Программа аварийно завершает работу после получения слишком большого количества сообщений send () за короткий период времени. - PullRequest
0 голосов
/ 26 мая 2020

Моя цель - написать архитектуру клиент-сервер с использованием сокетов TCP в C. Мне успешно удалось установить sh соединение между клиентом и сервером, а также отправлять и получать сообщения обоими способами. После получения сообщения оно обрабатывается другими потоками. (Он будет поставлен в очередь, и с ней будет работать другой поток).

Сейчас я тестирую свою реализацию под нагрузкой, send() отправляя множество сообщений от клиента серверу.

Итак, по сути, он делает следующее:

Мой клиент переходит на l oop и отправляет X-сообщения, используя send(), на сервер. После выхода для l oop соединение с сервером будет close() d. Все это происходит сразу, без задержек.

Серверная программа работает следующим образом: у нее есть поток, в котором она принимает сообщения и обрабатывает сообщения, помещая их в очередь. После постановки в очередь он будет продолжать ждать поступления новых сообщений. Что происходит: серверная программа просто завершает работу без каких-либо сообщений об ошибке, кроме того, что ошибка recv() не выполнена (т.е. возвращается -1).

Я заметил следующее: сервер получает примерно 4000 из 5000 сообщений до того, как клиент вызовет close(). Если я жду в клиенте, пока сервер не получит все сообщения, прежде чем клиент вызовет close(), сервер не взломает sh и просто продолжит работу. Если я не буду ждать до вызова close(), сервер просто перестанет работать. Никакое сообщение об ошибке и даже основная функция сервера не завершится sh (основная функция фактически заблокирована sem_wait(), пока какой-то поток sem_post() не станет семафором).

Итак, что я делаю не так? Как я могу сделать сервер более надежным, даже если клиент, например, дает сбой во время выполнения? Я не хочу, чтобы сервер зависел от клиента.

Или я мог перегрузить сервер, отправив слишком много сообщений без промежуточных задержек, и мой сценарий нереалистичен c?

Вот некоторые части моего кода, которые имеют решающее значение для механизма отправки / получения:

Сервер:

read_bytes = recv(i, buffer, sizeof(buffer), 0);

// <= 0 bytes read iff client disconnected or error
if (read_bytes <= 0) {
    if(read_bytes == -1) {
        printf("error: recv() failed on port %s\n", port);
    } else {
        if(DEBUG_NETWORKING) printf("server:%s: socket %d disconnected\n", port, i);
    }

    // Disconnect and remove from master set
    close(i);
    FD_CLR(i, &master_set);
}

// Client wants to tell us something!
else {

    // Test if forcefully connected
    test = (int) buffer[0];

    if(test != 4) { // If it's NOT the EOT character (dec val =4), thus a "real message"
        if(DEBUG_NETWORKING) printf("server:%s: received from socket %d (%i bytes) : %s\n", port, i, read_bytes, buffer);
        // Now call the data handler function that was provided with the function call of connections_handler()
        handler(buffer, read_bytes, i, port);
    }

    // This happens if the client forcefullys quits the process
    // without sending a disconnect signal (it actually sends an EOT character)
    // Catch here this bug.
    else {
        if(DEBUG_NETWORKING) printf("server:%s: socket %d will disconnect forcefully\n", port, i);
    }
}

Клиент

int rand_item_id;
int rand_amount;
int action;
char msg[256] = "";
int i=0;

while(1) {
    i++;
    if(i==5000) break;
    if (atoi(argv[2]) != 0) {
        usleep(atoi(argv[2]));
    }

    rand_item_id = rand() % atoi(argv[3]);

    // either buy or get, 50/50% chance
    action = rand() % 2;
    if(action == 0) {
        // BUY
        rand_amount = rand() % 20;
        sprintf(msg, "BUY item_%i %i\n", i, rand_amount);
    } else {
        // GET
        sprintf(msg, "GET item_%i\n", i);
    }
    printf("%s\n", msg);

    send(sock, msg, strlen(msg), 0);
}

//sleep(10);
close(sock);

1 Ответ

2 голосов
/ 26 мая 2020

Программа завершается с сигнала 13, который равен SIGPIPE. Этот сигнал обычно используется только в том случае, если вы хотите выполнять асинхронный ввод-вывод, т.е. когда вы получаете сигнал, вы читаете.

У вас есть сообщение l oop, которое всегда ожидает сообщений, поэтому вы не Плевать на этот сигнал. Поэтому настройте обработчик сигнала, чтобы игнорировать его.

signal(SIGPIPE, SIG_IGN);
...