Ошибки форматирования при передаче файлов через несколько клиентов с использованием сокетов в C - PullRequest
0 голосов
/ 03 апреля 2012

Я пытаюсь реализовать простой тестер кода: очень простую версию ACM ICPC или онлайн-судьи Google Code Jam.

Оценочная часть работает (пока), но я застрял в глупостичасть передачи файла.

В основном мои настройки таковы:

У меня есть сервер (всегда включен) и несколько клиентских систем, принадлежащих командам, которые отправят свой код.Они могут передавать файлы друг другу в команде, но сервер будет вести журнал передач.Сервер иногда может отправлять объявления всем или определенным клиентам.Окончательный код будет передан на конкретную пустую клиентскую машину для оценки.

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

select(fdmax+1, &read_fds, NULL, NULL, NULL)

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

Для получения данных на сервер я использую следующую функцию:

void send_recv(int i, fd_set *master, int sockfd, int fdmax)
{
    int nbytes_recvd, j;
    char recv_buf[BUFSIZE], buf[BUFSIZE];

    if ((nbytes_recvd = recv(i, recv_buf, BUFSIZE, 0)) <= 0) {
        if (nbytes_recvd == 0) {
            printf("socket %d hung up\n", i);
        }else {
            perror("recv");
        }
        close(i);
        FD_CLR(i, master);
    }else {
        FILE *logger;
        logger = fopen(fname2, "w");
        fprintf(logger,"Client %i> %s", i,recv_buf);
        for(j = 0; j <= fdmax; j++){
            send_to_all(j, i, sockfd, nbytes_recvd, recv_buf, master );
        }
    }
}

Здесь, вместо того, чтобы регистрировать все данные файла, передаваемые по потоку отдельно, я получаю беспорядокэто трудно разобрать.

Эта функция фактически передает файлы (все ANSI * .c):

void send_to_all(int j, int i, int sockfd, int nbytes_recvd, char *recv_buf, fd_set *master)
{
    if (FD_ISSET(j, master)){
        if (j != sockfd && j != i) {    //prevents data rewrite to incoming host
            int client;
            sscanf(recv_buf, "%d >", &client);
            if(client == 0){                //universal send
                if (send(j, recv_buf, nbytes_recvd, 0) == -1) {
                    perror("send");
                }
            }                               //send to specified host
            else if (send(client, recv_buf, nbytes_recvd, 0) == -1) {
                perror("send");
            }
        }
    }
}

Здесь входящие файлы теряют все свое форматирование и печатаются дважды каждый раз.

Урезанная версия кода моего сервера находится здесь: http://codepad.org/TTejTfbL

Мой вопрос: я делаю что-то в корне неправильно?Неужели моя логика (и, соответственно, мой код) безвозвратно нарушена?

Я был бы рад, если бы кто-то мог указать мне правильное направление.Или даже сказать мне, чтобы выбросить все это и начать с нуля.(^; __; ^)

1 Ответ

1 голос
/ 03 апреля 2012

Вы не можете предполагать, что вы можете send() любой объем данных за один вызов, и монотлически он может быть успешным или неудачным.Существуют ограничения для буферов, реализованных библиотекой.

Вы можете передать, например, 20 КБ send() и успешно вернуть его после отправки только 4711 байт.Это потребует от вас перехода на нужный уровень в буфере, уменьшения количества байтов и повторной попытки.

Это необходимо зациклить, пока вы не отправите все свои данные или не получитеОшибка ввода / вывода из сокета.

...