標籤:style color 使用 strong 資料 ar 代碼 linux
注意並不是send把s的發送緩衝中的資料傳到串連的另一端的,而是協議傳的,send僅僅是把buf中的資料copy到s的發送緩衝區的剩餘空間裡
TCP發給對方的資料,對方在收到資料時必須給矛確認,只有在收到對方的確認時,本方TCP才會把TCP發送緩衝區中的資料刪除。
UDP因為是不可靠串連,不必儲存應用進程的資料拷貝,應用進程中的資料在沿協議棧向下傳遞時,以某種形式拷貝到核心緩衝區,當資料連結層把資料傳出後就把核心緩衝區中資料拷貝刪除。因此它不需要一個發送緩衝區。
在阻塞模式下, send函數的過程是將應用程式請求發送的資料拷貝到發送緩衝中發送並得到確認後再返回.但由於發送緩衝的存在,表現為:如果發送緩衝大小比請求發送的大小要大,那麼send函數立即返回,同時向網路中發送資料;否則,send向網路發送緩衝中不能容納的那部分資料,並等待對端確認後再返回(接收端只要將資料收到接收緩衝中,就會確認,並不一定要等待應用程式調用recv);
在非阻塞模式下,send函數的過程僅僅是將資料拷貝到協議棧的緩衝區而已,如果緩衝區可用空間不夠,則盡能力的拷貝,返回成功拷貝的大小;如緩衝區可用空間為0,則返回-1,同時設定errno為EAGAIN.
linux下可用sysctl -a | grep net.ipv4.tcp_wmem查看系統預設的發送緩衝大小:
net.ipv4.tcp_wmem = 4096 16384 81920
這有三個值,第一個值是socket的發送緩衝區分配的最少位元組數,第二個值是預設值(該值會被net.core.wmem_default覆蓋),緩衝區在系統負載不重的情況下可以增長到這個值,第三個值是發送緩衝區空間的最大位元組數(該值會被net.core.wmem_max覆蓋).
根據實際測試,如果手工更改了net.ipv4.tcp_wmem的值,則會按更改的值來運行,否則在預設情況下,協議棧通常是按net.core.wmem_default和net.core.wmem_max的值來分配記憶體的.
應用程式應該根據應用的特性在程式中更改發送緩衝大小:
socklen_t sendbuflen = 0;
socklen_t len = sizeof(sendbuflen);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("default,sendbuf:%d\n", sendbuflen);
sendbuflen = 10240;
setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("now,sendbuf:%d\n", sendbuflen);
需要注意的是,雖然將發送緩衝設定成了10k,但實際上,協議棧會將其擴大1倍,設為20k.
在Linux中使用非阻塞的socket的情形下。
(一)發送時
當客戶通過Socket提供的send函數發送大的資料包時,就可能返回一個EGGAIN的錯誤。該錯誤產生的原因是由於send 函數中的size變數大小超過了tcp_sendspace的值。tcp_sendspace定義了應用在調用send之前能夠在kernel中緩衝的資料量。當應用程式在socket中設定了O_NDELAY或者O_NONBLOCK屬性後,如果發送緩衝被佔滿,send就會返回EAGAIN的錯誤。
為了消除該錯誤,有三種方法可以選擇: 1.調大tcp_sendspace,使之大於send中的size參數 ---no -p -o tcp_sendspace=65536
2.在調用send前,在setsockopt函數中為SNDBUF設定更大的值
3.使用write替代send,因為write沒有設定O_NDELAY或者O_NONBLOCK
(二)接收時
接收資料時常遇到Resource temporarily unavailable的提示,errno代碼為11(EAGAIN)。這表明你在非阻塞模式下調用了阻塞操作,在該操作沒有完成就返回這個錯誤,這個錯誤不會破壞socket的同步,不用管它,下次迴圈接著recv就可以。對非阻塞socket而言,EAGAIN不是一種錯誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。其實這算不上錯誤,只是一種異常而已。
在Linux中使用非阻塞的socket的情形下。
(一)發送時
當客戶通過Socket提供的send函數發送大的資料包時,就可能返回一個EGGAIN的錯誤。該錯誤產生的原因是由於send 函數中的size變數大小超過了tcp_sendspace的值。tcp_sendspace定義了應用在調用send之前能夠在kernel中緩衝的資料量。當應用程式在socket中設定了O_NDELAY或者O_NONBLOCK屬性後,如果發送緩衝被佔滿,send就會返回EAGAIN的錯誤。
為了消除該錯誤,有三種方法可以選擇: 1.調大tcp_sendspace,使之大於send中的size參數 ---no -p -o tcp_sendspace=65536
2.在調用send前,在setsockopt函數中為SNDBUF設定更大的值
3.使用write替代send,因為write沒有設定O_NDELAY或者O_NONBLOCK
(二)接收時
接收資料時常遇到Resource temporarily unavailable的提示,errno代碼為11(EAGAIN)。這表明你在非阻塞模式下調用了阻塞操作,在該操作沒有完成就返回這個錯誤,這個錯誤不會破壞socket的同步,不用管它,下次迴圈接著recv就可以。對非阻塞socket而言,EAGAIN不是一種錯誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。其實這算不上錯誤,只是一種異常而已。
另外,如果出現EINTR即errno為4,錯誤描述Interrupted system call,操作也應該繼續。
最後,如果recv的傳回值為0,那表明對方已將串連斷開,我們的接收操作也應該結束。