我编写程序,它工作正常,但我想用sendfile()重写它,现在我陷入了循环。
服务器端:
客户方:
P.S在以前版本的程序中,我停留了一段时间,但这取决于我使用printf的原因有多少?对于e.x我添加一行printf程序卡住,删除它,工作正常。
UPDT :重写代码客户端/服务器
客户端
/* Received file name */
int rc_byte = 0;
rc_byte = recv(fd, rx_tx_file->out_name, sizeof(rx_tx_file->out_name),0);
if (rc_byte < 0){
perror("Failed to receive file name: ");
exit(-1);
} else
printf("Recv out name %s\n", rx_tx_file->out_name);
//printf("file name rc %s\n", rx_tx_file->out_name);
trimm_path_name(rx_tx_file);
/* Received md5sum */
rc_byte = recv(fd, rx_tx_file->md5sum, sizeof(rx_tx_file->md5sum), 0);
if (rc_byte < 0) {
perror("Failed to receive check sum: ");
exit(-1);
} else
printf("recv md5s %s\n", rx_tx_file->md5sum);
/* Received file size */
rc_byte = recv(fd, &size, sizeof(size), 0);
if(rc_byte < 0) {
perror("Recevid size of file: ");
exit(-1);
}
printf("%d recv size\n", size);
to_read = size;
if (stat(dir, &st) == -1){
mkdir(dir, 0777);
}
send_data :(将func添加到服务器)
void send_data(int client_fd, m_file *rx_tx_file, int option, int size) {
int send_byte = 0;
int total_send = 0;
if (option == SEND_NAME) {
while (total_send < strlen(rx_tx_file->in_name)) {
send_byte = send(client_fd, rx_tx_file->in_name, sizeof(rx_tx_file->in_name),0);
if(send_byte == -1) {
perror("Failed to send file name to client: ");
exit(SEND_TO_CLIENT_ERROR);
}
total_send += send_byte;
}
}
else if (option == SEND_MD5) {
total_send = 0;
send_byte = 0;
while (total_send < strlen(rx_tx_file->md5sum)) {
send_byte = send(client_fd, rx_tx_file->md5sum, sizeof(rx_tx_file->md5sum),0);
if(send_byte == -1){
perror("Failed to send file md5sum to client: ");
exit(-1);
}
total_send += send_byte;
}
}
else if (option == SEND_SIZE) {
send_byte = send(client_fd, &size, sizeof(size),0);
if (send_byte == -1) {
perror("Failed to send size: ");
}
}
}
服务器:
client_fd = accept(server_fd, (struct sockaddr*) &client_addr, &length)
/*send name of file*/
send_data(client_fd, rx_tx_file, SEND_NAME, 0);
/*send md5 sum*/
take_check_sum(rx_tx_file,rx_tx_file->file_in, 0);
send_data(client_fd, rx_tx_file, SEND_MD5, 0);
/*send size of file*/
size = stats.st_size;
send_data(client_fd, rx_tx_file, SEND_SIZE, size);
remain_data = stats.st_size;
printf("File [%s] ready to send\ncheck sum [%s]\n", rx_tx_file->in_name,rx_tx_file->md5sum);
while (((send_byte = sendfile(client_fd, file_fd, &offset, size)) > 0) && (remain_data > 0))
{
remain_data -= send_byte;
printf("remain %d", remain_data);
}
printf("Succesfully");
因为我使用一个客户端并传递应该通过命令行args在服务器端发送的文件,所以我不需要等待(client_fd = accpet)我只使用一个连接并关闭服务器。现在它的工作很好。但是有一个问题是开放的,我应该如何重写客户端以循环收集数据。我不知道我应该回收哪个尺寸,因为我无法在我的while循环中写出正确的条件。 THX都是为了帮助。
答案 0 :(得分:4)
TCP是流。它没有消息边界。因此,您的代码将无效。
首先,您发送文件的名称:
send(client_fd, rx_tx_file->in_name, strlen(rx_tx_file->in_name)+1,0)
然后你立即发送md5总和,然后发送文件大小:
send(client_fd, rx_tx_file->md5sum, strlen(rx_tx_file->md5sum)+1, 0)
send(client_fd, &size, sizeof(int),0)
由于前两个字符串没有固定的字节数,因此当您尝试从服务器读取文件大小或md5总和时,您很可能还会读取文件的大小,甚至可能是档案数据。
首先,停止尝试将尽可能多的发送和读取代码放入if
和while
语句的条件子句中。
究竟是什么
if (send(client_fd, rx_tx_file->md5sum, strlen(rx_tx_file->md5sum)+1, 0) == -1) {
perror("Failed to send file md5sum to client: ");
exit(-1);
}
让你超过
ssize_t bytes_sent = send(client_fd, rx_tx_file->md5sum, strlen(rx_tx_file->md5sum)+1, 0);
if ( bytes_sent < 0 )
{
perror("Failed to send file md5sum to client: ");
exit(-1);
}
将所有代码放入if
子句中,就不会在发送中获得任何内容。如果strlen(rx_tx_file->md5sum)+1
为87
且send()
来电返回15
,会怎样?这是您的代码无法处理的可能返回值,因为它将所有内容都填充到if
子句中。
ssize_t bytes_sent = send(client_fd, rx_tx_file->md5sum, strlen(rx_tx_file->md5sum)+1, 0);
if ( bytes_sent < 0 )
{
perror("Failed to send file md5sum to client: ");
exit(-1);
}
else if ( bytes_sent < strlen(rx_tx_file->md5sum)+1 )
{
// partial send...
}
这实际上更好地编码为循环。
你没有发布你的接收代码,但是如果它是相同的样式你不仅没有获得任何东西,通过将所有内容放入if
条款,你再次无法做任何体面的错误检测或校正。
如果您的文件名recv
代码类似于
char filename[1024];
if (recv(fd, &filename, sizeof(filename), 0) < 0) {
perror("Failed to read file name: ");
exit(-1);
}
你不能告诉你刚收到什么。你刚收到多少字节?您可能已收到文件名。您可能只收到了文件名的部分。您可能已收到文件名,md5总和以及一些文件内容本身。
你不知道你收到了什么,而你的代码却无法分辨。如果将文件名和md5接收缓冲区清零且仅recv
最多比缓冲区大小小一个字节,则至少应避免未定义的行为。但是如果你没有将缓冲区归零,或者你读取了缓冲区的最后一个字节,那么你也可以在没有以文件结尾的字符串或md5总和的情况下结束。然后,当您尝试将其视为以空字符结尾的字符串时,您会得到未定义的行为。
如果你在尝试读取文件数据之前在recv
调用中获得了额外的字节,这就解释了为什么你的代码被卡住了 - 它在进入循环之前已经读取了一些文件内容,所以循环永远不会看到所有内容 - 其中一些内容已经消失。
答案 1 :(得分:2)
您应该避免在服务器中使用strlen:
if(send(client_fd, rx_tx_file->in_name, strlen(rx_tx_file->in_name)+1,0) == -1)
而是按照您在客户端中的预期发送大小为sizeof(rx_tx_file->out_name)
的固定长度字符串
如果文件名较小,只需用空格填充它,使其长度为sizeof(rx_tx_file->out_name)
你还应该在while循环中放入每个接收调用,并添加它实际收到预期字节数的检查,有时recv
只返回部分数据,你需要发布另一个recv
到接收其余的预期数据