理解套接字recv(),send()

记得以前发过一篇类似的博文(原博客被和谐了,连接找不到了)。新手最容易混淆的就是这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操作放进循环直到操作完期望数据,这点以后再整理。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章