本文共 1125 字,大约阅读时间需要 3 分钟。
记得以前发过一篇类似的博文(原博客被和谐了,连接找不到了)。新手最容易混淆的就是这2个函数了,今天看UNP时,找到了个很不错的图示,觉得理解清楚后就基本没什么问题了,在这里做个简单整理,注意此图示是假设从stdin接受输入,然后send给套接字发送;从套接字recv后,传给stdout输出。
send:
tooptr :指向下一个将传送给socket的字节
toiptr :指向下一个可以接收应用层数据的位置
所以,要传送给套接字的数据长度就是toiptr - tooptr。
内核缓冲区可以接受stdin传来的数据长度是&to[MAXLINE] - toiptr。
阻塞模式下:应用层copy数据至内核缓冲区即返回,若没有足够缓冲区(如网络太慢),则阻塞至有足够空间
非阻塞模式下:若没有足够缓冲区,立即返回EWOULDBLOCK,有缓冲区,立即返回的是已经copy了的数据长度。
=============================分割线===================================
recv:
froptr :指向下一个将传送给应用层的字节
friptr :指向下一个可以接收socket数据的位置
所以,要传送给应用层的数据长度就是friptr - froptr 。
内核缓冲区可以接受socket传来的数据长度是&fr[MAXLINE] - friptr。
阻塞模式下:若缓冲区内无数据可读,则阻塞等待至有数据才返回,数据长度不定,可以是1个字节,也可以是一个完整数据包
非阻塞模式下:若缓冲区内无数据,立即返回EWOULDBLOCK,有缓冲区,与上面相同。
=============================分割线===================================
总结:
无论阻塞还是非阻塞,不要指望send(n) or recv(n)就能发送或接收n字节的数据。
把内核缓冲区理解清楚对网络编程理解很有帮助。
思考:
众所周知一个服务器设计原则是“不要使用任何阻塞操作”。
很容易理解,一是充分利用CPU;二则是安全性,比如恶意客户很容易让服务器阻塞在它上面。
关于非阻塞的安全性,我看过很多代码都是把非阻塞send()放进一个循环里,没有发送完指定n个数据则不退出,这在正常情况下可以,但是若网络比较慢,根据上面图示推测,显然while()退出也缓慢,这势必会影响服务器对其他套接字数据的发送。更不用考虑若对方是恶意用户,比如只接收一个字节则sleep()。。
所以,我觉得,高性能服务器不能用阻塞,也不能把任何I/O操作放进循环直到操作完期望数据,这点以后再整理。。。
转载地址:http://mebci.baihongyu.com/