本次尝试主要研究 linux socket接受发送缓冲区的大小,以及当缓冲区阻塞时,能发送多少数据。
(1)实验与尝试
测试环境: vmware虚拟机 centos7系统。
服务端建立连接后睡眠,应用层不接受任何数据,只有内核接受缓冲区才接受数据。
服务端代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 8096
int main(int argc, char** argv){
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[MAXLINE];
FILE *fp;
int n;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
printf("----init socket----\n");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
//设置端口可重用
int contain;
setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &contain, sizeof(int));
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
printf("----bind sucess----\n");
if( listen(listenfd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
if((fp = fopen("new.txt","ab") ) == NULL )
{
printf("File.\n");
close(listenfd);
exit(1);
}
printf("======waiting for client's request======\n");
while(1){
struct sockaddr_in client_addr;
socklen_t size=sizeof(client_addr);
if( (connfd = accept(listenfd, (struct sockaddr*)&client_addr, &size)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
int s_length;
socklen_t optl = sizeof s_length;
getsockopt(connfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl);
printf("server connfd send buffer = %d\n",s_length);
getsockopt(connfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl);
printf("server connfd recv buffer = %d\n",s_length);
sleep(300000);
while(1){
n = read(connfd, buff, MAXLINE);
if(n == 0)
break;
fwrite(buff, 1, n, fp);
}
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
close(connfd);
fclose(fp);
}
close(listenfd);
return 0;
}
客户端代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 8096
int main(int argc, char** argv){
int sockfd, len;
char buffer[MAXLINE];
struct sockaddr_in servaddr;
FILE *fq;
/*
if( argc != 2){
printf("usage: ./client \n");
return 0;
}
*/
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
/*
if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n",argv[1]);
return 0;
}
*/
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
int s_length;
socklen_t optl = sizeof s_length;
getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl); //
printf("client send buffer = %d\n",s_length); //
getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl); //
printf("client recv buffer = %d\n",s_length);
if( ( fq = fopen("/root/socket/all.txt","rb") ) == NULL ){
printf("File open.\n");
close(sockfd);
exit(1);
}
bzero(buffer,sizeof(buffer));
int sum = 0;
int writelen = 0;
while(!feof(fq)){
len = fread(buffer, 1, sizeof(buffer), fq);
writelen = write(sockfd, buffer, len);
if(writelen < 0) {
printf("write.\n");
break;
}
sum += writelen;
printf("writelen %d sum %d\n",writelen, sum);
}
printf("sum %d", sum);
close(sockfd);
fclose(fq);
return 0;
}
运行服务端 效果截图如下:
客户端截图效果如下
最后写多少数据进去不同的时期运行结果不是固定的
(3)分析与疑惑:
客户端与服务端的连接socket 内核发送缓冲区约为2.6M,接收缓冲区为1M,按照以前的想法,文本数据all.txt 的大小约为8.8M,客户端每次向发送缓冲区写如8096字节。按照原来的设想,客户端能写入的字节 = 客户端发送缓冲区大小 + 服务端接收缓冲区大小,约3.6M。事实上客户端写入的字节数均大于4.7M,与设想不符合。
(3)尝试解决
尝试使用抓包工具wiresha'rk,查看tcp连接状态以及窗口大小,单服务器与客户端都再虚拟机上,发包没有经过网卡,故捕获不了。利用linux自带的 tcpdump -i -lo 抓取回环网口的包,截图如下;
结论尚未明确,等待下一部操作。有知情大佬请留言。