Программирование сокетов на C: при выходе из сервера клиента происходит сбой сервера - PullRequest
0 голосов
/ 01 ноября 2018

Я запускаю программный код сокета для связи нескольких клиентов с одним сервером. Все происходит правильно, но когда я нажимаю Ctrl C, чтобы выйти из одного из клиентов, сервер не показывает, как я ожидал. Ниже приведен код:

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 4444

int main(){

    int clientSocket, ret;
    struct sockaddr_in serverAddr;
    char buffer[1024];

    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0){
        printf("[-]Error in connection.\n");
        exit(1);
     }
     printf("[+]Client Socket is created.\n");

     memset(&serverAddr, '\0', sizeof(serverAddr));
     serverAddr.sin_family = AF_INET;
     serverAddr.sin_port = htons(PORT);
     serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
         printf("[-]Error in connection.\n");
         exit(1);
     }
     printf("[+]Connected to Server.\n");

     while(1){
        printf("Client: \t");
        scanf("%s", &buffer[0]);
        send(clientSocket, buffer, strlen(buffer), 0);

        if(strcmp(buffer, ":exit") == 0){
            close(clientSocket);
            printf("[-]Disconnected from server.\n");
            exit(1);
        }

        if(recv(clientSocket, buffer, 1024, 0) < 0){
            printf("[-]Error in receiving data.\n");
        }else{
            printf("Server: \t%s\n", buffer);
        }
    }

    return 0;
}

Server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 4444

int main(){

    int sockfd, ret;
    struct sockaddr_in serverAddr;

    int newSocket;
    struct sockaddr_in newAddr;

    socklen_t addr_size;

    char buffer[1024];
    pid_t childpid;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("[-]Error in connection.\n");
        exit(1);
    }
    printf("[+]Server Socket is created.\n");

    memset(&serverAddr, '\0', sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("[-]Error in binding.\n");
        exit(1);
    }
    printf("[+]Bind to port %d\n", 4444);

    if(listen(sockfd, 10) == 0){
        printf("[+]Listening....\n");
    }else{
        printf("[-]Error in binding.\n");
    }


    while(1){
        newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
        if(newSocket < 0){
            exit(1);
        }
        printf("Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));

        if((childpid = fork()) == 0){
            close(sockfd);

            while(1){
                recv(newSocket, buffer, 1024, 0);
                if(strcmp(buffer, ":exit") == 0){
                    printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
                    break;
                }else{
                    printf("Client: %s\n", buffer);
                    send(newSocket, buffer, strlen(buffer), 0);
                    bzero(buffer, sizeof(buffer));
                }
            }
        }

     }

    close(newSocket);


    return 0;
}

Когда я нажимаю Ctrl C, чтобы выйти из клиента. На стороне сервера это показывает:

Client:
Client:
Client:
Client:

и кажется, что он зацикливается на "Клиент:" навсегда, вместо того, чтобы показывать сообщение printf "Отключено от ...", и продолжает работать с другими клиентами, как я ожидал. Я смотрю на этот код на YouTube, они могут правильно запустить его в видео, но я не знаю, почему, когда я загружаю этот код и запускаю на своем компьютере, возникает эта проблема. Может кто-нибудь помочь мне решить эту проблему, чтобы сервер мог напечатать сообщение «Отключение ...». Спасибо.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Когда я нажимаю Ctrl C, чтобы выйти из клиента. На стороне сервера это показывает:

Client:
Client:
Client:
Client:

и кажется, что цикл "Клиент:" навсегда вместо того, чтобы показывать сообщение printf "Отключен от ..." и продолжаю работать с другими клиентами как я и ожидал.

Ваш код печатает сообщение об отключении и выходит из цикла только в том случае, если он получает сообщение ": exit" от клиента. Если вы убьете клиента с помощью Ctrl-C, он прекратит работу, не отправив такого сообщения.

Надежный код сервера будет проверять возвращаемое значение вызова recv(), который будет возвращать -1, чтобы сигнализировать об ошибке. Ваш сервер игнорирует это и просто пытается прочитать снова, и снова, и снова. Хотя вы не можете рассчитывать на получение ошибки в каждом сценарии, когда клиент уходит, тот факт, что ваш сервер продолжает печатать «Клиент:», указывает на то, что вы получаете его в этом случае.

Я смотрю на этот код на YouTube, они могут правильно запустить его в видео, но я не знаю, почему, когда я загружаю этот код и запускаю на моем компьютер, он получает эту проблему.

Либо то, что они продемонстрировали в видео, отличалось от кода, который вы представили (возможно, видео было обманчиво), либо они вышли из клиента, набрав команду ": exit", а не просто убив его.

0 голосов
/ 01 ноября 2018

Похоже, ваш клиент неправильно закрывает соединение. Если вы используете Ctrl C для остановки клиента, то вы убиваете клиентскую программу и не прерываете цикл. Если вы хотите таким образом остановить клиент, вам нужно обработать SIGINT и закрыть соединение с сокетом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...