любопытная вещь произошла в программировании сокетов Linux - PullRequest
0 голосов
/ 11 марта 2012

Я пытаюсь построить сервер, который может обслуживать множество клиентов.

Сервер просто выполняет простую работу: получает входную строку от клиента и затем меняет каждую букву на верхний регистр.

Но проблема в том, что, когда я пытаюсь завершить работу одного клиента, например, типа «Ctrl-C», моя ОС будет внезапно закрыта.

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

/* client.c */
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000

int main (void)
{
    struct  sockaddr_in servaddr, cliaddr;
    char    buf[MAXLINE];
    int sockfd, n;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (fgets(buf, MAXLINE, stdin) != NULL) {
        write(sockfd, buf, strlen(buf));
        n = read(sockfd, buf, MAXLINE);
        if(n == 0) printf("Connect closed\n");
        else write(STDOUT_FILENO, buf, n);
    }
    close(sockfd);
    return 0;
}

/* server */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAXLINE 80
#define SERV_PORT 8000

void sigchld_func (int signo) {
    wait(NULL);
}

int main (void)
{
    struct  sockaddr_in servaddr, cliaddr;
    char    buf[MAXLINE];
    char    str[INET_ADDRSTRLEN];
    int     listenfd, connfd;
    socklen_t   cliaddr_len;
    int     n, i;
    pid_t   pid;

    signal(SIGCHLD, sigchld_func);

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(listenfd, 20);

    printf("Accepting connections...\n");

    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
        if ((pid = fork()) < 0) {
            perror("fork error!");
            exit(1);
        } else if (pid > 0) {
            close(connfd);
        } else {
            close(listenfd);
            while (1) {
                n = read(connfd, buf, MAXLINE);
                if (n <= 0) {
                    printf("Connection closed\n");
                    break;
                }
                inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str));
                printf("Received from %s at port %d\n", str, ntohs(cliaddr.sin_port));
                for (i = 0; i < n; i++)
                    buf[i] = toupper(buf[i]);
                write(connfd, buf, n);
            }
            close(connfd);
        }
    }
    return 0;
}

1 Ответ

6 голосов
/ 11 марта 2012

Ваш серверный код вызывает «бомбу-вилку», и вы не видите его должным образом, потому что вы не проверяете возвращаемое значение accept.

Основная причина заключается в том, что в дочернем элементе, который читает/ пишет клиенту, после того, как соединение закрыто, вы не звоните exit или не возвращаетесь из основного.

Таким образом, дочерний процесс остается в цикле верхнего уровня while(1), пытается accept на listenfd (но вы закрыли ту, что хорошо).accept терпит неудачу, и вы в любом случае разветвляетесь.Плотные петли вилок замедляют работу вашего компьютера, планировщик не может правильно с ними справиться (если у вас нет контрмер).

Поэтому выйдите из программы после close(connfd) и добавьте ещепроверка ошибок в вашем коде.

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