2017-06-02 282 views
0

我想实现一个程序,将任何文件从服务器传输到客户端。我必须使用读/写功能读取和写入数据(用于学校作业)。这里是服务器和客户端的代码。通过套接字传输文件c

server.c

char buffer[512];   

    if((file = open(strTable[1], O_RDONLY)) == -1) { perror("Open"); } 

    while(read(file, buffer, sizeof(buffer)) != 0) 
    { 
     size = strlen(buffer)+1; 
     if(write(newsock, &size, sizeof(size)) < 0) { perror("Write"); exit(1); } 

     write_all(newsock, buffer, strlen(buffer)+1); 
    } 

    size = 4; 
    if(write(newsock, &size, sizeof(size)) < 0) { perror("Write"); exit(1); } 
    write_all(newsock, "end", 4); 

它打开strTable [1](其中包含我想读取文件),它读取的sizeof(缓冲区)字节,然后我发送给客户多少字节我将写入套接字,然后我发送字节。这里是write_all函数。

int write_all(int sock, char* buffer, int size) 
{ 
    int nwrite, sent = 0; 

    while(sent < size) 
    { 
     if((nwrite = write(sock, buffer + sent, size - sent)) < 0) 
     { perror("Write"); exit(1); } 

     sent += nwrite; 
    } 

    return sent; 
} 

client.c

if((file = open(absolute, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 
       { perror("Open"); }  

while(true) 
     { 
      received = 0; 

      /* Read the desired readable size */ 
      if(read(sock, &size, sizeof(size)) < 0) 
      { perror("Read"); pthread_exit(NULL); } 

      /* Read all data */ 
      while(received < size) 
      { 
       if((nread = read(sock, buffer + received, size - received)) < 0) 
       { perror("Read"); pthread_exit(NULL); } 

       received += nread; 
      } 

      if(strncmp(buffer, "end", 4) == 0) { break; } 

      write_all(file, buffer, strlen(buffer)+1); 
     } 

客户端打开一个文件(绝对),并在其所写的东西它读取。它首先读取它需要读取的尺寸,然后它不会停下来读取,直到达到该尺寸。如果客户端读取“结束”,则服务器已停止写入套接字,以便客户端停止读取。

问题是我无法打开转移后的文件。我读了一些我无法打开的图像。我还读了一个file.txt,我写了一些随机单词,这似乎被复制了,但它也有一些垃圾(其照片编号为2)。为什么我得到这个以及如何正确地从套接字传输文件?

enter image description here

enter image description here

+0

[tag:encoding]的相关性使我不知所措。 – EJP

+0

'read'和'write'都返回读取或写入的字节数,这可能比请求的少。 –

回答

1

常见的问题。 read()不终止缓冲区,因此使用strlen()作为计数无效。读/写循环应该是这样的:

int count; 
while ((count = read(inFD, buffer, sizeof buffer)) > 0) 
{ 
    if (write(outFD, buffer, count) < 0) 
    { 
     perrror("write"); // at least 
     break; 
    } 
} 

其次是错误处理如下:

if (count < 0) 
{ 
    perror("read"); // at least 
} 

你的第二个问题带有假设"end"将自身作为一个独立的消息被接收。这不能保证。您必须通过在每个文件之后关闭套接字来使用流结束,或者在每个文件之前发送长度,并且只从每个文件的流中读取许多字节。但是,由于您已经发送了长度,发送"end"无论如何都毫无意义。

+0

您还需要检查来自'write'的返回值,因为它可能写入少于count个字节,在这种情况下,您需要再次写入调用才能写入更多。 –

+0

特别是在非阻塞模式下。某些特定的底层对象(如管道和文件)可能会保证小于某个限制的写入不会返回短值,但是您需要检查计数实际上是否小于该限制,并且outFD是限制适用的某些内容... –

+0

@ChrisDodd对不起,我误解了。根据Posix规范,不在*阻止*模式,但我应该检查错误。 – EJP