Hello! I'm writing an application that is working over TCP. Total traffic is very low (~ 10 kb/sec), but performance is very bad. I've tried to investigate problem with tcpdump and strace, and it shows that application does multiple writes, but TCP buffers them and send after some delay (about 40 msec). Due to nature of my application, it is essential to send any available data ASAP (decreased bandwidth is not important). I've set TCP_NODELAY option on socket, but it doesn't help.
We've written a simple program to reproduce the effect. It sends 10 small packets, then sleeps for 0.1 sec. Another node tries to receive data. Strace shows that 2 packets are sent immediately and other 8 are grouped together and delayed by 40 msec. It is interesting that this effect can be seen not only on Ethernet links, but on loopback also (with the same magic constant of 40 msec). Here is a test run: server (should be run first): $ ./a.out 1 5000 Server: begin send_all Server: total time 14.216441 client: $ ./a.out 2 5000 localhost Client: connected to localhost:5000 Client: begin receive_all Client: total time 14.223265 Expected time is 10.0 sec (instead of 14.0 sec). If packets are received more often (DELIM constant is set to 1 or 2) then effect disappear. Is this a desired behaviour? How can I specify that packets should be sent really immediately after write? Some people reported that this program runs in 9.997 sec when run on FreeBSD. Please cc me on replies, as I'm not subscribed to mailing list. With best regards, Alexander. Listing follows: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <time.h> int TOTAL_SENDS = 1000; int DELIM = 10; int sock = -1; int init_server(int port) { struct sockaddr_in sin; struct sockaddr_in new_sin; int new_sock; int val; int sockaddrlen; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) return -1; val = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) return -1; memset(&sin,0,sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(port); if (-1 == bind(sock,(struct sockaddr*)&sin,sizeof(sin))) return -2; if (-1 == listen(sock,1)) return -3; sockaddrlen = sizeof(struct sockaddr_in); new_sock = accept(sock,(struct sockaddr*)&new_sin,(socklen_t*)&sockaddrlen); if (new_sock == -1) return -4; sock = new_sock; val = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != 0) return -5; return 0; } int init_client(char* hostname, int port) { int val; int res; struct sockaddr_in sin; sock = socket(PF_INET, SOCK_STREAM, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); memcpy(&sin.sin_addr, gethostbyname(hostname)->h_addr, 4); val = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); res = connect(sock, (struct sockaddr*)&sin, sizeof(sin)); printf("Client: connected to %s:%d\n", hostname, port); if (res == -1) return -1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); return 0; } void send_all(unsigned long delay) { int i; char buf[1024]; printf("Server: begin send_all\n"); for (i = 1; i < TOTAL_SENDS; ++i) { write(sock, buf, 1); if (i % DELIM == 0) read(sock, buf, 1); if (i % 10 == 0) usleep(delay); } } void receive_all(unsigned long delay) { int i; char buf[1024]; printf("Client: begin receive_all\n"); for (i = 1; i < TOTAL_SENDS; ++i) { read(sock, buf, 1); if (i % DELIM == 0) write(sock, buf, 1); if (i % 10 == 0) usleep(delay); } } int main(int argc, char* argv[]) { int port; char* host; int me; struct timeval tv1, tv2; double tt; assert(argc > 2); me = atoi(argv[1]); switch (me) { case 1: port = atoi(argv[2]); if (init_server(port)) { printf("Server initialization failed!\n"); return 1; } gettimeofday(&tv1, 0); send_all(100000); gettimeofday(&tv2, 0); tt = tv2.tv_sec - tv1.tv_sec + (tv2.tv_usec - tv1.tv_usec) * 0.000001; printf("Server: total time %f\n", tt); break; case 2: assert(argc == 4); port = atoi(argv[2]); host = argv[3]; if (init_client(host, port)) { printf("Client initialization failed!\n"); return 1; } gettimeofday(&tv1, 0); receive_all(100000); gettimeofday(&tv2, 0); tt = tv2.tv_sec - tv1.tv_sec + (tv2.tv_usec - tv1.tv_usec) * 0.000001; printf("Client: total time %f\n", tt); break; default: printf("Wrong parameter\n"); return 1; } shutdown(sock, SHUT_RDWR); close(sock); return 0; } - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html