您好我编写了一个服务器应用程序,它接受来自客户端的名称,该名称通常是文件名。它打开文件,将内容读入缓冲区,然后使用send()
通过以太网传输缓冲区。但问题出现在客户端,所有字节都没有成功接收。我只收到我发送的部分内容。
供您参考,这是服务器端的代码片段:
服务器:
fp = fopen(filename,"r+");
strcpy(str,"");
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
fread(str, size, 1,fp);
fclose(fp);
printf("Size of the file is : %d\n",size);
sprintf(filename, "%d", size);
n = send(nsd, filename, strlen(filename), 0);
while(size > 0){
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
}
请帮我编写客户端应用程序。我目前对如何编写它感到困惑。我将recv()
部分放在while(1)
循环中,以便客户端继续运行直到所有字节已成功收到?
答案 0 :(得分:3)
<强> EDITED 强>
对于初学者,您可以同时使用read from the file
和write to the socket
两个块
因为,您正在通过TCP传输数据,请记住数据是作为流而不是作为消息可靠地传输的。因此,不要假设除了订单之外如何收集数据。
以下是它的编写方式:
open socket
open file
size_of_file = read_file_size(file);
send(socket, &size_of_file, sizeof(int), ...)
while (all is written)
read fixed chunk from file
write as much was read to the socket
cleanup // close file, socket
至于recv
部分,我认为最好将文件大小作为整数发送并继续读取while循环,直到你从服务器发送了多少字节为止
就是这样:
recv(socket, &size_of_msg, sizeof(int), ...)
while(all is read)
read fixed chunk from the socket
cleanup
答案 1 :(得分:3)
嗯,我看到你在套接字上发送消息的方式至少存在一些问题。
首先来自fread的手册页:
The function fread() reads nmemb elements of data, each size bytes
long, from the stream pointed to by stream, storing them at the loca-
tion given by ptr.
你正在尝试的是:
fread(str, size, 1,fp);
我认为你的意思是
fread(str, 1,size,fp);
虽然它没有说明这个问题。
但问题在于:
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
虽然通过减少成功发送的字节数减少“大小”,但是在哪里扩展str指向要发送数据的新缓冲区位置。这只会重复重新发送缓冲区的初始字节。
str += n; //Assuming str is char*
将解决您的问题。
答案 2 :(得分:2)
“我应该将recv()部分放在while(1)循环中,以便客户端继续运行,直到所有字节都成功收到?”
这样的事情。永远不要假设recv()
调用得到了所有已发送的内容 - tcp / ip将消息分解为较低级别的数据包,并且recv()将在读取任何点上实际接收到的任何数据量后返回。您不必直接担心,除非您需要使用某种协议来指示消息的长度,以便接收方知道要读取多少内容,例如:。
char buffer[4096];
int msgsz = 600, // see below
sofar = 0,
cur;
while (sofar < msgsz) {
cur = recv (
socket_fd,
&buffer[sofar],
msgsz - sofar,
0
);
if (cur == -1) {
// error
break;
} else if (cur == 0) {
// disconnected
break;
}
sofar += cur;
}
WRT msgsz
,你可以将它包含在一个固定长度的标题中,首先读取。一个简单的版本可能只有4个字节,包含uint32_t
,即一个长度为int的字节。您还可以使用带有数字的空终止字符串,但这意味着在找到'\0'
之前读取。
答案 3 :(得分:2)
使用strlen
似乎不合适。您已经阅读了该文件,您知道它有多长,那么为什么strlen
?要么你得到相同的结果(所以它是多余的),否则你会得到别的东西(所以这是一个错误)。