【问题标题】:Formatting errors while transferring files over multiple clients using Sockets in C使用 C 中的套接字通过多个客户端传输文件时出现格式错误
【发布时间】:2012-04-04 15:55:47
【问题描述】:

我正在尝试实现一个简单的代码测试器: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

我的问题是,我做错了什么?我的逻辑(以及我的代码)是否已无法挽回?

如果有人能指出我正确的方向,我会很高兴。 或者甚至告诉我把它全部扔掉,从头开始。 (^;__;^)

【问题讨论】:

    标签: c sockets file-transfer


    【解决方案1】:

    您不能假设您可以在一次调用中send() 任意数量的数据,并使其整体成功或失败。库实现的缓冲区有限制。

    你完全有可能通过例如20 KB 到send(),仅发送 4,711 字节后成功返回。这将要求您在缓冲区中前进适当的数量,减少“要走的字节数”,然后重试。

    这需要循环,直到您发送完所有数据,或从套接字接收到 I/O 错误。

    【讨论】:

    • 我想明白你在告诉我什么 - 但我认为我已经涵盖了。我的Client Code(精简版)循环发送数据:第 79 到 84 行。这还会溢出吗?而且,当 send() 失败时,我确实得到了一个 -1 返回。我还应该在哪里检查 I/O 错误?
    • 我的意思是,我应该使用像 wireshark 这样的东西来嗅探 I/O 错误,还是应该进行运行时检查?
    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 2014-06-10
    • 2018-04-19
    • 1970-01-01
    • 2014-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多