2011-10-08 76 views
1

我做了一个客户端&服务器建立通过套接字TCP连接,我试图通过套接字发送二进制数据,但我只能派出TXT或PDF文件,我没有运气exe文件,我使用fread和fseek来读取文件并将其分割成缓冲区。当我读取整个exe文件时,它会被成功发送,但是当我分割它时,它会被发送损坏!通过TCP发送二进制文件插座Ç

我读了一些关于套接字的书,但我仍然不太了解,并且有一些问题。

可以在一个send()中发送整个文件吗?或者我应该继续以小块形式发送它?

此外,为什么EXE文件在我发送块时被损坏?

谢谢! (C语言)

客户端代码:

int bufSize = 10000; 
int sentBytes = 0; 


    FILE * pFile; 
    long remainingBytes; 
    char * buffer; 
    size_t result; 

    pFile = fopen ("D:\\file.exe" , "rb"); 
    fseek (pFile , 0 , SEEK_END); 
    remainingBytes = ftell (pFile); 
    rewind (pFile); 

int bufferSize = remainingBytes > bufSize ? bufSize : remainingBytes; 
buffer = (char*) malloc (sizeof(char)*bufferSize); 
send(Socket, (char*)&remainingBytes, 4, 0); 

while(remainingBytes > 0) 
{ 
    fseek (pFile , sentBytes , SEEK_SET); 
    result = fread(buffer,1,bufferSize,pFile); 
    if(bufferSize < remainingBytes) 
    { 
     send(Socket, buffer, bufferSize, 0); 
    } 
    else 
    { 
     send(Socket, buffer, remainingBytes, 0); 
     bufferSize = remainingBytes; 
    } 
    remainingBytes -= bufferSize; 
    sentBytes += bufferSize; 
} 

服务器代码(C#)

 try 
     { 
      int bufferSize = 200; 
      int len = 0; 
      int receivedBytes = 0; 
      int remainingBytes = len; 
      byte[] length = new byte[4]; 
      //byte[] imgBuf = new byte[bufferSize]; 

      int current = 0; 
      List<byte[]> coming = new List<byte[]>(); 

      sockets[number].Receive(length,4,0); 

      len = BitConverter.ToInt32(length, 0); 
      remainingBytes = len; 

      bufferSize = len < bufferSize ? len : bufferSize; 

      while(receivedBytes < len) 
      { 
       if (remainingBytes > bufferSize) 
       { 
        coming.Add(new byte[bufferSize]); 
        //imgBuf = new byte[bufferSize]; 
        sockets[number].Receive(coming[current], bufferSize, 0); 
       } 
       else 
       { 
        coming.Add(new byte[remainingBytes]); 
        //imgBuf = new byte[remainingBytes]; 
        sockets[number].Receive(coming[current], remainingBytes, 0); 
        bufferSize = remainingBytes; 
       } 
       remainingBytes -= bufferSize; 
       receivedBytes += bufferSize; 
       current++; 
       //Array.Clear(imgBuf, 0, imgBuf.Length); 
      } 

      using (var stream = new FileStream(@"C:\receivedFile.exe",FileMode.Create)) 
      { 
       using (var binaryWriter = new BinaryWriter(stream)) 
       { 
        foreach (byte[] buffer in coming) 
        { 
         binaryWriter.Write(buffer); 
        } 
       } 

      } 
     } 
     catch (Exception ex) 
     { this.setText(ex.Message, textBox2); } 

编辑:感谢您的帮助,我得到它的工作:)

 try 
     { 
      int bufferSize = 1024 * 100; 
      int len = 0; 
      int receivedBytes = 0; 
      int remainingBytes = len; 
      int reached = 0; 

      byte[] length = new byte[4]; 
      byte[] imgBuf = new byte[bufferSize]; 

      int current = 0; 
      sockets[number].Receive(length,4,0); 

      len = BitConverter.ToInt32(length, 0); 
      remainingBytes = len; 

      bufferSize = len < bufferSize ? len : bufferSize; 
      imgBuf = new byte[len]; 

      while (reached < len) 
      { 
       reached += sockets[number].Receive(imgBuf, receivedBytes, remainingBytes, 0); 
       remainingBytes = len - reached; 
       receivedBytes = reached; 
       current++; 
       //Array.Clear(imgBuf, 0, imgBuf.Length); 
      } 

      using (var stream = new FileStream(@"C:\putty.exe",FileMode.Create)) 
      { 
       using (var binaryWriter = new BinaryWriter(stream)) 
       { 
         binaryWriter.Write(imgBuf); 
       } 
      } 
      Array.Clear(imgBuf, 0, imgBuf.Length); 
     } 
     catch (Exception ex) 
     { this.setText(ex.Message, textBox2); } 
+1

如果你从文件系统传输整个文件,你应该使用['的TransmitFile()'](http://msdn.microsoft.com/en-us/library/ms740565(VS.85)。 aspx)(如果在Windows上)或['sendfile()'](http://www.kernel.org/doc/man-pages/online/pages/man2/sendfile.2.html)(如果在Unix上) – millimoose

+0

感谢您的回答,但正如我所提到的,当我发送整个文件时,我完全没有问题。只有当我尝试以大块发送时才会出现此问题。 –

+0

我想说的是,不应该通过在内存中缓冲文件来从文件中发送文件,以便从性能的角度出发,无论文件是否在大块中 - 使用其中一种函数会更高效。 – millimoose

回答

4

您不检查您在sockets[number].Receive(coming[current], bufferSize, 0);实际收到的字节数。它不必与您声明的缓冲区大小相等。 另外,如评论所述,将整个文件保存在内存中不是一个好主意。

+0

我不知道这是多么有用,但它总是接收“bufferSize”相同的长度。 我编辑了这一行到 bytesReceived = sockets [number] .Receive(coming [current],bufferSize,0); –

+0

这是很难得到它在调试模式,只是添加一个例外bytesReceived!= coming [current] .Length并运行你的代码 –

+0

我发现最后有什么错, 我不得不使用过载o函数接收 bytess =套接字[数字]。Receive(imgBuf,receivedBytes,bufferSize,0);的 而不是创建一个字节列表,并添加一个新的字节数组,每个收到,我与消息长度为一个字节数组,并追加到它的所有请求 –

2

除了检查接收的字节数,您需要检查每个发送呼叫发送的字节数 - 如果你的TCP传输窗口填满了,比你要求发送调用可能发送更少的数据,其中如果您需要重新发送未发送的数据。

一般情况下,你总是需要检查你的系统的返回值调用来检查所有不同的偏僻角落里可能发生的情况。阅读send(2)和recv(2)的手册页以获取可能发生的所有事情的完整列表。