做了一个转发TCP 和UDP的服务端,但是现在测试老有问题,就是UDP总会有那么几次超时,原因还没找到,不过先总结一下网络的编程。
首先默认的状态下,recvfrom和recv都是阻塞的状态,也就是没接收到会一直阻塞,知道返回,但是可以通过select设置超时:
TIMEVAL tWait;
tWait.tv_sec = 0;
tWait.tv_usec = 1000000; // wait for 10000us
fd_set revSet;
FD_ZERO(&revSet);//清零
FD_SET(AcceptSocket, &revSet); //将套接字加入描述符
int iResult = select(1, &revSet, NULL, NULL, &tWait);//在10ms内判断对应的socket是否可读,若刻度,立即返回套接字个数,若10ms内不可读,则返回0,然后return,结束此函数。
if ( iResult == 0 )
{
printf("[TCP]--Connection from client %d.%d.%d.%d closed.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}
else if ( SOCKET_ERROR == iResult )
{
printf("[TCP]--Connection from Client %d.%d.%d.%d error.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}
现在初步的判断是接受缓冲区的问题,不过对于缓冲区还有一点迷惑:
接受缓冲区是有数据就立即接受,但是发送缓冲区是等最大500ms(好像是),然后将这个时间接到的所有数据一起发送(异步),或者一个数据足够大后直接发送,这点我不是很确定。
缓冲区有数据就立刻发送缓冲区的设定如下:
BOOL bNodelay=TRUE;
setsockopt(AcceptSocket,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelay,sizeof(BOOL));//缓冲区有数据就立刻发送,IPPROTO_TCP选项是bool型,即费0则1,而SOL_SOCKET是实在的数,TCP_NODELAY 禁止发送合并的Nagle算法,其他类似的如下:
setsockopt()支持下列选项。其中“类型”表明optval所指数据的类型。
选项 类型 意义
SO_BROADCAST BOOL 允许套接口传送广播信息。
SO_DEBUG BOOL 记录调试信息。
SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。
SO_DONTROUTE BOOL 禁止选径;直接传送。
SO_KEEPALIVE BOOL 发送“保持活动”包。
SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留。
SO_OOBINLINE BOOL 在常规数据流中接收带外数据。
SO_RCVBUF int 为接收确定缓冲区大小。
SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind())。
SO_SNDBUF int 指定发送缓冲区大小。
TCP_NODELAY BOOL 禁止发送合并的Nagle算法。
setsockopt()不支持的BSD选项有:
选项名 类型 意义
SO_ACCEPTCONN BOOL 套接口在监听。
SO_ERROR int 获取错误状态并清除。
SO_RCVLOWAT int 接收低级水印。
SO_RCVTIMEO int 接收超时。
SO_SNDLOWAT int 发送低级水印。
SO_SNDTIMEO int 发送超时。
SO_TYPE int 套接口类型。
IP_OPTIONS 在IP头中设置选项。
http://baike.baidu.com/view/569217.htm
记得以前有些朋友讨论过,socket虽然send成功了,但是其实只是发送到数据缓冲区里面了,而并没有真正的在物理设备上发送出去;而通过这条语句,将发送缓冲区设置为0,即屏蔽掉发送缓冲以后,一旦send返回(当然是就阻塞套结字来说),就可以肯定数据已经在发送的途中了^_^,但是这样做也许会影响系统的性能
to:Sander()
UDP也有拷贝过程,但是UDP包有最大限制为64K;
TCP_NODELAY 一般用在the normal data stream 上;
12.发送数据时候一般是系统缓冲区满以后才发送,现在设置为只要系统
缓冲区有数据就立刻发送:
BOOL bNodelay=TRUE;
SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL));
UDP丢包是不可避免的,你可以把每个包用一个字段标识,对一部分发两遍,另外还有其他的方法,如包设置大小,发送时注意SLEEP(n),n1-10等方法
Q:本地同时与多个主机建立连接,如果这些主机同时发生数据到本地,而本地又没有调用recv进行处理,会出现什么情况?
A:系统为每个socket建立一个缓存,ip层组包进程在收到数据包后会把数据放入socket缓存。调用recv将socket缓存的内容copy到程序定义的缓存,如果通信进程不能及时recv,将导致该socket缓存满。如果用tcp协议,socket缓存满以后,系统会向对方发出错误消息,对方回收到wsaewouldblock错误,如果是用udp协议,系统会把该socket的以后收到的数据丢弃~