【问题标题】:How to send and receive bytes with socket apis?如何使用套接字 API 发送和接收字节?
【发布时间】:2012-05-27 05:53:59
【问题描述】:

您好,我编写了一个服务器应用程序,它接受来自客户端的名称,通常是文件名。它打开文件,将内容读入缓冲区,然后使用 send() 在以太网上传输缓冲区。但是问题出现在客户端,所有字节都没有成功接收。我只收到我发送的一部分。

供您参考,这里是服务器端的代码sn-p:

服务器

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) 循环中,以便客户端继续运行,直到所有字节都已完成收到成功了吗?

【问题讨论】:

  • 你用的是什么类型的socket?它是一个UDP套接字吗?如果是这种情况,您应该考虑丢包并重新传输...或者,您可以使用 TCP...
  • 这是我正在使用的 tcp 套接字 ...

标签: c linux unix tcp network-programming


【解决方案1】:

“我应该把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,您可以将其包含在固定长度的标头中,首先读取该标头。一个简单的版本可能只是包含uint32_t 的4 个字节,即一个具有长度的int。您也可以使用带有数字的空终止字符串,但这意味着读取直到找到'\0'

【讨论】:

    【解决方案2】:

    已编辑
    对于初学者,您可以同时分块使用 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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        好吧,我发现您通过套接字发送消息的方式至少存在一些问题。

        首先来自 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*
        

        将解决您的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-11
          • 2010-11-13
          • 1970-01-01
          • 2013-11-13
          • 1970-01-01
          • 2010-11-14
          • 2016-02-21
          • 2013-04-01
          相关资源
          最近更新 更多