Ошибка подключения TCP-сокетов на языке C

Я уже задавал вопрос об этой проблеме, но не нашел ответа, а также сообщение закрыто, и я не знаю, почему?? Тем не менее, я повторяю вопрос.

Я хочу соединить два TCP-сокета в простой архитектуре клиент-сервер и настраиваю две виртуальные машины для имитации двух машин, которые хотят взаимодействовать.

Вот клиентский код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>

int main(int argc, char ** argv) {
    //controllo che la porta venga indicata in riga di comando
    if (argc != 2) {
        printf("Usage: %s <port>", argv[0]);
        exit(0);
    }
    //variabili di controllo, socket e indirizzo
    int port = atoi(argv[1]);
    int sock;
    struct sockaddr_in addr;
    socklen_t addr_size;
    char buffer[1024];
    int n;
    //chiamata a socket e subito dopo controllo
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("[-] Error while creating socket.\n");
        exit(1);
    }

    printf("[+] TCP socket created. \n");
    memset(&addr, '\0', sizeof(addr));//setto i byte a 0
    //imposto gli attributi dell'indirizzo
    addr.sin_family = PF_INET;
    addr.sin_port = port;
    addr.sin_addr.s_addr = INADDR_ANY;
    //connetto la socket
    n = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
    if (n < 0) {
        printf("Error while connecting the socket...: %s\n", strerror(errno));
    printf("Errno value = %d", errno);
        exit(1);
    }
    printf("[+] Client connected.\n");

    bzero(buffer, 1024);// azzero i byte del buffer
    strcpy(buffer, "Hello World");
    printf("Client: %s\n", buffer);
    send(sock, buffer, strlen(buffer), 0); // mando il messaggio contenuto nel buffer

    bzero(buffer, 1024);
    recv(sock, buffer, sizeof(buffer), 0); //ricevo la risposta del server 
    printf("Server: %s\n", buffer);

    close(sock); // chiudo la connessione lato client
    printf("[+] Disconnected from the server");

    return 0;
} 

А вот код сервера:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(int argc, char** argv) {
    //controllo che da riga di comando venga inserita la porta a cui collegare la socket
    if (argc != 2) {
        printf("Usage: %s <port>", argv[0]);
        exit(0);
    }
    //creo tutte le variabili che mi serviranno 
    int port = atoi(argv[1]); //porta presa da riga di comando
    int server_sock, client_sock; //socket per server e client 
    struct sockaddr_in server_addr, client_addr; //struct per gestire gli indirizzi di server e client(IPv4, IPv6)
    socklen_t addr_size;    //lunghezza degli indirizzi
    char buffer[1024];  //buffer per il trasferimento dei messaggi
    int n;  //variabile di controllo

    //chiamata alla funzione socket che restituisce un valore int a server_sock
    server_sock = socket(AF_INET, SOCK_STREAM, 0); 
    //controllo che la chiamata socket() abbia restituito un valore > 0, quindi esito della chiamata positivo
    if (server_sock < 0) {
        perror("[-] Error while creating socket.\n");
        exit(1);
    }

    printf("[+] TCP socket created. \n");
    //setto i byte della memoria a 0
    memset(&server_addr, '\0', sizeof(server_addr));
    //assegno i vari attributi dell'indirizzo
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = port;
    server_addr.sin_addr.s_addr = INADDR_ANY;

    //chiamata alla funzione bind che associa la socket con la porta e ne metto il valore di ritorno in n 
    n = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    //controllo che la chiamata precedente sia andata bene quindi n > 0
    if (n < 0) {
        perror("[-] Error while binding the socket.\n");
        exit(1);
    }
    printf("[+] Socket binded to the port %d\n", port);

    //metto in ascolto il server
    int listenVar = 0;
    listenVar = listen(server_sock, 5);
    if (listenVar < 0) {
        perror("[-] Error while setup listening phase...\n");
        exit(1);
    }
    printf("[+] Listening...\n");

    //ciclo su i client che si collegano al server
    while(1) {
        
        addr_size = sizeof(client_addr); // size dell'indirizzo del client
        //chiamata alla funzione accept, che restituisce un valore int 
        client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addr_size);
        if (client_sock < 0) {
            perror("[-]Error while accepting the connection");
            exit(1);
        }
        char ipString[40]; // stringa per salvare l'ip del client che si è collegato al server
        inet_ntop(AF_INET, &client_addr, ipString, sizeof(client_addr)); //converto l'ip in un formato di testo
        printf("[+] Client connected.\n Client IP:%s\n", ipString); //stampo l'indirizzo che si è collegato al server

        bzero(buffer, 1024); //azzero i byte del buffer
        recv(client_sock, buffer, sizeof(buffer), 0); //ricevo il messaggio dal client
        printf("Client: %s\n", buffer); // stampo il messaggio salvato in buffer

        bzero(buffer,1024); //riazzero il buffer 
        strcpy(buffer, "Hi from the server"); // passo una stringa nel buffer
        printf("Server: %s\n", buffer); 
        send(client_sock, buffer, strlen(buffer), 0); // mando il messaggio del buffer al client

        close(client_sock); //chiudo la connessione 
        printf("[+] Client disconnected.\n");
    }

    return 0;
}

У меня проблема с управлением функцией и возвращаемое значение errno 111, или соединение отказано, но я не понимаю почему. Я думаю, что проблем с настройкой соединения нет, потому что если я выполню команду nc на машинах, они оба без проблем будут общаться.

addr.sin_port = port; должно быть addr.sin_port = htons(port);
Barmar 13.04.2024 20:23

Второй printf() может не отображать правильное значение errno, поскольку его может изменить первый printf(). Вам нужно сохранить его в другой переменной или сделать одну printf().

Barmar 13.04.2024 20:25

Помимо отмеченного выше htons(port), в клиентской части этого кода нет адреса для подключения (и из-за этого возникает сообщение «отказано в соединении», если только это не локальное соединение). Тогда есть неправильная структура для получения адреса клиента перед печатью (должно быть .sin_addr) с помощью inet_ntop(). Может быть, еще какие-то такие маленькие ошибки. (В целом этот код выглядит как смесь стилей BSD и Linux, судя по используемым функциям/констам)

yvs2014 13.04.2024 21:03

@NinoQuindici_Git «Я уже задавал вопрос об этой проблеме, но не нашел ответа, а также сообщение закрыто, и я не знаю почему?? Однако я повторно публикую вопрос». - Я не вижу более раннего сообщения от вас. Но если бы он был и его закрыли, правильным действием было бы исправить любую проблему, из-за которой он закрылся, чтобы его можно было снова открыть. Просто сделайте репост того же вопроса еще раз.

Remy Lebeau 13.04.2024 22:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

На стороне клиента INADDR_ANY (0.0.0.0) не является действительным IP-адресом для connect(). На стороне сервера вы можете bind() использовать серверный сокет, чтобы INADDR_ANY прослушивать все локальные сетевые интерфейсы.

При звонке connect() вам необходимо указать реальный IP-адрес сервера. Поскольку ваш клиент и сервер работают на разных виртуальных машинах, серверной виртуальной машине должен быть присвоен общедоступный IP-адрес, доступный с клиентской виртуальной машины.

Кроме того, вам необходимо использовать htons() при присвоении значения полю sinaddr_in::sin_port.

Привет, спасибо всем. Я изменил INADDR_ANY в привязке на стороне клиента, затем изменил addr.sin_port = port на htons(port) (я не заметил этой ошибки до вашего комментария, поэтому не смог найти эту ошибку сам), и теперь все работает правильно! Большое спасибо!

NinoQuindici_Git 14.04.2024 16:09

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