您的位置:首页 > 其它

阻塞和非阻塞套接字一次可以发送多大的数据量

2016-01-18 11:14 323 查看
我们应该知道无论是阻塞还是非阻塞,其调用send来发送数据的实质是将应用程序缓冲区的数据拷贝到socket缓冲区中,然后协议栈对这些数据进行发送,也就说send就是拷贝。因此我之前的理解是:对于套接字发送数据(阻塞和非阻塞),其一次发送的数据量不能大于socket缓冲区的大小。

在当前项目中使用的是非阻塞套接字,并且将socket的发送缓冲区大小设置为1M,以防止较大量的数据发送。现在遇到了一个数据包的大小大于1M的情况,这总不能一直来扩大socket的发送缓冲区吧,担心会使数据拷贝的时间大大增大。因此参照了darwin的数据发送,发现其发送数据时没有考虑数据量与socket发送缓冲区的大小,并且socket的发送缓冲区被设置为96K,但是可以调用send函数来发送数据量为几M的数据。这是为什么?

难道应该是这样:阻塞套接字一次发送的数据量不能大于socket缓冲区的大小,而非阻塞可以。

伟人毛主席说过,没有调查就没有发言权。对于程序员,能用代码说的事就不要猜测,下面写了一个小的程序来测试阻塞和非阻塞套接字一次可以发送的数据量有多大:

//建立一个win32控制台应用程序
#include "stdafx.h"
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include<iostream>
using std::cout;
using std::endl;
int _tmain(int argc, _TCHAR* argv[])
{

WORD wVersionRequested;
WSADATA wsaData={0};
int err;

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return -1;          // 返回值为零的时候是表示成功申请WSAStartup
}

cout<<"初始化成功"<<endl;
SOCKET sd=socket(AF_INET,SOCK_STREAM,0);
if(sd==INVALID_SOCKET)
{
cout<<"创建套接字失败\n"<<endl;
WSACleanup();
return 0;
}
cout<<"创建socket成功"<<endl;

int nSendBuf=1024*1024;//设置发送缓冲区的大小1M
if(setsockopt(sd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int))==SOCKET_ERROR)
{
cout<<"设置发送缓冲区失败"<<endl;
closesocket(sd);
WSACleanup();
}
cout<<"设置发送缓冲区成功"<<endl;

sockaddr_in saServer;
saServer.sin_family=AF_INET;
saServer.sin_addr.s_addr=inet_addr("192.168.4.199");
saServer.sin_port=htons(10000);
if(connect(sd,(sockaddr*)&saServer,sizeof(sockaddr_in))==SOCKET_ERROR)//在此使用阻塞套接字连接
{
cout<<"连接服务器失败"<<endl;
closesocket(sd);
WSACleanup();
return 0;
}
cout<<"连接服务器成功"<<endl;
cout<<"阻塞套接字测试"<<endl;;
char *SendBuf=new char[1024*1024*2];
int i=0;
int SendLen;
while(i++<10)//测试10次
{
SendLen=send(sd,SendBuf,1024*1024*2,0);
if(SendLen==SOCKET_ERROR)
{
cout<<"错误代码"<<WSAGetLastError()<<endl;
}
else
{
cout<<"发送数据长度为"<<SendLen<<endl;
}
}

unsigned long ul = 1;
if(ioctlsocket(sd, FIONBIO,&ul)==SOCKET_ERROR)
{
cout<<"设置非阻塞模式失败"<<endl;
closesocket(sd);
WSACleanup();
return 0;
}

cout<<"设置非阻塞模式成功"<<endl;
cout<<"非阻塞套接字测试"<<endl;
i=0;
while(i++<10)//测试10次
{
SendLen=send(sd,SendBuf,1024*1024*2,0);
if(SendLen==SOCKET_ERROR)
{
cout<<"错误代码"<<WSAGetLastError()<<endl;
}
else
{
cout<<"发送数据长度为"<<SendLen<<endl;
}
}
closesocket(sd);
WSACleanup();
delete[] SendBuf;

system("pause");
return 0;
}
代码很简单,创建了一个指定发送缓冲区大小为1M的socket,并分别测试其在阻塞和非阻塞模式下发送2M的数据的能力。这仅仅是一个客户端程序,服务器程序使用的是测试工具TCP/UDP debug,其运行结果截图如下:





由结果可知。对于非阻塞和阻塞套接字,其一次可以发送的数据的大小均不受socket发送缓冲区大小的限制。至于非阻塞下面的10035错误代码,只是表明当前缓冲区满而已,只需在合适的时候再次调用send进行发送即可。如果是这样的话,那么socket的使用就简单多了,看来send里面还是封装了不少的东西,期待看到linux下的源码实现。

如有错误,欢迎指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: