可靠传输必然优先考虑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;
}
各位看情况来使用吧。