关于TCP中send发送数据、select的一些困惑及实验
来源:百度文库 编辑:神马文学网 时间:2024/04/24 12:02:31
不知道是不是应该发在这里,看了一下这里好像主要是交流网络配置的?但其它更想不出什么地方了。内容比较多,请大家见谅。
在阻塞式的socket中,recv/read调用肯定不一定返时刚好读满缓冲区(即使对端没有关闭还在发送),这个比较容易理解,也很容易测试出来。但对于send的返回值,许多资料中讲得都很含糊,在MSDN中说是“非阻塞的socket有可能发送成功而返回的值小于要发送的长度“,即只发送了一部分出去,感觉言下之义就是阻塞式的只要发送成功就肯定是指定的发送长度,和文件写一样。Linux/FreeBSD中man手册都没有明确的说明,只说成功时返回发送的数据字节数,失败返回-1。
以前刚学网络时看的是《UNIX网络编程》的第二版,现在俺这本书找不到了,于是找了一本第三版的电子书看,但浏览了一下没看到什么说明。这个发送实际上以前就比较困惑,由于自己不做网络开发也没有专门测试过,问过一些专门做网络的好像也不是很清楚;而接收如果按每次能收满这个在工作中是见到过问题的。
《UNIX网络编程》第三版的代码:
vsFTP中的代码:
后面一个实际上是写socket的。从这两种看感觉都是认为写操作有可能不能一次写完,而且这里显然不是处理非阻塞式的,因为没有处理非阻塞式特别的返回码。
然后我开始做实验。结果发现不管缓冲区多大,对端阻塞的话本端要么阻塞,要么全部发送。不管多大缓冲区发送,都无法构造出有可能发磅成功但只发送部分的情况。
如果是这样的话也算OK吧,因为Linux的man手册中讲到send/recv的第四个参数是WAITALL只提到读数据。但这样就又使我对于 select疑惑起来。因为select对读很简单,保证读一次不会阻塞是可以的。但对于这个测试结果,select可写的话后面的写操作有可能还是阻塞 掉,因为select时并不知道后续的发送要发多少数据。UNPv3给出的select返回socket可写的条件(其它三个条件不相关):
The number of bytes of available space in the socket send buffer is greater than or equal to the current size of the low-water mark for the socket send buffer and either: (i) the socket is connected, or (ii) the socket does not require a connection (e.g., UDP). This means that if we set the socket to nonblocking (Chapter 16), a write operation will not block and will return a positive value (e.g., the number of bytes accepted by the transport layer). We can set this low-water mark using the SO_SNDLOWAT socket option. This low-water mark normally defaults to 2048 for TCP and UDP sockets.
最开始我以WinXP 做Server,连接之后等待键盘输入才读数据,这样Linux下的客户端最终总会阻塞,而在Server读几次之后客户端会再写一些数据。最后发24K 包发送时确实会出来select返回可写,但实际的send阻塞的情况,不过好像有一些随机。另外此时发现一个奇怪的现象,因为Windows下SOL_RCVBUF缺省为8K,而Linux下SOL_SNDBUF缺省为16K,但实际上发了许多24K包才阻塞,实在是想不明白,所以抓包看了一下,发现确实发给Windows的数据包远超过8K之后它才发Window Full,不知道除了TCP的接收缓冲区Windows还有哪也缓存数据了。
后来在FreeBSD下面编译客户端也测试了一下。在FreeBSD下发送缓冲区缺省是32K,但肯定地发完第5包之后select再交返回1,然后就阻 塞了。Linux下有些随机,往往是发完第6包阻塞在select上,后面随着Server读一些数据有可能select返回1但却发送阻塞,但有时也是 发完第5包之后select返回1后发送 阻塞。
另外比较奇怪的是在Linux下SOL_SNDLOWAT值为1,而FreeBSD是前面UNP中提到的2K,所以按道理Linux应该更容易出现select返回中写而发送阻塞,但测试结果FreeBSD更固定地出现。
环境是Fedora 7.0和FreeBSD 7.0。
由于是测试代码,有些乱。Client代码如果要在FreeBSD下编译需要在
#include
#include
后面再包含一些文件:
#include
在阻塞式的socket中,recv/read调用肯定不一定返时刚好读满缓冲区(即使对端没有关闭还在发送),这个比较容易理解,也很容易测试出来。但对于send的返回值,许多资料中讲得都很含糊,在MSDN中说是“非阻塞的socket有可能发送成功而返回的值小于要发送的长度“,即只发送了一部分出去,感觉言下之义就是阻塞式的只要发送成功就肯定是指定的发送长度,和文件写一样。Linux/FreeBSD中man手册都没有明确的说明,只说成功时返回发送的数据字节数,失败返回-1。
以前刚学网络时看的是《UNIX网络编程》的第二版,现在俺这本书找不到了,于是找了一本第三版的电子书看,但浏览了一下没看到什么说明。这个发送实际上以前就比较困惑,由于自己不做网络开发也没有专门测试过,问过一些专门做网络的好像也不是很清楚;而接收如果按每次能收满这个在工作中是见到过问题的。
《UNIX网络编程》第三版的代码:
- [color=Navy]
- ssize_t /* Write "n" bytes to a descriptor. */
- writen(int fd, const void *vptr, size_t n)
- {
- size_t nleft;
- ssize_t nwritten;
- const char *ptr;
- ptr = vptr;
- nleft = n;
- while (nleft > 0) {
- if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
- if (nwritten < 0 && errno == EINTR)
- nwritten = 0; /* and call write() again */
- else
- return(-1); /* error */
- }
- nleft -= nwritten;
- ptr += nwritten;
- }
- return(n);
- }
- /* end writen */
- [/color]
vsFTP中的代码:
- int
- vsf_sysutil_write_loop(const int fd, const void* p_buf, unsigned int size)
- {
- int retval;
- int num_written = 0;
- if (size > INT_MAX)
- {
- die("size too big in vsf_sysutil_write_loop");
- }
- while (1)
- {
- retval = vsf_sysutil_write(fd, (const char*)p_buf + num_written, size);
- if (retval < 0)
- {
- /* Error */
- return retval;
- }
- else if (retval == 0)
- {
- /* Written all we're going to write.. */
- return num_written;
- }
- if ((unsigned int) retval > size)
- {
- die("retval too big in vsf_sysutil_read_loop");
- }
- num_written += retval;
- size -= (unsigned int) retval;
- if (size == 0)
- {
- /* Hit the write target, cool. */
- return num_written;
- }
- }
- }
后面一个实际上是写socket的。从这两种看感觉都是认为写操作有可能不能一次写完,而且这里显然不是处理非阻塞式的,因为没有处理非阻塞式特别的返回码。
然后我开始做实验。结果发现不管缓冲区多大,对端阻塞的话本端要么阻塞,要么全部发送。不管多大缓冲区发送,都无法构造出有可能发磅成功但只发送部分的情况。
如果是这样的话也算OK吧,因为Linux的man手册中讲到send/recv的第四个参数是WAITALL只提到读数据。但这样就又使我对于 select疑惑起来。因为select对读很简单,保证读一次不会阻塞是可以的。但对于这个测试结果,select可写的话后面的写操作有可能还是阻塞 掉,因为select时并不知道后续的发送要发多少数据。UNPv3给出的select返回socket可写的条件(其它三个条件不相关):
The number of bytes of available space in the socket send buffer is greater than or equal to the current size of the low-water mark for the socket send buffer and either: (i) the socket is connected, or (ii) the socket does not require a connection (e.g., UDP). This means that if we set the socket to nonblocking (Chapter 16), a write operation will not block and will return a positive value (e.g., the number of bytes accepted by the transport layer). We can set this low-water mark using the SO_SNDLOWAT socket option. This low-water mark normally defaults to 2048 for TCP and UDP sockets.
最开始我以WinXP 做Server,连接之后等待键盘输入才读数据,这样Linux下的客户端最终总会阻塞,而在Server读几次之后客户端会再写一些数据。最后发24K 包发送时确实会出来select返回可写,但实际的send阻塞的情况,不过好像有一些随机。另外此时发现一个奇怪的现象,因为Windows下SOL_RCVBUF缺省为8K,而Linux下SOL_SNDBUF缺省为16K,但实际上发了许多24K包才阻塞,实在是想不明白,所以抓包看了一下,发现确实发给Windows的数据包远超过8K之后它才发Window Full,不知道除了TCP的接收缓冲区Windows还有哪也缓存数据了。
后来在FreeBSD下面编译客户端也测试了一下。在FreeBSD下发送缓冲区缺省是32K,但肯定地发完第5包之后select再交返回1,然后就阻 塞了。Linux下有些随机,往往是发完第6包阻塞在select上,后面随着Server读一些数据有可能select返回1但却发送阻塞,但有时也是 发完第5包之后select返回1后发送 阻塞。
另外比较奇怪的是在Linux下SOL_SNDLOWAT值为1,而FreeBSD是前面UNP中提到的2K,所以按道理Linux应该更容易出现select返回中写而发送阻塞,但测试结果FreeBSD更固定地出现。
环境是Fedora 7.0和FreeBSD 7.0。
由于是测试代码,有些乱。Client代码如果要在FreeBSD下编译需要在
#include
#include
后面再包含一些文件:
#include
-
tcp_send_test_srv.rar (2.43 KB)
下载次数:32
2008-05-02 00:04
Server测试代码
-
tcp_send_test.rar (2.4 KB)
关于TCP中send发送数据、select的一些困惑及实验
(复用代码)经常用到的几个自定义函数: 监听·连接服务器·发送数据函数Send·接收数据函数Recv
关于石油的一些数据整理
转载:关于石油的一些数据整理
关于石油的一些数据整理
关于select
服务端中一些数据的分析
Linux中select函数的使用
如何发送超大附件及一些常用技巧
关于人生的困惑
关于工作及生活的一些记忆
关于国家大事及政治的一些英语词汇
#send
使用HttpUrlConnection发送数据
使用HttpUrlConnection发送数据
关于linux中的select
select中, UNION 和 UNION ALL的使用方法
在局域网XP机中利用net?send命令进行简单的聊天
人生的困惑及救助
心身作用的原理及关于灵的一些思考
关于一个小孩子的实验
关于艾灸的实验研究
TCP/IP数据包头格式
TCP/IP数据包头格式