套接字socket选项TCP_NODELAY、TCP_CORK与TCP_QUICKACK

一、简介:
TCP_NODELAY关闭Nagle算法,控制的是数据的发送。Nagle 算法规定,如果包大于MSS(Max Segment Size)或含有FIN则立即发送,否则放入缓冲区,等已经发送的包被确认后后再发送。即网络上只能有一个未确认的小包。可以降低网络小包数量,减少了ip头部在网络上的比重,提升网络性能。
TCP_CORK:设置后不会发送任何小包(小于mss)除非超时200ms
TCP_QUICKACK (since Linux 2.4.4) 设置后会立刻发送确认ACK,而不是延迟发送ack。若未开启,则Delay ack延迟确认,使得协议有机会合并ack,提高网络利用率,默认40ms超时确认,系统值可配置。

二、测试:

测试方法:server ip 192.168.x.5,client ip 192.168.x.7。sever接受client连接,但是不做任何处理;client与server建立连接后,连续发送10个字符:
1、server端关闭QUICKACK,client端关闭NODELAY(也就是会延迟发送):server关闭了quickack,故会等一个超时再确认或等到有数据发送顺带发送确认ack,但server没数据发送,故等到40ms超时;由于client没有收到server端的确认ack,且nodelay关闭,即开启了延迟发送,所以等收到server的ack后才继续发送剩余数据

2、server端开启QUICKACK,client端开启NODELAY(立刻发送):server端收到一个数据后立刻发送确认给client

套接字socket选项TCP_NODELAY、TCP_CORK与TCP_QUICKACK_第1张图片

3、server端关闭QUICKACK,client端开启NODELAY(立刻发送):client不等确认连续发送10个字符,server端在10ms后发送ack。疑问:为什么是10ms后发送ack”

套接字socket选项TCP_NODELAY、TCP_CORK与TCP_QUICKACK_第2张图片

4、server端开启QUICKACK,client端关闭NODELAY(也就是会延迟发送):server收到数据后立刻发送确认给client,client将余下9个字符合并发送。

5、server端关闭QUICKACK,client端开启TCP_CORK:client端发送10个字符,远小于MSS,故等200ms超时后发送

三、总结:

延迟与带宽利用率不可兼得。若需要降低延迟,则应开启QUICKACK、NODELAY;否则两者都关闭,提高带宽利用率。

四、附demo

server代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#define BUFLEN 1024

int main(int argc, char** argv)
{
	int listenfd, connfd;
	socklen_t clilen;
	struct sockaddr_in cliaddr, servaddr;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	memset(&cliaddr, 0, sizeof(cliaddr));
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(9000);
	bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

	listen(listenfd, 128);
	printf("listen port 9000...\n");
	clilen = sizeof(cliaddr);
	connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);
	if(connfd <= 0) {
		perror("accept error\n");
		exit(1);
	}

	int quick = 1, size = 1;
	int rc = setsockopt(connfd, IPPROTO_TCP, TCP_QUICKACK, &quick, sizeof(int));
	
	sleep(10);
	close(connfd);
	return 0;
}

client代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFLEN 1024

int main(int argc, char** argv)
{
	int sockfd;
	struct sockaddr_in servaddr;

	if(argc !=2)
	{
		printf("usage: a.out server_addr\n");
		exit(1);
	}
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(9000);
	if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
	{
		printf("invalid addr: %s\n", argv[1]);
		return 1;
	}
	if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
	{
		printf("failed to connect to server %s, errno:%d\n", argv[1], errno);
		return 1;
	}
	int rc = 0;

	int nodelay = 1;
	rc = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(int));
	int cork = 1;
	rc = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &cork, sizeof(int));

	printf("nodelay test connected, nodelay set \n");
	char sendline[2] = {0};
	sendline[0] = 'a';
	int n = 0;
	for(int i = 0;i<10;i++)
		n+=write(sockfd, sendline, strlen(sendline));
	printf("%d bytes are sent\n", n);
	if(read(sockfd, sendline, 2) <=0)
	{
		printf("server terminated \n");
		exit(1);
	}

	return 0;
}

你可能感兴趣的:(网络编程,网络,tcp/ip,服务器)