1. 程式人生 > >socket之send與傳送緩衝區大小的關係

socket之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(int);

    buf = (char *)malloc(1024 * 3);	
    fd = socket(AF_INET, SOCK_STREAM,0 );

    setsockopt(fd,SOL_SOCKET, SO_SNDBUF,(const char*)&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,(const char*)&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都會分幀傳送。

相關推薦

socketsend傳送緩衝區大小關係

自己做了個測試,伺服器只起socket在偵聽,不recv, 也不send. //ubuntu10.04 32bit #include <stdio.h> #include <sys/types.h> #include <sys/socke

tcp協議系列文章(7):send()的資料大小可用的傳送緩衝區大小關係

筆者這裡要指出的是,man send 手冊上說的或許與send()的版本有關。詳細的,可以檢視筆者的另一篇部落格,上面有就send()的行為的詳細說法。 下面的部落格內容,其實驗證的方法與驗證的目的並不相同!!!請讀者注意!!! 自己做了個測試,伺服器只起s

C++ Socket程式設計(二) sendrecv 緩衝區阻塞

socket緩衝區 每一個socket在被建立之後,系統都會給它分配兩個緩衝區,即輸入緩衝區和輸出緩衝區。 send函式並不是直接將資料傳輸到網路中,而是負責將資料寫入輸出緩衝區,資料從輸出緩衝區傳送到目標主機是由TCP協議完成的。資料寫入到輸出緩衝區之

六、資料庫表之間的關係

  表1 foreign key 表2 則表1的多條記錄對應表2的一條記錄,即多對一 利用foreign key的原理我們可以製作兩張表的多對多,一對一關係 多對多: 表1的多條記錄可以對應表2的一條記錄 表2的多條記錄也可以對應表1的一條

(多圖) 超強整理!PCB設計電流線寬的關係

源:(多圖) 超強整理!PCB設計之電流與線寬的關係 http://www.51hei.com/bbs/dpj-39134-1.html   關於PCB線寬和電流的經驗公式,關係表和軟體網上都很多,本文把網上的整理了一下,旨在給廣大工程師在設計PCB板的時候提供方便。 以下總結了

mysql學習【第6篇】:資料庫表之間的關係 資料庫表之間的關係

資料庫之 表與表之間的關係 表1 foreign key 表2 則表1的多條記錄對應表2的一條記錄,即多對一

超強整理!PCB設計電流線寬的關係

超強整理!PCB設計之電流與線寬的關係   關於pcb線寬和電流的經驗公式,關係表和軟體網上都很多,本文把網上的整理了一下,旨在給廣大工程師在設計PCB板的時候提供方便。     以下總結了八種電流與線寬的關係公式,表和計算公式,雖然各不相同(大體

微信公眾號開發接收傳送訊息

說明:該篇部落格是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝大家! 在上一篇部落格中已經驗證了伺服器有效性:https://blog.csdn.net/qq_41782425/article/details/85321424 一丶概論 公眾號接收與傳送訊息 驗證

Socketsend方法傳送結構體和recv接受結構體

  Socket中的send函式可以傳送字串,但不能直接傳送結構體,因此在傳送端先把結構體轉成字串,然後用send傳送,在接收端recv字串,再轉換成原先的結構體,這個就是解決問題的主要思路,實現中要注意的問題在下文闡述。   為了客戶端之間能夠互相通訊,實現私聊

資料庫表之間的關係

表1 foreign key 表2 則表1的多條記錄對應表2的一條記錄,即多對一 利用foreign key的原理我們可以製作兩張表的多對多,一對一關係 多對多: 表1的多條記錄可以對應表2的一條記錄 表2的多條記錄也可以對應表1的一條記錄 一對一:

socketsend和recv原理剖析

談到網路socket程式設計, 我們不得不提兩個基本也很重要的函式:send和recv.  對socket程式設計理解不深的童鞋容易產生這樣一個錯誤的認識: send函式是用來發送資料, 而recv函式是用來接收資料的, 其實, 這種觀點是稍微有點偏頗的, 掩蓋了本質。

boost庫socket 非阻塞/緩衝區大小等屬性設定

asio socket 非阻塞/緩衝區大小等屬性設定ip::tcp::socket m_socket  //設定阻塞與非阻塞void SetNoBlock(bool bNoBlock){ if(bNoBlock) {  boost::asio::socket_base::by

面試經典問題-傳送/接受視窗快取的關係

1,tcp傳輸報文段,傳送視窗與快取的關係??? 2,普通意義上的,TCP傳輸報文段的時候會產生稍帶確認嗎??? 3,接受方收到位元組確認不是按順序的,那麼對這些東西已經收到的確認號如何處理???

設定SOCKET傳送接收緩衝區

主  題: 淺析:setsockopt()改善程式的健壯性 作  者: gdy119 (夜風微涼) 不斷的收到coolmei25 (梅生)的答謝,我都不好意思了(我都沒幫到他),下面寫出我在網路程式設計中的一點心得體會,希望對他(^_^也對大家)有幫助:1. 如果在已經處於

Socketsend/recv的迴圈傳送和接收、緩衝區、阻塞

這篇文章略作刪減後轉過來了。主要有以下幾點值得自己注意的: (1)剛開頭對套接字的理解。 (2)緩衝區的理解。 其他部分有時間重新整理。 套接字的概念及分類        在網路中,要全域性的標識一個參與通訊的程序,需要三元組:協議,IP地址以及埠號。要描述兩個應用

Java Socket 實現HTTPHTTPS協議傳送POST/GET請求

JAVA Socket 實現HTTP與HTTPS客戶端傳送POST與GET方式請求         哇,一看標題怎麼這麼長啊,其實意思很簡單,哥討厭用HTTP Client做POST與GET提交覺得那個畢竟是別人寫得AP

python摸爬滾打day17----類類之間的關係

1、類與類之間的聯絡  1.1  依賴關係    類A中使用了類B, 類B作為引數傳進類A的方法中被使用. 這種關係中類與類之間的聯絡是最輕的.  1 class Elephant: 2 3 def open(self,ele):

1015 - 計算幾何多邊形的關係 - Points Within(ZOJ1081)

傳送門   分析 射線法 雖然這個射線法有很多需要特判的情況,但總的來說還是蠻好用的 判斷點與多邊形的關係,若使用射線法,就是說從這個點往右做一條與 x 軸平行的射線,看它與多邊形相交了幾次 若相交了偶數次,則不在多邊形內部(相當於從這個多邊形中穿過去,沒有留在

1015 - 計算幾何直線直線的關係 - Intersecting Lines(POJ1269)

傳送門   題意 給你兩條直線 若其相交則輸出  交點的座標 若其平行則輸出  NONE 若其重合則輸出  LINE   分析 比較基礎的計算幾何,就是考向量的使用 判斷兩條直線是否平行,就是看其叉積是否為

1016 - 計算幾何直線的關係 - TOYS(POJ 2318)

傳送門   題意 給你一個這樣的圖 然後隨機給你 m 個點,問落在每一個區域內的點有多少個   分析 入門題入門題 依舊是利用叉積,叉積太強了! 二分尋找並判斷     gsj太厲害了,簡直每次我演算法