理解套接字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操作放進循環直到操作完期望數據,這點以後再整理。。。

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