tcp協議系列文章(7):send()的資料大小與可用的傳送緩衝區大小的關係
筆者這裡要指出的是,man send 手冊上說的或許與send()的版本有關。詳細的,可以檢視筆者的另一篇部落格,上面有就send()的行為的詳細說法。
下面的部落格內容,其實驗證的方法與驗證的目的並不相同!!!請讀者注意!!!
自己做了個測試,伺服器只起socket在偵聽,不recv, 也不send.
- //ubuntu10.04 32bit
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- int main(void)
- {
- int fd;
- struct sockaddr_in addr;
- fd = socket(AF_INET, SOCK_STREAM, 0);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(103);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- bind(fd, (struct sockaddr *)&addr, sizeof(addr));
- listen(fd,5);
- }
客戶端,將傳送緩衝區大小設定成2k,然後一次傳送3k的資料。
- //ubuntu10.04 32bit
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- int main()
- {
- int fd,ret,tmp,sendlen;
- struct sockaddr_in addr;
- char *buf;
- int sendBufLen = 1024*2;
- socklen_t optlen = sizeof
- buf = (char *)malloc(1024 * 3);
- fd = socket(AF_INET, SOCK_STREAM,0 );
- setsockopt(fd,SOL_SOCKET, SO_SNDBUF,(constchar*)&sendBufLen, sizeof(int));
- getsockopt(fd,SOL_SOCKET, SO_SNDBUF,(int *)&tmp, &optlen);
- printf("send_tmp=%d,optlen=%d\n",tmp,(int)optlen); //設定傳送緩衝區2048
- getsockopt(fd,SOL_SOCKET, SO_RCVBUF,(int *)&tmp, &optlen);
- printf("recv_tmp=%d,optlen=%d\n",tmp,(int)optlen);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(103);
- addr.sin_addr.s_addr = inet_addr("222.111.112.204"); //填上自己的IP
- ret = connect (fd, (struct sockaddr *)&addr, sizeof(addr));
- printf("connect return %d\n",ret);
- getchar();
- if (ret >= 0)
- sendlen = send(fd,buf,1024*3,0);
- printf("sendlen=%d\n",sendlen); //此處返回3072
- getchar();
- return 0;
- }
互動報文
從這裡看出當傳送長度大於緩衝區大小時,是分次傳送,三次加起來 1448 + 1448 + 176 = 3072
在windows下,做同樣的測試
- // xp vc6.0 32bit
- #include <stdio.h>
- #include <winsock2.h>
- #include <iostream.h>
- #pragma comment (lib,"ws2_32")
- void main()
- {
- int len,optval,optlen,iResult;
- SOCKADDR_IN clientService;// 地址
- SOCKET ConnectSocket;// socket
- WSADATA wsaData;// 庫
- unsigned char buf[1024*3];
- //初始化socket庫, 儲存ws2_32.dll已經載入
- iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if (iResult != NO_ERROR)
- printf("Error at WSAStartup()\n");
- // 建立socket
- ConnectSocket = socket(AF_INET, // IPv4
- SOCK_STREAM, // 順序的、可靠的、基於連線的、雙向的資料流通訊
- IPPROTO_TCP // 使用TCP協議
- /*0*/);
- if (ConnectSocket == INVALID_SOCKET)
- {
- printf("Error at socket(): %d\n", WSAGetLastError());
- WSACleanup();
- return ;
- }
- optlen = sizeof(optval);
- getsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, &optlen);
- printf("send buf len is %d\n",optval); //預設傳送緩衝區8k
- getsockopt(ConnectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&optval, &optlen);
- printf("Recv buf len is %d\n",optval); //預設接收緩衝區8k
- optval = 1024 * 2;
- setsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, optlen);
- getsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, &optlen);
- printf("send buf len change to %d\n",optval);
- // 設定服務端的通訊協議、IP地址、埠
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr( "222.111.112.204" );
- clientService.sin_port = htons( 103 );
- // 連線到服務端
- if ( connect(
- ConnectSocket, // socket
- (SOCKADDR*) &clientService, // 地址
- sizeof(clientService) // 地址的大小
- ) == SOCKET_ERROR)
- {
- printf( "Failed to connect(%d)\n",WSAGetLastError() );
- WSACleanup();
- return ;
- }
- len = send(ConnectSocket, (char*)buf, 1024*3, 0);
- printf("send length is %d\n",len); //這裡同樣直接返回3072
- system("pause");
- return;
- }
分三次傳送1460+1460+152 = 3072
上面都是阻塞的傳送,對於socket是非阻塞的話,做同樣的測試
- //ubuntu10.04 32bit
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #include <errno.h>
- #include <arpa/inet.h>
- int main()
- {
- int fd,ret,tmp,sendlen,flags,fd_num;
- fd_set rset,wset;
- struct timeval tval;
- struct sockaddr_in addr;
- char *buf;
- int sendBufLen = 1024*2;
- socklen_t optlen = sizeof(int);
- buf = (char *)malloc(1024 * 3);
- fd = socket(AF_INET, SOCK_STREAM,0 );
- setsockopt(fd,SOL_SOCKET, SO_SNDBUF,(constchar*)&sendBufLen, sizeof(int));
- getsockopt(fd,SOL_SOCKET, SO_SNDBUF,(int *)&tmp, &optlen);
- printf("send_tmp=%d,optlen=%d\n",tmp,(int)optlen);
- getsockopt(fd,SOL_SOCKET, SO_RCVBUF,(int *)&tmp, &optlen);
- printf("recv_tmp=%d,optlen=%d\n",tmp,(int)optlen);
- flags = fcntl(fd,F_GETFL,0);
- fcntl(fd,F_SETFL,flags|O_NONBLOCK);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(103);
- addr.sin_addr.s_addr = inet_addr("222.111.112.204");
- ret = connect (fd, (struct sockaddr *)&addr, sizeof(addr));
- if ((ret < 0) && (errno == EINPROGRESS))
- {
- FD_ZERO(&rset);
- FD_SET(fd,&rset);
- wset = rset;
- tval.tv_sec = 3;
- tval.tv_usec = 0;
- if ( -1 == (fd_num = select(fd+1, &rset, &wset, NULL, &tval)))
- {
- perror("select error");
- exit(0);
- }
- else
- {
- if ((fd_num == 1) && FD_ISSET(fd, &wset)) //connect only can be write
- {
- printf("connect OK!\n");
- }
- else
- {
- perror("state error");
- exit(0);
- }
- }
- }
- if (-1 ==(sendlen = send(fd,buf,1024*3,0)))
- {
- perror("send error");
- }
- else
- {
- printf("sendlen=%d\n",sendlen); //直接返回3072
- }
- return 0;
- }
和blocking socket表現是一樣的,一次send,協議棧分三幀傳送。
- //xp vc6.0 32bit
- #include <stdio.h>
- #include <winsock2.h>
- #include <iostream.h>
- #pragma comment (lib,"ws2_32")
- void main()
- {
- int len,optval,optlen,iResult,fd_num,on=1;
- SOCKADDR_IN clientService;// 地址
- SOCKET ConnectSocket;// socket
- WSADATA wsaData;// 庫
- unsigned char buf[1024*3];//
- fd_set rset,wset;
- struct timeval tval;
- //初始化socket庫, 儲存ws2_32.dll已經載入
- iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if (iResult != NO_ERROR)
- printf("Error at WSAStartup()\n");
- // 建立socket
- ConnectSocket = socket(AF_INET, // IPv4
- SOCK_STREAM, // 順序的、可靠的、基於連線的、雙向的資料流通訊
- IPPROTO_TCP // 使用TCP協議
- /*0*/);
- if (ConnectSocket == INVALID_SOCKET)
- {
- printf("Error at socket(): %d\n", WSAGetLastError());
- WSACleanup();
- return ;
- }
- if(0 == ioctlsocket(ConnectSocket, FIONBIO, (unsigned long *)&on))
- {
- printf("socket non-blocking set success!\n");
- }
- optlen = sizeof(optval);
- getsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, &optlen);
- printf("send buf len is %d\n",optval);
- getsockopt(ConnectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&optval, &optlen);
- printf("Recv buf len is %d\n",optval);
- optval = 1024 * 2;
- setsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, optlen);
- getsockopt(ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&optval, &optlen);
- printf("send buf len change to %d\n",optval);
- // 設定服務端的通訊協議、IP地址、埠
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr( "222.111.112.204" );
- clientService.sin_port = htons( 103 );
- // 連線到服務端
- if ( connect(
- ConnectSocket, // socket
- (SOCKADDR*) &clientService, // 地址
- sizeof(clientService) // 地址的大小
- ) == SOCKET_ERROR)
- {
- if ( WSAEWOULDBLOCK == WSAGetLastError() )
- {
- FD_ZERO(&rset);
- FD_SET(ConnectSocket,&rset);
- wset = rset;
- tval.tv_sec = 3;
- tval.tv_usec = 0;
- if (SOCKET_ERROR == (fd_num = select(ConnectSocket+1, &rset, &wset, NULL, &tval)))
- {
- printf( "select Failed (%d)\n",WSAGetLastError() );
- WSACleanup();
- return ;
- }
- else
- {
- if ((fd_num == 1) && FD_ISSET(ConnectSocket, &wset)) //connect成功後,只能可寫,不能可讀可寫
- {
- printf("connect OK!\n");
- }
- else
- {
- printf( "connect Failed (%d)\n",WSAGetLastError() );
- WSACleanup();
- return ;
- }
- }
- }
- else
- {
- printf( "Failed to connect(%d)\n",WSAGetLastError() );
- WSACleanup();
- return ;
- }
- }
- if (SOCKET_ERROR == (len=send(ConnectSocket, (char*)buf, 1024*3, 0)))
- {
- printf("send error %d\n", WSAGetLastError());
- }
- else
- {
- printf("send length is %d\n",len); //直接返回3072
- }
- system("pause");
- return;
- }
可見,當send的資料長度大於socket的緩衝區長度時,不管是windows還是linux,send都會分幀傳送。
相關推薦
tcp協議系列文章(7):send()的資料大小與可用的傳送緩衝區大小的關係
筆者這裡要指出的是,man send 手冊上說的或許與send()的版本有關。詳細的,可以檢視筆者的另一篇部落格,上面有就send()的行為的詳細說法。 下面的部落格內容,其實驗證的方法與驗證的目的並不相同!!!請讀者注意!!! 自己做了個測試,伺服器只起s
Git系列文章(四):常見異常問題
1、GitHub提交的時顯示Updates were rejected because the remote contains work that you do git push -u origin master 每次建立新的倉庫,提交的時總會出現這樣的錯誤。Updates
Git系列文章(三):本地新建專案提交至遠端倉庫
------新建專案後,選中專案資料夾右鍵git Bash Here ------使用git init ------使用git status ------使用git add . ------使用git commit -m "新增檔案" ------使用gi
Git系列文章(二):從github上下載專案,本地修改後提交至github
Spring官方demo綠房子:spring-projects/greenhouse 1、獲取github遠端倉庫地址: [email protected]:spring-projects/greenhouse.git 2、用git克隆專案到本地 選擇要克隆的程式碼,滑鼠右
Git系列文章(一):Git簡介
Git:一個開源的分散式版本控制系統,可以有效的高速的控制管理各種從小到大的專案版本。他的作者就是大名鼎鼎的Linux系統創始人Linus。 git命令教程:https://www.yiibai.com/git 常用的幾個命令: git init 初始化版本倉庫 git
每日一python(7):基礎資料結構----字串
1、索引 例1: >>> s = "apple" >>> s[0] 'a' >>> s[1] 'p' >>> s[2] 'p' >>> s[3] 'l' >>> s[4]
DM 原始碼閱讀系列文章(七)定製化資料同步功能的實現
作者:王相 本文為 DM 原始碼閱讀系列文章的第七篇,在 上篇文章 中我們介紹了 relay log 的實現,主要包括 relay
標號(7):python(就業階段)——網路TCP
<1>TCP概念 英文全拼(Transmission Control Protocol)簡稱傳輸控制協議,它是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議. <2>TCP特點 1、 面向連線 TCP不適用於廣播的應用程式,基
arcgis jsapi介面入門系列(7):滑鼠在地圖畫線
初始化,每個map執行一次就行 drawPolylineInit: function () { //畫幾何物件初始化 //新建一個圖形圖層用於存放畫圖過程中的圖形 let layer = new t
python快速學習系列(7):迭代器
迭代器協議 1.迭代器協議: ·迭代器是一個物件 ·迭代器可以被next()函式呼叫,並返回一個值 ·迭代器可以被iter()函式呼叫,並返回迭代器自己 ·連續被next()呼叫時返回一系列的值 ·如果到了迭代的末尾,則丟擲StopIteration異常 ·迭代器也可以沒有末尾,只要被nex
TCP/IP學習筆記(7)-廣播,多播IGMP協議
單播,多播,廣播的介紹 單播(unicast) 單播是說,對特定的主機進行資料傳送。例如給某一個主機發送IP資料包。這時候,資料鏈路層給出的資料頭裡面是非常具體的目的地址,對於乙太網來 說,就是網絡卡的MAC地址(不是FF-FF-FF-FF-FF-FF這樣的地址)
解讀ASP.NET 5 & MVC6系列(7):依賴注入
在前面的章節(Middleware章節)中,我們提到了依賴注入功能(Dependency Injection),ASP.NET 5正式將依賴注入進行了全功能的實現,以便開發人員能夠開發更具彈性的元件程式,MVC6也利用了依賴注入的功能重新對Controller和View的服務注入功能進行了重新設計;未來的依賴
ONVIF協議網路攝像機(IPC)客戶端程式開發(7):裝置搜尋
1 專欄導讀 本專欄第一篇文章「專欄開篇」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解,專欄前面文章講過的知識點(或程式碼段),後面文章不會贅述。為了節省篇幅,突出重點,在文章中展示的示例程式碼僅僅是關鍵程式碼,你可以在「專欄開篇」中獲取完整程式碼。
【NLP】驀然回首:談談學習模型的評估系列文章(三)
作者:白寧超 2016年7月19日19:04:51 摘要:寫本文的初衷源於基於HMM模型序列標註的一個實驗,實驗完成之後,迫切想知道採用的序列標註模型的好壞,有哪些指標可以度量。於是,就產生了對這一專題進度學習總結,這樣也便於其他人蔘考,節約大家的時間。本文依舊旨在簡明扼要梳理出模型評估核心指標,
【NLP】驀然回首:談談學習模型的評估系列文章(二)
作者:白寧超 2016年7月19日10:24:24 摘要:寫本文的初衷源於基於HMM模型序列標註的一個實驗,實驗完成之後,迫切想知道採用的序列標註模型的好壞,有哪些指標可以度量。於是,就產生了對這一專題進度學習總結,這樣也便於其他人蔘考,節約大家的時間。本文依舊旨在簡明扼要梳理出模型評估核心指標,
【NLP】驀然回首:談談學習模型的評估系列文章(一)
作者:白寧超 2016年7月18日17:18:43 摘要:寫本文的初衷源於基於HMM模型序列標註的一個實驗,實驗完成之後,迫切想知道採用的序列標註模型的好壞,有哪些指標可以度量。於是,就產生了對這一專題進度學習總結,這樣也便於其他人蔘考,節約大家的時間。本文依舊旨在簡明扼要梳理出模型評估核心指標,
MVC之前的那點事兒系列(7):WebActivator的實現原理詳解
文章內容 上篇文章,我們分析如何動態註冊HttpModule的實現,本篇我們來分析一下通過上篇程式碼原理實現的WebActivator類庫,WebActivator提供了3種功能,允許我們分別在HttpApplication初始化之前,之後以及ShutDown的時候分別執行指定的程式碼,示例如下: [
樹莓派3學習筆記(7):7寸(分辨率800 480)顯示器配置
樹莓派、顯示器配置樹莓派3學習筆記(7):7寸(分辨率800 480)顯示器配置 樹莓派搭載分辨率為800X480的顯示器在顯示的時候可能會遇到無法全屏顯示的問題, 顯示器只有部分能夠顯示,有一部分是黑邊,對於這一種情況,我們只需進入系統的boot目錄,找到config.txt文件,或者直接在命
Windows Phone開發(7):當好總舵主
發的 content 數據 new 窗口 sdn 內容 str 剛才 吹完了頁面有關的話題,今天我們來聊一下頁面之間是如何導航的,在更多情況下,我們的應用程序不會只有一個頁面的,應該會有N個,就像我們做桌面應 用開發那樣,我們一個應用程序中可能不止一個窗體(極簡單的程序除外
springBoot(7):web開發-錯誤處理
spring boot 錯誤處理 處理方式一:實現ErrorController接口原理:Spring Boot 將所有的錯誤默認映射到/error, 實現ErrorController接口代碼:package com.example.demo.controller; import org.sp