如何使用socket apis发送和接收字节?

时间:2012-05-20 12:08:18

标签: c linux unix tcp network-programming

您好我编写了一个服务器应用程序,它接受来自客户端的名称,该名称通常是文件名。它打开文件,将内容读入缓冲区,然后使用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 个答案:

答案 0 :(得分:3)

<强> EDITED
对于初学者,您可以同时使用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

答案 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?要么你得到相同的结果(所以它是多余的),否则你会得到别的东西(所以这是一个错误)。