根据我的理解,每个套接字都与两个缓冲区相关联,即发送缓冲区和接收缓冲区,因此当我调用send()
函数时,要发送的数据将被放入发送缓冲区,现在Windows有责任将此发送缓冲区的内容发送到另一端。
在阻塞套接字中,send()
函数不会返回,直到所提供的所有数据都被放入发送缓冲区为止。
那么发送缓冲区的大小是多少?
我进行了以下测试(发送1 GB的数据):
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
int main()
{
// Initialize Winsock
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
// Create socket
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
//----------------------
// Connect to 192.168.1.7:12345
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.1.7");
address.sin_port = htons(12345);
connect(s, (sockaddr*)&address, sizeof(address));
//----------------------
// Create 1 GB buffer ("AAAAAA...A")
char *buffer = new char[1073741824];
memset(buffer, 0x41, 1073741824);
// Send buffer
int i = send(s, buffer, 1073741824, 0);
printf("send() has returned\nReturn value: %d\nWSAGetLastError(): %d\n", i, WSAGetLastError());
//----------------------
getchar();
return 0;
}
输出:
send() has returned
Return value: 1073741824
WSAGetLastError(): 0
send()
立即返回,这是否意味着发送缓冲区的大小至少为1 GB?
关于测试的一些信息:
- 我正在使用TCP阻塞套接字。
- 我已连接到一个LAN机器。
- 客户端Windows版本:Windows 7 Ultimate 64位。
- 服务器Windows版本:Windows XP SP2 32位(安装在Virtual Box中)。
编辑:我还尝试连接到Google(173.194.116.18:80),并且得到了相同的结果。
编辑2:我发现了一些奇怪的事情,将发送缓冲区设置为64 KB和130 KB之间的值将使send()
按预期工作!
int send_buffer = 64 * 1024; // 64 KB
int send_buffer_sizeof = sizeof(int);
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)send_buffer, send_buffer_sizeof);
编辑 3:后来(多亏了 Harry Johnston)我发现我错误地使用了 setsockopt()
,这是正确的用法:
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&send_buffer, send_buffer_sizeof);
将发送缓冲区设置为64 KB到130 KB之间的值不能使send()
按预期工作,而是将发送缓冲区设置为0
会使其阻塞(这是我观察到的,我没有任何关于此行为的文档)。
那么我的问题是:在哪里可以找到有关Windows下如何使用send()
(以及可能的其他套接字操作)的文档?
getsockopt()
函数自己发现大小。那么你如何知道它是否立即返回呢?这段代码无法告诉你。 - user207421getsockopt()
时发生了什么?你得到了什么值?显然是一个很大的值。 - user207421Socket.Send
调用会阻塞。进程变得无法终止 :(. 这是在向Google发送数据的物理机器上发生的。当Send
调用开始时,由Commit Charge测量的系统内存使用情况没有增加。 - usr