可靠传输必然优先考虑TCP,但是不同人遇到不同问题,可能会有变态的情况,用UDP也要达到TCP那样保持发送顺序和可靠性,还要类似未连接的状态。
偶然间看到这两个库,测试了一下效果确实不错,分享一下。
1.ENet
ENet 是一个易用的、可移植的 UDP 网络开发包,主要功能包括连接管理、可靠的按顺序的多通道包传输机制、包分解和重新打包、避免堵塞机制等。
经测试,此库用于局域网没多大问题,但是在公网环境里,速度很差,伪连接还经常断开。100000字节的数据发了十几秒,还经常有几次发了一半连接就断开了。测试为公司网络--本VPS(香港机房)
官方链接: http://enet.bespin.org/Tutorial.html
示例:
建立server
ENetAddress address; ENetHost * server; /* Bind the server to the default localhost. */ /* A specific host address can be specified by */ /* enet_address_set_host (& address, "x.x.x.x"); */ address.host = ENET_HOST_ANY; /* Bind the server to port 1234. */ address.port = 1234; server = enet_host_create (&address /* the address to bind the server host to */, 32 /* allow up to 32 clients and/or outgoing connections */, 2 /* allow up to 2 channels to be used, 0 and 1 */, 0 /* assume any amount of incoming bandwidth */, 0 /* assume any amount of outgoing bandwidth */); if (server == NULL) { fprintf (stderr, "An error occurred while trying to create an ENet server host.\n";); exit (EXIT_FAILURE); } ... enet_host_destroy(server);
事件处理
ENetEvent event; /* Wait up to 1000 milliseconds for an event. */ while (enet_host_service (client, & event, 1000) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: printf ("A new client connected from %x:%u.\n", event.peer -> address.host, event.peer -> address.port); /* Store any relevant client information here. */ event.peer -> data = "Client information"; break; case ENET_EVENT_TYPE_RECEIVE: printf ("A packet of length %u containing %s was received from %s on channel %u.\n", event.packet -> dataLength, event.packet -> data, event.peer -> data, event.channelID); /* Clean up the packet now that we're done using it. */ enet_packet_destroy (event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: printf ("%s disconected.\n", event.peer -> data); /* Reset the peer's client information. */ event.peer -> data = NULL; } } ... ... ...
在使用上,还有channelID和限速等功能,使用起来很方便,static release大概40Kb,整个工程文件数不错,提供了VS工程可以直接编译测试。
2.UDT
UDT 是一个可靠的基于UDP的数据传输协议,主要为应用程序间提供高效高速的广域网数据传输功能。UDT 使用 UDP 协议来传输大数据块,通过它的可靠性控制和拥塞控制机制。该协议比 TCP 的传输速度要快,具有高可配置性和各种不同的拥塞控制算法。
这个库宣传最大的特点就是快!在可靠传输的基础上,是TCP数据传输的4倍多!不过博主测试,这个库提供的函数并不像ENet那样高度封装使用方便,比较像TCP socket那一套函数调用流程,对于UDP独立包的概念也没有了,转成了数据流的方式。
官方链接: http://udt.sourceforge.net/udt4/index.htm
示例:
建立server
#include <arpa/inet.h> #include <udt.h> #include <iostream.h> using namespace std; int main() { UDTSOCKET serv = UDT::socket(AF_INET, SOCK_STREAM, 0); sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(9000); my_addr.sin_addr.s_addr = INADDR_ANY; memset(&(my_addr.sin_zero), '\0', 8); if (UDT::ERROR == UDT::bind(serv, (sockaddr*)&my_addr, sizeof(my_addr))) { cout << "bind: " << UDT::getlasterror().getErrorMessage(); return 0; } UDT::listen(serv, 10); int namelen; sockaddr_in their_addr; UDTSOCKET recver = UDT::accept(serv, (sockaddr*)&their_addr, &namelen); char ip[16]; cout << "new connection: " << inet_ntoa(their_addr.sin_addr) << ":" << ntohs(their_addr.sin_port) << endl; char data[100]; if (UDT::ERROR == UDT::recv(recver, data, 100, 0)) { cout << "recv:" << UDT::getlasterror().getErrorMessage() << endl; return 0; } cout << data << endl; UDT::close(recver); UDT::close(serv); return 1; }
客户端示例
#include <iostream> #include <udt.h> #include <arpa/inet.h> using namespace std; using namespace UDT; int main() { UDTSOCKET client = UDT::socket(AF_INET, SOCK_STREAM, 0); sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(9000); inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); memset(&(serv_addr.sin_zero), '\0', 8); // connect to the server, implict bind if (UDT::ERROR == UDT::connect(client, (sockaddr*)&serv_addr, sizeof(serv_addr))) { cout << "connect: " << UDT::getlasterror().getErrorMessage(); return 0; } char* hello = "hello world!\n"; if (UDT::ERROR == UDT::send(client, hello, strlen(hello) + 1, 0)) { cout << "send: " << UDT::getlasterror().getErrorMessage(); return 0; } UDT::close(client); return 1; }
各位看情况来使用吧。