send()函數默認情況下會使用Nagle算法。Nagle算法通過將未確認的數據存入緩沖區直到積攢到一定數量一起發送的方法。來降低主機發送零碎小數據包的數目。所以假設send()函數發送數據過快的話,該算法會將一些數據打包后統一發出去。假設不了接這樣的情況,接收端採會遇到看似非常奇怪的問題,比方成功recv()的次數與成功send()的次數不相等。在這中情況下,接收端能夠通過recv()的返回值是否為0來推斷發送端是否發送完成。
通過setsockopt()的TCP_NODELAY選項來禁用Nagle算法。但經試驗這樣的方法似乎不總是有效,只是對於同樣數量的send(),設置了TCP_NODELAY選項后recv()成功的次數要比設置之前多出幾倍。這是不是說明設置了TCP_NODELAY后,系統會進最大的努力不去緩存。可是假設send的實在太快的話,還是會緩存的。
因此。假設你不希望send()的數據被本地緩存到一定數量之后再發送,而是send()多少次就發送多少次。穩妥的方式還是每次send之后調用一下usleep()函數,給系統一個反應的時間。
以下的樣例演示了send()調用的快慢對數據是否打包的影響,凝視掉server里的usleep(1000),會導致數據打包發送。
TCP_NODELAY是唯一使用IPPROTO_TCP層的選項,宏TCP_NODELAY的頭文件是linux/tcp.h或者netinet/tcp.h。
由於不知到send()數據緩存的問題,我調試一天的程序。我的五一勞動節啊!!
server.c:
#include<stdlib.h> #include<stdio.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<sys/wait.h> #include<netinet/in.h> #include<netdb.h> #include<arpa/inet.h> #include<netinet/tcp.h> //#include<linux/tcp.h> int main(){ int socksv, sockcl; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size; if((socksv = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("sever socket fail\n"); return -1; } memset(&server_addr, 0, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(6001); server_addr.sin_addr.s_addr = INADDR_ANY; int r = 1; setsockopt(socksv, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(int)); int t = 1; if(-1 == setsockopt(socksv, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(int))){ printf("setsockopt fail\n"); return -1; } if(bind(socksv, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){ printf("server bind fail\n"); return -1; } if(listen(socksv, 5) == -1){ printf("server listen fail\n"); return -1; } while(1){ sin_size = sizeof(struct sockaddr_in); if((sockcl = accept(socksv, (struct sockaddr *)&client_addr, &sin_size)) == -1){ printf("server accept fail\n"); continue; } int times = 1024; int allbytes = 0; int i; for(i = 0; i < times; i++){ char buf[] = "#this is a message from ptypeServer"; int sendbytes; if((sendbytes = send(sockcl, buf, strlen(buf), 0)) == -1){ printf("server send fail\n"); } usleep(1000); allbytes += sendbytes; } printf("have send %d packages to client, allbytes=%d\n", times, allbytes); close(sockcl); } }
client.c :
#include<stdlib.h> #include<stdio.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<sys/wait.h> #include<netinet/in.h> #include<netdb.h> #include<arpa/inet.h> int main(){ int socksv; char buf[1024 * 1024]; if((socksv = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("socket fail\n"); return -1; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(6001); server_addr.sin_addr.s_addr = inet_addr("192.168.1.100"); if(connect(socksv, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){ printf("connect fail\n"); return -1; } int times = 0; int allbytes = 0; int numbytes = 1; while(numbytes != 0){ times++; if((numbytes = recv(socksv, buf, sizeof(buf), 0)) == -1){ printf("recv fail\n"); return -1; } // buf[numbytes] = '\0'; // printf("numbytes=%d buf=[%s]\n", numbytes, buf); allbytes += numbytes; } printf("server is closed, have recv %d packages from server, " "allbytes=%d\n", times - 1, allbytes); }
參閱: http://baike.baidu.com/link?url=-QgA0U7iv5tno-qnorYKDMNazOeOdcGk-pKIVFcOy-n6vhoITKdzlCg1VZYjqJ1DnOlpaaA54E7HrqQX6Bc_e_