Сброс соединения путем программирования одноранговых сокетов

Я получаю сообщение об ошибке в коде на стороне клиента о соединение сброшено узлом, когда я вызываю функцию Отправить из клиента --> сервера. Я посмотрел это в Интернете, но я не совсем понимаю, может ли кто-нибудь объяснить, что вызывает эту ошибку и почему?

Это код клиентского сокета. Я заставил его принимать сервер на 127.0.0.1.

КЛИЕНТ.С

#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERVER_PORT 9002
#define BUFSIZE 4096
#define SOCKETERROR (-1)
#define SERVER_BACKLOG 1

typedef struct sockaddr_in SA_IN;
typedef struct sockaddr SA;

struct sockaddr_in init_socket(const char* address);
void check(int output,const char* msg);

int main(int argc,char** argv){

int     number = 0;
int     client_socket;
SA_IN   client_address;


check((client_socket = socket(AF_INET,SOCK_STREAM,0)),"[SERVER] : cannot create socket");
client_address = init_socket("127.0.0.1");
check(connect(client_socket,(struct sockaddr*)&client_address,sizeof(client_address)),"[CLIENT]--(connect)--->[SERVER] ");

 while(1){ 
    if(send(client_socket,&number,sizeof(number),0),"[CLIENT]-------->[SERVER] " > 0){

        number++;
        if(number == 100) break;
        printf("[CLIENT] : %d\n",number);

        check(recv(client_socket,&number,sizeof(int),0),"[CLIENT]-------->[SERVER] ");
    }
}
close(client_socket);
return 0;
}

struct sockaddr_in init_socket(const char* address){
    struct sockaddr_in server_address;
    server_address.sin_family       = AF_INET; 
    server_address.sin_port         = htons(SERVER_PORT);
    // server_address.sin_addr.s_addr  = INADDR_ANY;
    server_address.sin_addr.s_addr  = inet_addr(address);
    return server_address;
}

void check(int output,const char* msg){
    if(output < 0){
        perror(msg);
        exit(1);
    }
}

Это код серверного сокета. Он принимает клиентов с любого адреса (INADDR_ANY).

СЕРВЕР.C

#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERVER_PORT 9002
#define BUFSIZE 4096
#define SOCKETERROR (-1)
#define SERVER_BACKLOG 1

typedef struct sockaddr_in SA_IN;
typedef struct sockaddr SA;

void handle_connection(int client_socket);
struct sockaddr_in init_socket();
void check(int output,const char* msg);

int main(int argc,char** argv){

    int     number;
    int     server_socket   , client_socket;
    SA_IN   server_address  ,client_address;
    
    check((server_socket = socket(AF_INET,SOCK_STREAM,0)),"[SERVER] : cannot create socket");
    server_address = init_socket();
    check(bind(server_socket,(SA*)&server_address,sizeof(server_address)),"[SERVER] : binding error");
    check((client_socket = listen(server_socket,SERVER_BACKLOG)),"[SERVER] : listen failed");

     while(1){ 
        if(recv(client_socket,&number,sizeof(int),0) > 0){


            number++;
            if(number == 100) break;
            printf("[SERVER] : %d\n",number);

            check(send(client_socket,&number,sizeof(number),0),"[SERVER]-------->[CLIENT]: ERROR");
        }
    }
    close(server_socket);
    return 0;
}

struct sockaddr_in init_socket(){
    struct sockaddr_in server_address;
    server_address.sin_family       = AF_INET; 
    server_address.sin_port         = htons(SERVER_PORT);
    server_address.sin_addr.s_addr  = INADDR_ANY;
    return server_address;
}

void check(int output,const char* msg){
    
    if(output < 0){
        fprintf(stderr,"%s\n",msg);
        exit(1);
    }
}

Помните, что TCP — это протокол потоковое. Передаваемые данные представляют собой просто поток байтов. Нет границ сообщения или разделителей. Поэтому часто может случиться так, что одно «сообщение», отправленное через сокет TCP, может быть не получено полностью на другом конце. Когда вы получаете из сокета, вы должны точно знать, сколько нужно получить, и делать это в цикле, пока не получите полное сообщение. Крайне маловероятно в вашем случае, когда вы передаете только int, но что-то нужно помнить для будущих программ.

Some programmer dude 17.05.2022 11:05

Это означает, что другая сторона закрыла сокет.

user253751 17.05.2022 11:06

Вы неправильно реагируете на конец потока в клиенте, поэтому продолжаете отправлять после того, как сервер отключился, поэтому, когда вы продолжаете отправлять, вы получаете сброс соединения. Решение: правильно реагировать на конец потока, закрывая сокет. Без сомнения, это то, что check() должен делать, но это не так.

user207421 17.05.2022 13:37
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
3
21
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

«Соединение, сброшенное узлом» — это именно то, на что это похоже: «Узел» (другая сторона соединения) закрыл соединение.

Обычно вы обнаруживаете это, проверяя, доступен ли сокет для чтения, и когда read (или recv) возвращает 0.

Если вы не обнаружите это таким образом и вместо этого попытаетесь записать в сокет, вы получите ту ошибку, которую вы получаете.

Если вы получите эту ошибку (или обнаружите закрытое соединение другим способом), вам следует закрыть конец соединения.


Конкретная проблема с вашим кодом заключается в том, что ваша функция check проверяет только ошибки, а не другие условия, которые могут применяться (например, закрытое соединение).

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

Другие вопросы по теме