socket之send与发送缓冲区大小的关系
2013-06-17 16:06
344 查看
关于send函数在发送的数据长度大于发送缓冲区大小,或者大于发送缓冲区剩余大小时,socket会怎么反应。参见这篇博客的两种说法/article/8175885.html
自己做了个测试,服务器只起socket在侦听,不recv, 也不send.
客户端,将发送缓冲区大小设置成2k,然后一次发送3k的数据。
交互报文
从这里看出当发送长度大于缓冲区大小时,是分次发送,三次加起来 1448 + 1448 + 176 = 3072
在windows下,做同样的测试
分三次发送1460+1460+152 = 3072
上面都是阻塞的发送,对于socket是非阻塞的话,做同样的测试
和blocking socket表现是一样的,一次send,协议栈分三帧发送。
可见,当send的数据长度大于socket的缓冲区长度时,不管是windows还是linux,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都会分帧发送。
相关文章推荐
- tcp协议系列文章(7):send()的数据大小与可用的发送缓冲区大小的关系
- socket之send与发送区的大小关系
- socket编程缓冲区大小对send()的影响
- 如何获取SOCKET 发送缓冲区使用大小
- socket编程缓冲区大小对send()的影响
- tcp socket发送缓冲区、接受缓冲区、滑动窗口协议之间的关系
- Linux:测试socket发送和接收时,缓冲区buf的大小
- 如何获取/设置socket对应的内核缓冲区(发送,接收)的大小
- socket对应的内核缓冲区(发送,接收)的大小
- Linux下Socket编程中用send发送结构体
- socket的发送和接收缓冲区
- 修改socket收发缓冲区大小限制
- tcp socket的发送与接收缓冲区
- Socket编程注意接收缓冲区大小
- send和recv只是内核缓冲区和应用程序缓冲区之间的搬运工---严格来讲send和recv并不具备发送和接收功能
- TCP滑动窗口和socket缓冲区之间的关系(记录)
- tcp/ip协议栈--socket API 之发送函数(send/write)
- socket的发送与接收缓冲区
- boost库之socket 非阻塞/缓冲区大小等属性设置
- CocoaAsyncSocket UDP发送数据超过包大小限制(Message too long)