Может связаться с моим сервером через telnet, но не через мой клиент - PullRequest
0 голосов
/ 30 января 2019

В настоящее время я пишу небольшое приложение чата на C для обучения сети.Я разрабатываю с использованием протокола управления передачей с сокетом в C. Я смог подключиться к своему серверу с клиентом, который не был закодирован мной (в локальной сети).Теперь Telnet успешно подключается к моему серверу чата (то есть с сервером и клиентом Telnet на одном компьютере), и я могу отправлять и получать сообщения, НО мой очень простой клиент не может подключиться к нему.С самого начала я использую порт 9002 и сейчас пытаюсь подключиться с IPv6-адресом :: 1.Вот код «принимающего клиента» моего сервера:

int main(void)
   {
    //Create the socket
    int sock = socket(AF_INET6, SOCK_STREAM, 0);

    printf("Socket créer\n");

    //Set up the socket interface
    struct sockaddr_in6 sin6 = { 0 };
    sin6.sin6_family = AF_INET6;
    sin6.sin6_port = htons(PORT);
    sin6.sin6_addr = in6addr_any; 

    //Bind the socket on the port
    if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
    {
        perror("bind()");
        errx(EXIT_FAILURE, "Fail to bind");
    }

    //Make the sockey listen the port
    if(listen(sock, MAX_CLIENT) == SO_ERROR)
    {
        perror("listen()");
        errx(EXIT_FAILURE, "Fail to listen");
    }

    printf("Socket listening\n");

    int csock;
    size_t clientID = 0;
    --snip--

    while(1)
    {
        struct sockaddr_in6 csin6;
        memset(&csin6, 0, sizeof(struct sockaddr_in6));
        int sin6size = sizeof(struct sockaddr_in6);

        //Accept a communication
        printf("Wait for communication\n");
        csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
        printf("Connection accepted\n");
        char msg[16];
        sprintf(msg, "CONNECTED - %zu\n", clientID);
        send(csock, msg, sizeof(msg), 0);
        printf("Client %zu connected\n", clientID);

        //Handle client
       --snip--
    }

Так что это базовое соединение с сокетом с использованием подключенного соединения.Сервер обрабатывает несколько клиентов в цикле while благодаря многопоточности.
Вот код клиента:

void *sender(void *arg)
{
    int socket = (int)(long)arg;
    char buffer[BUFF_SIZE];
    while(1)
    {
        scanf("%s", buffer);
        send(socket, buffer, strlen(buffer), 0);
        bzero(buffer, BUFF_SIZE);
    }
}
int main(int argc, char *argv[])
{
    if(argc < 2)
        errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");

    //Create the socket
    int sock = socket(AF_INET6, SOCK_STREAM, 0);
    struct hostent *hostinfo = NULL;
    hostinfo = gethostbyname2(argv[1], AF_INET6);
    if(hostinfo == NULL)
        errx(EXIT_FAILURE, "Can't connect to the server\n");

    //Set up the socket interface
    struct sockaddr_in6 sin6 = { 0 };
    sin6.sin6_family = AF_INET6;
    sin6.sin6_port = htons(PORT);
    sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr; 

    if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
    {
        perror("connect()");
        errx(EXIT_FAILURE, "Fail to connect");
    }
    printf("Connection established\n");

    pthread_t sending;
    if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
        printf("Fail to create a thread\n");

    //Handle reception
    char buffer[BUFF_SIZE];
    int n;
    while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
    {
        buffer[n] = '\0';
        printf("%s", buffer);
    }

    printf("Erreur: %d\nConnection broken\n", n);
    pthread_cancel(sending);
    close(sock);
    return EXIT_SUCCESS;
}

Итак, я запускаю клиента с:

~ ./client ::1

Выводвыглядит следующим образом:

Connection established
Error: -1
Connection broken

Пока сервер все еще «ожидает связи».Это означает, что сервер не принимает соединение, но клиент успешно подключается.

Спасибо за помощь.

1 Ответ

0 голосов
/ 30 января 2019

Это, вероятно, уже connect(), который здесь не срабатывает:

if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)

SO_ERROR не предназначен для использования здесь, но как опция сокета при получении ошибки при сбое асинхронного соединения,A (синхронно) connect() возвращает -1 в случае ошибки и устанавливает errno, поэтому

if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {

...

Позже, recv здесь:

while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)

завершается неудачно с ошибкой ENOTCONN, так как соединение не было установлено заранее.

Одна и та же ошибка SO_ERROR присутствует в различных местах кода вашего сервера;возможно, что уже bind() там терпит неудачу!После этого вызов listen() будет автоматически привязан к свободному эфемерному порту, поэтому вызов, как и вызов accept(), будет успешным.

Почему вызов bind() может быть неудачным?Возможно, вам придется установить опцию сокета SO_REUSEADDR при (пере) запуске сервера, иначе он может отказаться от использования недавно привязанного порта, если соединения все еще находятся в состоянии TIME_WAIT.Поместите это непосредственно перед bind() звонком:

int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

Это может помочь.

...