一、简介:
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
3、server端关闭QUICKACK,client端开启NODELAY(立刻发送):client不等确认连续发送10个字符,server端在10ms后发送ack。疑问:为什么是10ms后发送ack”
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;
}