本文章主要记录写socket代码时问题。
recv(size)大于缓冲区size会发生什么
这个问题是作者想要发送大文件,但传的很慢,于是提高缓冲区大小,虽然驴不对嘴,但是我照他的想了想,那应该跟正常没啥区别,这个问题就类似于缓冲区的数据为10,你应用里size为100,那接收的不就是10嘛。
如下代码
char msgbuffer[100];
int size;
if((size = recv(sock, msgbuffer, sizeof(msgbuffer), 0)) < 0){ //将缓冲区数据读到msgbuffer中
cout << "读取错误!错误原因 errno:" << errno << endl;
close(sock);
return 0;
}
else if(size == 0){
cout << "读端已关闭" << endl;
close(sock);
return 0;
}
else
cout << "读取成功:" << msgbuffer << endl << "读取字节:" << size << endl;
设置阙值
读阙值可以设置,写不可以,不知为什么
这个是由于网上文章写读写阙值分别为1和2048,但我查了下,都是1,且读阙值可以修改,写阙值不可以。
int val;
socklen_t valLen = sizeof(int);
cout << "套接字读缓冲" << endl;
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &valLen);
cout << "默认大小:" << val << endl;
getsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, &val, &valLen);
cout << "默认水位:" << val << endl;
cout << "套接字写缓冲" << endl;
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &valLen);
cout << "默认大小:" << val << endl;
getsockopt(sock, SOL_SOCKET, SO_SNDLOWAT, &val, &valLen);
cout << "默认水位:" << val << endl;
val = 1000;
setsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof(val));
getsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, &val, &valLen);
cout << "读水位修改为:" << val << endl;
val = 1000;
setsockopt(sock, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val));
getsockopt(sock, SOL_SOCKET, SO_SNDLOWAT, &val, &valLen);
cout << "写水位修改为:" << val << endl;
会发现写水位为1且不能修改。
读写和修改缓冲区大小
当读端数据>读端缓冲
当写端数据>写端缓冲,会发生什么。
当读端数据 > 读端缓冲
并不会发生什么。读端数据其实就是对端的发送数据。连接的时候发送端会根据读端缓冲区大小设置发送窗口,因此不会溢出。如下代码
//修改读端大小为最小:读端大小最小为2304
val = 1;
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, sizeof(int));
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &valLen);
cout << "读端大小 :" << val << endl;
//假设对端发送大于2304数据。设为20000
//recv 从缓冲区读
char msgbuffer[1000000];
int size;
int sum = 0;
while(true){
size = recv(sock, msgbuffer, sizeof(msgbuffer), 0);
cout << "读字节:" << size << endl;
sum += size;
if(sum == 20000){
cout << "读总和:" << sum << endl;
return 0;
}
}
我们会发现缓冲区的数据并不会超过缓冲区大小。
//将上边代码msgbuffer修改为100
char msgbuffer[100];
可以看到只读100。这是因为msgbuffer为100,但这并不代表缓冲只有100的数据。
当写端数据 > 写端缓冲
rwqrq
rqwrqw
//修改写端大小为最小:写端大小最小为4608
val = 1;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, sizeof(int));
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &valLen);
cout << "写端大小 :" << val << endl;
//假设对端发送大于2304数据。设为20000
//写入
char msgbuffer[20000];
int size;
size = send(sock, msgbuffer, sizeof(msgbuffer), 0);
cout << "写入字节:" << size << endl;
send(sock, msgbuffer, 1000000, 0); 要写100w
recv(sock, msgbuffer, 1000000, 0);要读100w
分别考虑两个事情
1.100w和缓冲区的空间
2.100w和缓冲区的数量
100w < 空间
写成功
100w = 空间
写成功
100w > 空间
写失败,返回写入的数量。
100w < 数量
读成功
100w = 数量
读成功
100w > 数量
读失败,返回读取的数量。
换句话说
当要写的>写入的,说明缓冲区空间<要写的且只有那么多
当要读的>读取的,说明缓冲区数量<要读的且只有那么多
recv(sock, msgbuffer, 1000000, 0);要读100w
返回 < 100w : 读缓冲有 < 100w的数据
返回 = 100w : 读缓冲有>=100w的数据
返回 > 100w : 不可能返回 > 100w