0

嗨,我编写了一个服务器应用程序,它接受来自客户端的名称,通常是文件名。它打开文件,将内容读入缓冲区,然后使用以太网通过以太网传输缓冲区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)循环中,以便客户端继续运行,直到成功接收到所有字节?

4

4 回答 4

3

已编辑
对于初学者,您可以同时read from the filewrite 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
于 2012-05-20T12:42:17.180 回答
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*

将解决您的问题。

于 2012-05-20T13:07:15.713 回答
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 个字节,其中包含 a uint32_t,即带有长度的 int 。您也可以使用带有数字的空终止字符串,但这意味着读取直到'\0'找到。

于 2012-05-20T12:41:43.153 回答
2

使用strlen似乎不合适。您已经阅读了该文件,您知道它有多长,那为什么要这样做strlen呢?要么你得到相同的结果(所以它是多余的),要么你会得到别的东西(所以这是一个错误)。

于 2012-05-20T12:44:24.807 回答