Моя цель - написать архитектуру клиент-сервер с использованием сокетов 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);