|
[Original]
[Print]
[Top]
|
我的笔记本电脑和pc直连,都是100M网卡,笔记本上运行server程序接收数据,pc上运行client通过tcp/ip发送数据,数据量每秒大约100K字节,可是client send()几次就失败了,send返回0,不能继续发送了!
需要说明的是每秒钟send()的次数比较多,每次传输1k的数据,但我想百兆网卡不会因为这点数据而阻塞吧,会是什么原因呢?
我对socket了解的太少,请大家多指教!
谢谢!
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
谢谢enigma0702
只是一个测试程序,结构很简单,如下:
while(1)
{
if (flag) break;
// usleep(1);
send_ret = send(skt,buf,len,MSG_DONTWAIT|MSG_NOSIGNAL);
printf("send_ret=%d
",send_ret);
}
发现问题如下:
(1)当len==1时,也就是每次只发送一个字节,程序是正常的,send_ret都返回1,但是当len再大一些,比如len==5,每次send都返回-1了,这是为什么?
(2)当我在if (flag) break;之后加上usleep(1)后,即使len很大,比如1024,程序也可以正常运行,为什么加上这么一点延迟效果就这么好了?
(3)加上usleep(1)后,我逐渐增大len的值,但增加到1350左右时,每次send后都返回-1,即使此时将延迟增加到一秒这么长,send也返回-1,这又说明了什么?难道和tcp/ip的什么缓冲区有关系?具体我就不明白了?烦请大家抽空解释一下,谢谢了!!
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
MSG_DONTWAIT
This flag specifies nonblocking for a single I/O operation, without having to turn on the nonblocking flag for the socket, perform the I/O operation, and then turn off the nonblocking flag.
This flag is newer than the others and might not be supported on all systems.
书上参考的。
你把选项去掉,看看会有什么结果,是不是你发得太快,对方和你断开了。
|
|
|
----
be simple, be happy :-)
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
没说完呢,
MSG_DONTWAIT
Enables non-blocking operation; if the operation would block,
EAGAIN is returned (this can also be enabled using the O_NONBLOCK
with the F_SETFL fcntl(2)).
对面缓冲满了,返回 -1 很正常。 errno 应该是 EAGAIN 。
|
|
----
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
谢谢大家!
我又试了一下,errno确实是EAGAIN,那么如果对面缓冲区满了,发送方应如何处理才不至于丢失数据呢?通过sleep()肯定不是解决问题的办法,改变缓冲区的大小可以吗?或者还有什么好的方法,请大家多多指导教,谢谢!
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
1. 不要用非阻塞方式啊,除非你有特别的需求
2. 如果你非得用非阻塞方式,那就不停的发送,直到成功。
就象你开始给出的代码一样——不过,如果我是你的老板,你这么干,我非炒了你不可 :-)
3. 如果你确实非得用非阻塞方式,就用select(或poll)吧,我想它应该能处理你的问题
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
谢谢cyberzhang 和 Atu
to Atu:
谢谢,改成阻塞的确实可以了!但我想知道你说的"除非你有特别的需求",是指什么特别的需求,才应该用非阻塞呢?
另外再请教一个问题,就是两台百兆网卡的笔记本直连,是不是每秒钟最多传输12.5兆字节的数据,实际情况能达到这个值吗?如果数据量比12.5M大,是不是百兆网卡就不能用了,必须换更快的了?
谢谢!
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
阻塞与非阻塞,更多的要看你的实际需要了
如果你的程序只想一心一意的发送(或接收)数据,不需要做其他的事情,就可以用阻塞方式;
这个时候,你的读/写操作调用在完成后才返回;
否则,如果你的程序同时还要处理其他事情,就要用非阻塞方式,
无论是否成功,调用都会立刻返回——你也需要从返回值来判断是否成功了。
而这种模式要避免“忙循环”,就是前面我说的,你可能被炒掉的代码,
而是应该用select()来解决这个问题。
最典型的例子就是做一个很简单聊天服务器,它需要同时listen多个socket,
对于从任何一个socket发来的数据,它都要读它,并且再把它发送到其他的所有socket,
这种情况就是一个select()的典型应用。
更多的阻塞与非阻塞方式,到google去搜索吧,一大堆的文章。
至于网络速度,你的理解基本是对的,但是100M应该足以应付大部分的需求了
如果数据量大的话,只是需要更多的时间来传输而已,
只要你能接受这个速度,100M网卡就能用
100M的单位是速度,而不是大小。
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
感谢Atu,您讲的太好了,我又学到不少东西,谢谢!
我还有个问题比较迷惑,就是上面的代码,在非阻塞模式下,死循环中每次send一千多字节,只要加上usleep(1)一行,程序也可以正常执行,不加usleep(1)的话send就返回-1,仅仅延迟1微秒,这么短的时间,为什么结果会差别这么大????
而我算了一下,百兆的网卡1us最多也就传输十几个字节,tcp/ip在延迟的1us内能干些什么呢?使send得以正常发送! 想不明白!
谢谢!!
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
usleep(1)并不等于就是只s挂起1微秒,只是保证最少挂起1微秒。
The sleep may be lengthened slightly by any system activity or by the
time spent processing the call or by the granularity of system timers.
我不认为Linux能精确地挂起1微秒。
|
|
----
I love David Beckham and Man.Utd. for ever.
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
usleep(1)至少也需要延迟一个tick时间,比如HZ=1000的系统,它就是1ms, 所以实际上等于大大降低了发送速度。
正确的做法就是检测返回值,如果是EAGAIN错误,就需要重送,这期间你也可以去做点别的事情,该做的事都做完了那么可以usleep(1)一下。 要是觉得根本没事可做,那么就用阻塞型即可。
|
|
[Original]
[Print]
[Top]
|
|