我正在尝试实现一个简单的代码测试器: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
我的问题是,我是否做了一些根本错误的事情?我的逻辑(以及我的代码)是否已经无法挽回地损坏了?
如果有人能指出我正确的方向,我会很高兴。 或者甚至告诉我把一切都扔掉,从头开始。 (^;__;^)
最佳答案
您不能假设您可以在一次调用中 send()
任意数量的数据,并使其整体成功或失败。库实现的缓冲区存在限制。
您完全有可能通过,例如20 KB 到 send()
,并在仅发送 4,711 字节后成功返回。这需要您在缓冲区中前进适当的量,减少“剩余字节数”,然后重试。
这需要循环,直到您发送完所有数据,或从套接字接收到 I/O 错误。
关于c - 使用 C 中的套接字通过多个客户端传输文件时出现格式错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9995431/