2014-05-16 74 views
0

我有一个用于文件发送的客户端和服务器代码。出于某种原因,我需要在客户端接收和从服务器发送...发送多个文件客户端和服务器

一切工作完美,在某些情况下,所有文件发送和接收完美。在另外一些情况下,发送几个文件程序崩溃后。不明白问题出在哪里?

错误:

client colsole

server console

客户

// client code 
using System; 
using System.IO; 
using System.Collections.Generic; 
using System.Linq; 

using System.Net; 
using System.Net.Sockets; 
using System.Text; 

class Client003 
{ 
    const string destFilePath = @"..\..\..\"; 
    const int BufferSize = 1024; 

    public static void StartReceiving() 
    { 
     // Data buffer for sending data. 
     byte[] buffer; 

     // FileStream to read data 
     FileStream fileStream; 
     int fileNameLen = 0; 
     string fileName = ""; 
     long fileLen = 0; 
     int NoOfPackets = 0; 
     int receivedBytes = 0; 
     int i, j; 

     // Connect to a remote device. 
     try 
     { 
      // Establish the remote endpoint for the socket. 
      // This example uses port 11000 on the local computer. 
      IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
      IPAddress ipAddress = ipHostInfo.AddressList[0]; 
      IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000); 

      // Create a TCP/IP socket. 
      Socket receiver = new Socket(AddressFamily.InterNetwork, 
       SocketType.Stream, ProtocolType.Tcp); 

      // Connect the socket to the remote endpoint. Catch any errors. 
      try 
      { 
       receiver.Connect(remoteEP); 

       buffer = new byte[4]; 
       receiver.Receive(buffer, 4, 0); 
       int filesNumber = BitConverter.ToInt32(buffer, 0); 

       for (i = 0; i < filesNumber; i++) 
       { 
        buffer = new byte[4]; 
        receiver.Receive(buffer, 4, 0); 
        fileNameLen = BitConverter.ToInt32(buffer, 0); 
        // -- 
        buffer = new byte[fileNameLen]; 
        receiver.Receive(buffer, fileNameLen, 0); 
        fileName = Encoding.UTF8.GetString(buffer); 
        // -- 
        buffer = new byte[8]; 
        receiver.Receive(buffer, 8, 0); 
        fileLen = BitConverter.ToInt64(buffer, 0); 
        // -- 
        NoOfPackets = Convert.ToInt32(Math.Ceiling(
         Convert.ToDouble(fileLen)/Convert.ToDouble(BufferSize))); 
        fileStream = new FileStream(destFilePath + fileName, FileMode.OpenOrCreate, FileAccess.Write); 
        receivedBytes = 0; 
        // -- 
        for (j = 0; j < NoOfPackets; j++) 
        { 
         if (fileLen > BufferSize) 
         { 
          buffer = new byte[BufferSize]; 
          receivedBytes = receiver.Receive(buffer, BufferSize, 0); 
          fileStream.Write(buffer, 0, receivedBytes); 
          fileLen -= BufferSize; 
         } 
         else 
         { 
          buffer = new byte[fileLen]; 
          receivedBytes = receiver.Receive(buffer, (int)fileLen, 0); 
          fileStream.Write(buffer, 0, receivedBytes); 
         } 
        } 
        fileStream.Close(); 
       } 
       // Release the socket. 
       receiver.Shutdown(SocketShutdown.Both); 
       receiver.Close(); 

      } 
      catch (ArgumentNullException ane) 
      { 
       Console.WriteLine("ArgumentNullException : {0}", ane.ToString()); 
      } 
      catch (SocketException se) 
      { 
       Console.WriteLine("SocketException : {0}", se.ToString()); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Unexpected exception : {0}", e.ToString()); 
      } 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

    public static int Main(String[] args) 
    { 
     StartReceiving(); 
     return 0; 
    } 
} 

服务器

//server code 
using System; 
using System.IO; 

using System.Net; 
using System.Net.Sockets; 
using System.Text; 

using System.Collections.Generic; 

class Server003 
{ 
    public static void StartListening() 
    { 
     // Data buffer for incoming data. 
     byte[] buffer; 
     byte[] fileNameByte; 
     byte[] fileNameLenByte; 
     byte[] fileLenByte; 

     // FileStream to write data 
     FileStream fileStream; 
     Int64 fileLen = 0; 
     int NoOfPackets = 0; 
     int readBytes = 0; 
     int i; 

     // Establish the local endpoint for the socket. 
     // Dns.GetHostName returns the name of the 
     // host running the application. 
     IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[0]; 
     IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

     // Create a TCP/IP socket. 
     Socket listener = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, ProtocolType.Tcp); 

     // Bind the socket to the local endpoint and 
     // listen for incoming connections. 
     try 
     { 
      listener.Bind(localEndPoint); 
      listener.Listen(10); 

      // Start listening for connections. 
      Console.WriteLine("Waiting for a connection..."); 
      // Program is suspended while waiting for an incoming connection. 
      Socket handler = listener.Accept(); 

      Int32 filesNumber = binFilesNames.Count; 
      byte[] filesNumberByte = BitConverter.GetBytes(filesNumber); 
      handler.Send(filesNumberByte); 
      // -- 
      foreach (string binName in binFilesNames) 
      { 
       fileNameByte = Encoding.UTF8.GetBytes(binName); 
       fileNameLenByte = BitConverter.GetBytes(fileNameByte.Length); 
       handler.Send(fileNameLenByte); 
       handler.Send(fileNameByte); 
       // -- 
       fileStream = new FileStream(sourceFilePath + binName, FileMode.Open, FileAccess.Read); 
       fileLen = fileStream.Length; 
       fileLenByte = BitConverter.GetBytes(fileLen); 
       handler.Send(fileLenByte); 
       // -- 
       NoOfPackets = Convert.ToInt32(Math.Ceiling(
        Convert.ToDouble(fileLen)/Convert.ToDouble(BufferSize))); 
       for (i = 0; i < NoOfPackets; i++) 
       { 
        if (fileLen > BufferSize) 
        { 
         buffer = new byte[BufferSize]; 
         // reeding data from file and writing it to the bytes "buffer" 
         readBytes = fileStream.Read(buffer, 0, BufferSize); 
         // send bytes from "buffer" 
         handler.Send(buffer, readBytes, SocketFlags.None); 
         fileLen -= BufferSize; 
        } 
        else 
        { 
         buffer = new byte[fileLen]; 
         // reeding data from file and writing it to the bytes "buffer" 
         readBytes = fileStream.Read(buffer, 0, (int)fileLen); 
         // send bytes from "buffer" 
         handler.Send(buffer, readBytes, SocketFlags.None); 
        } 
       } 
       fileStream.Close(); 
      } 
      // Release the socket. 
      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 

     Console.WriteLine("\nPress ENTER to continue..."); 
     Console.Read(); 
    } 


    public static List<string> GetFiles() 
    { 
     var dir = new DirectoryInfo(sourceFilePath);   // folder with files 
     var files = new List<string>();     // List with file names 

     foreach (FileInfo file in dir.GetFiles("T*260000.bin")) 
     { 
      files.Add(Path.GetFileName(file.FullName)); 
     } 

     return files; 
    } 

    public static int Main(String[] args) 
    { 
     binFilesNames = GetFiles(); 
     StartListening(); 

     return 0; 
    } 

    const string sourceFilePath = @"..\..\..\Binaries\"; 
    static List<string> binFilesNames; 
    const int BufferSize = 1024; 
} 

UPD: 我考虑到指向LB2的时刻。这是接收部分,它的工作需要:

while ((receivedBytes = receiver.Receive(buffer)) > 0) // receive bytes to "buffer" 
{ 
    var tmpBuff = buffer.Take(receivedBytes); // takes first receivedBytes elements 
    bufferList.AddRange(tmpBuff); 
} 

但我不明白如何发送工作。当我一次发送整个数据 - 一切ok,但是当我试图发送部分它崩溃:

这工作和整个数据传送:

handler.Send(buffer); 

这一个崩溃:

int sentBytes = 0; 
int sumSentBytes = 0; 
do 
{ 
    // send bytes from "buffer" 
    sentBytes = handler.Send(buffer, sumSentBytes, BufferSize, SocketFlags.None); 
    sumSentBytes += sentBytes; 
} 
while (sentBytes > 0); 

那么构建大量数据发送的最佳方式是什么(在我的情况下大约20Mb,但取决于)?

+5

你除了张贴的代码墙,并要求*那里是我的错误*其他具体问题? –

+0

我没有找到发送多个文件的好例子,所以我认为它会很有趣 – Farik

+1

@Farik对于你的UPD发送逻辑...你继续循环,直到'发送'返回0.这是可疑的,因为你可能应该是循环,直到您的消息的所有字节已发送...我的猜测是这是您的错误... – LB2

回答

1

代码中有多个错误可以明确指出特定的来源。下面是你应该知道的几件事并且其代码需要清理:

  • Socket类是IDisposable,因此应该被包裹在using。 (我不知道这是完整的程序,还是只有驱动程序main()的片段,但是如果您拨打StartReceiving足够多的时间,它会泄漏内存)。
  • FileStream(你有一个for循环)是IDisposable,因此应该包装在using。 (打电话给.Close()可能实际清理不够,但还是更好用using。)
  • 使用Socket.Receive()是不正确的。你不能假设你收到了你请求的字节数。如果连接丢失,则返回0;或者接收缓冲区中当前可用的字节数(最多请求计数)返回Receive()。所以,当你经历:

      buffer = new byte[fileNameLen]; 
          receiver.Receive(buffer, fileNameLen, 0); 
          fileName = Encoding.UTF8.GetString(buffer); 
          // -- 
          buffer = new byte[8]; 
          receiver.Receive(buffer, 8, 0); 
          fileLen = BitConverter.ToInt64(buffer, 0); 
    

...这是很可能的,你只能读取的文件名字节的一部分,得到部分文件名,然后其余的文件名实际上是(错误地)解释为fileLen字节。

  • 正确使用receivedBytes复制收到的字节文件流,但你错误地BufferSize递减fileLen而非receivedBytes,从而通过可能只写流的一部分破坏你的文件,在这部分代码:

        receivedBytes = receiver.Receive(buffer, BufferSize, 0); 
            fileStream.Write(buffer, 0, receivedBytes); 
            fileLen -= BufferSize; 
    
  • 您保存在每次调用一个循环.Receive这是不必要的重新分配新的byte[]。您可以继续重复使用相同的缓冲区。

  • 对于服务器代码,您发布的例外截图有?用于消息(类似编码问题)。请陷阱并发布实际消息。

这些只是我偶然发现的几件事情。这些问题中有些是罪魁祸首,还是存在其他问题,很难确定存在这些问题。

+0

谢谢!所以我需要在每个接收步骤中检查receivedBytes? – Farik

+0

@Farik是的,不要认为'Receive'给出了你期望的所有字节。它可以减少你的收入,因此你需要一直给它打电话,直到你收到完整的消息。所以我建议你编写你的函数来处理接收完整的任意消息(无论是文件名,还是大小等),然后将它作为协议逻辑的一部分来调用。 – LB2

1

我猜你会得到一个exception

ArgumentOutOfRangeException:尺寸大于缓冲区的长度减去offset参数的值。

你必须减去从size参数已经发送的字节数:

int bytesToSend = BufferSize - sumSentBytes; 
sentBytes = handler.Send(buffer, sumSentBytes, bytesToSend, SocketFlags.None); 
+0

Exactly ArgumentOutOfRangeException!感谢你的回答。如果你的意思是“大小”等于我想发送的总字节数,它就可以工作!但这意味着在第一次迭代中,我试图发送整个数据,如果它没有发送,我试图发送剩下的数据。在这种情况下,我们并不试图发送相应的最大套接字缓冲区大小的数据。或者发送函数在开始发送之前分离数据,我不需要考虑它? – Farik

相关问题