I have a client server program written in C. The goal is to see how fast big data can be broadcast over TCP. The host operating system (Ubuntu Linux 14. *) is configured to improve TCP performance in accordance with the documentation for scaling tcp / socket / windows, etc., as shown below:
net.ipv4.tcp_window_scaling = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 16384 16777216
This aprt, I also increased the size of a single socket buffer by calling setsockopt.
But I don’t see the program reacting to these changes - the total bandwidth is either flat or even reduced from time to time. When I received tcpdump on the receiving side, in most cases (99%) I see a monotonous 1368 tcp packet model.
19:26:06.531968 IP <SRC> > <DEST>: Flags [.], seq 25993:27361, ack 63, win 57, options [nop,nop,TS val 196975830 ecr 488095483], length 1368
According to the documentation, the tcp window scaling option increases the size of the received frame depending on demand and capacity - but all I see is "win 57" - there are very few bytes left in the receiving buffer, which does not match the expection.
Therefore, I begin to suspect my assumptions in the setup itself and ask the following questions:
Are there any specific settings required on the sending side to improve reception on the client side? Make sure that you (the program) write the entire piece of data at one time is not enough?
, , ? , , /etc/sysctl.conf, - . sysctl -system , ? ?
, ?
, , , .
:
#cat client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#define size 1024 * 1024 * 32
int main(){
int s;
char buffer[size];
struct sockaddr_in sa;
socklen_t addr_size;
s = socket(PF_INET, SOCK_STREAM, 0);
sa.sin_family = AF_INET;
sa.sin_port = htons(25000);
sa.sin_addr.s_addr = inet_addr("<SERVERIP");
memset(sa.sin_zero, '\0', sizeof sa.sin_zero);
addr_size = sizeof sa;
connect(s, (struct sockaddr *) &sa, addr_size);
int rbl = 1048576;
int g = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rbl, sizeof(rbl));
while(1) {
int ret = read(s, buffer, size);
if(ret <= 0) break;
}
return 0;
}
:
bash-4.1$ cat server.c
#include <sys/types.h>
#include <sys/mman.h>
#include <memory.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
extern int errno;
#define size 32 * 1024 * 1024
int main() {
int fdsocket;
struct sockaddr_in sock;
fdsocket = socket(AF_INET,SOCK_STREAM, 0);
int rbl = 1048576;
int g = setsockopt(fdsocket, SOL_SOCKET, SO_SNDBUF, &rbl, sizeof(rbl));
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = inet_addr("<SERVERIP");
sock.sin_port = htons(25000);
memset(sock.sin_zero, '\0', sizeof sock.sin_zero);
g = bind(fdsocket, (struct sockaddr *) &sock, sizeof(sock));
if(g == -1) {
fprintf(stderr, "bind error: %d\n", errno);
exit(1);
}
int p = listen(fdsocket, 1);
char *buffer = (char *) mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(buffer == -1) {
fprintf(stderr, "%d\n", errno);
exit(-1);
}
memset(buffer, 0xc, size);
int connfd = accept(fdsocket, (struct sockaddr*)NULL, NULL);
rbl = 1048576;
g = setsockopt(connfd, SOL_SOCKET, SO_SNDBUF, &rbl, sizeof(rbl));
int wr = write(connfd, buffer, size);
close(connfd);
}