IRC-сервер segfault, когда клиенты отправляют более 10 сообщений - PullRequest
0 голосов
/ 19 января 2019

Когда клиент отправляет более 10 сообщений, сервер segfault, но сервер не имеет этой проблемы.он может отправлять неограниченное количество сообщений.

это, вероятно, вызвано моим буфером char * malloc () и, возможно, плохо free () ???Я пытаюсь использовать статический буфер массива без free (), очевидно, но это хуже.

Клиент

#include "header.h"

void    app(SOCKET socket)
{
    char pseudo[24];
    int statu;
    fd_set readfs;

    strcpy(pseudo, "[");
    strcat(pseudo, getname(sizeof(pseudo)));
    strcat(pseudo, "] ");

    while (1)
    {
        char *buffer = malloc(sizeof(char) * 1024);
        char *msg = malloc(sizeof(char) * 1000);

        FD_ZERO(&readfs);
        FD_SET(socket, &readfs);
        FD_SET(STDIN_FILENO, &readfs);

        if (select(socket + 1, &readfs, NULL, NULL, NULL) == -1)
        {
            perror("select()");
            exit(errno);
        }
        if (FD_ISSET(STDIN_FILENO, &readfs))
        {
            fgets(msg, sizeof(char) * 1000, stdin);
            strcpy(buffer, pseudo);
            strcat(buffer, msg);
            send_message(socket, buffer);
            cleanMsg(buffer, msg);
        }
        else if (FD_ISSET(socket, &readfs))
        {
            statu = receive_message(socket, buffer);
            if (statu == 0)
            {
                printf("Server disconnected !\n");
                break;
            }
            else
            {
                printf("%s\n", buffer);
                cleanMsg(buffer, msg);
            }
        }
    }
    close_connection(socket);
}

void    send_message(SOCKET socket, char *buffer)
{   
    int i;

    for (i = 0; buffer[i] != '\n'; i++) ;
    buffer[i] = '\0';

    if (send(socket, buffer, strlen(buffer), 0) < 0)
    {
        perror("send()");
        exit(errno);
    }
}

int receive_message(SOCKET socket, char *buffer)
{
    int statu = 0;
    if ((statu = recv(socket, buffer, 1024, 0)) < 0)
        perror("recv()");
    return statu;
}

void    cleanMsg(char *buffer, char *msg)
{
    memset(buffer, 0, strlen(buffer));
    memset(msg, 0, strlen(msg));
    free(buffer);
    free(msg);
}

char    *getname(size_t namesize)
{
    char *tmp = NULL;

    tmp = malloc(namesize);
    getlogin_r(tmp, namesize);

    return tmp;
}

Сервер:

#include "header.h"

int app(SOCKET master_socket, serv_config *s_conf)
{
    SOCKADDR_IN client_address = {0};
    SOCKET new_socket;
    int address_size = sizeof(client_address);
    int *clients_socket = NULL;
    int statu = 0;
    int fdmax;
    int sd;
    int i;

    clients_socket = malloc(sizeof(int) * s_conf->max_client);

    fd_set readfs;

    for (i = 0; i < s_conf->max_client; i++)
        clients_socket[i] = 0;

    while (1)
    {

        char *buffer = malloc(sizeof(char) * 1024);
        char *msg = malloc(sizeof(char) * 1000);

        FD_ZERO(&readfs);
        FD_SET(STDIN_FILENO, &readfs);
        FD_SET(master_socket, &readfs);

        fdmax = master_socket;

        for (i = 0; i < s_conf->max_client; i++)
        {
            sd = clients_socket[i];
            if (sd > 0)
                FD_SET(sd, &readfs);
            if (sd > fdmax)
                fdmax = sd;
        }

        if (select(fdmax + 1, &readfs, NULL, NULL, NULL) == -1)
        {
            perror("select()");
            exit(errno);
        }

        if (FD_ISSET(STDIN_FILENO, &readfs))
        {
            fgets(msg, sizeof(char) * 1000, stdin);
            strcpy(buffer, "[Server] ");
            strcat(buffer, msg);
            send_toall(clients_socket, 0, s_conf->max_client, buffer);
            cleanMsg(buffer, msg);
        }
        else if (FD_ISSET(master_socket, &readfs))
        {
            new_socket = accept(master_socket, (SOCKADDR *)&client_address, &address_size);

            if (new_socket == INVALID_SOCKET)
            {
                perror("accept()");
                closesocket(new_socket);
                exit(errno);
            }

            for (i = 0; i < s_conf->max_client; i++)
            {
                if (clients_socket[s_conf->max_client - 1] != 0)
                {
                    strcpy(buffer, "Connection error: no more client can be connected.\n");
                    send_message(new_socket, buffer);
                    cleanMsg(buffer, msg);
                    shutdown(new_socket, 2);
                    closesocket(new_socket);
                    break;
                }
                else if (clients_socket[i] == 0)
                {
                    clients_socket[i] = new_socket;
                    printf("New client connected with socket %d from %s:%d, in slot %d\n", clients_socket[i], inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port), i);
                    strcpy(buffer, "Success connecting.\n");
                    send_message(clients_socket[i], buffer);
                    cleanMsg(buffer, msg);
                    break;
                }
            }
        }
        else
        {
            for (i = 0; i < s_conf->max_client; i++)
            {
                if (FD_ISSET(clients_socket[i], &readfs))
                {
                    statu = receive_message(clients_socket[i], buffer);
                    if (statu == 0)
                    {
                        printf("Socket %d Disconnect\n", clients_socket[i]);
                        shutdown(clients_socket[i], 2);
                        closesocket(clients_socket[i]);
                        clients_socket[i] = 0;
                        break;
                    }
                    else
                    {
                        send_toall(clients_socket, clients_socket[i], s_conf->max_client, buffer);
                        cleanMsg(buffer, msg);
                        break;
                    }
                }
            }
        }
    }
    return *clients_socket;
}

void    send_toall(int *clients_socket, int actual_socket, int max, char *buffer)
{
    int i;

    for (i = 0; clients_socket[i] < max; i++)
    {
        if (clients_socket[i] != actual_socket && clients_socket[i] != 0)
            send_message(clients_socket[i], buffer);
    }
}

void    send_message(SOCKET socket, char *buffer)
{
    int i;

    for (i = 0; buffer[i] != '\n'; i++) ;
    buffer[i] = '\0';

    if (send(socket, buffer, strlen(buffer), 0) < 0)
    {
        perror("send()");
        exit(errno);
    }
}

int receive_message(SOCKET socket, char *buffer)
{
    int statu = 0;
    if ((statu = recv(socket, buffer, 1024, 0)) < 0)
        perror("recv()");
    return statu;
}

void cleanMsg(char *buffer, char *msg)
{
    memset(buffer, 0, strlen(buffer));
    memset(msg, 0, strlen(msg));
    free(buffer);
    free(msg);
}

Сервер просто segfault и выйти послеклиент отправляет более 10 сообщений.

Ответы [ 2 ]

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

проблема решена, просто замените это:

    for (i = 0; buffer[i] != '\n'; i++) ;
    buffer[i] = '\0';

на это:

    for (i = 0; buffer[i] != '\n' && buffer[i] != '\0'; i++) ;
    buffer[i] = '\0';
0 голосов
/ 19 января 2019

У вас есть серьезные проблемы с тем, как вы отправляете и получаете сообщения.

Во-первых, вы полностью игнорируете тот факт, что TCP-соединения представляют собой потоки без понятия границ сообщения.Если вы делаете два вызова на send() с каждой отправкой 10 байтов, одноранговый узел может recv() получить от 1 до 20 байтов в любой комбинации нескольких вызовов recv(), пока не будут получены все 20 байтов. Вы должны выяснить, как разделить их на два исходных сообщения.

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

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