Я немного поигрался с API сокетов, чтобы понять, как он работает.
Я написал две маленькие программы:
- Сервер прослушивает 8080 для потокового соединения. Каждому, кто подключается к нему, отправляется простое сообщение.
- Клиент подключается к 127.0.0.1:8080 и выгружает то, что он получает, в стандартный вывод. Это повторяется 20000 раз подряд.
Сообщения передаются невероятно быстро до ~ 16370 раз, затем они останавливаются на десятки секунд, прежде чем снова начинают двигаться очень быстро, чтобы завершить 20000 соединений.
Я повторил этот эксперимент несколько раз и поймал его в 16370, 16371 и 16372. Он удивительно последовательн в повторных экспериментах.
Мой вопрос: зачем делать паузу после ~ 16370 итераций? Что за узкое место здесь?
FWIW, я на MacOS Sierra.
Я запускаю код сервера следующим образом:
clang -Wall -Werror -Wpedantic server.c -o server.out && ./server.out
и код клиента вот так:
clang -Wall -Werror -Wpedantic client.c -o client.out && time ./client.out
Вот две программы:
server.c
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define PORT 8080
#define MAXMSG 512
int make_socket(int port) {
int sock;
struct sockaddr_in name;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(1);
}
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr*) &name, sizeof(name)) < 0) {
perror("bind");
exit(1);
}
return sock;
}
int main(int argc, char** argv) {
const char hello[] = "Hello visitor ";
char buffer[MAXMSG];
int sk;
unsigned long count = 0;
strcpy(buffer, hello);
sk = make_socket(PORT);
listen(sk, 10);
printf("ready\n");
for (;;) {
count++;
sprintf(buffer + strlen(hello), "%lu", count);
int s = accept(sk, NULL, NULL);
if (send(s, buffer, strlen(buffer) + 1, 0) < 0) {
perror("send");
exit(1);
}
close(s);
printf("data socket (%d) message sent (%s)\n", s, buffer);
}
}
client.c
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define PORT 8080
#define MAXMSG 512
int make_socket() {
int sock;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(1);
}
return sock;
}
int main(int argc, char** argv) {
char buffer[MAXMSG];
int sk;
size_t i;
struct sockaddr_in addr;
strcpy(buffer, "Hello world!");
for (i = 0; i < 20000; i++) {
sk = make_socket();
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sk, (struct sockaddr*) &addr, sizeof(addr));
recv(sk, buffer, strlen(buffer) + 1, 0);
close(sk);
printf("socket (%d) message = %s\n", sk, buffer);
}
}
Это последний вывод, который я получаю на стороне клиента:
socket (3) message = Hello visitor 16369
socket (3) message = Hello visitor 16370
socket (3) message = Hello visitor 16371
socket (3) message = Hello visitor 16372