2011-04-19 81 views
4

我有一个接收器和发件人客户端,几乎传输文件。这是我迄今在接收器上的东西:如何取消TCP文件传输c#

Thread t1; 
    int flag = 0; 
    string receivedPath; 
    public delegate void MyDelegate(string s); 
    int bytesRead = 0; 
    bool endReceive = false; 
     public Form1() 
     { 
      t1 = new Thread(new ThreadStart(StartListening)); 
      t1.Start(); 
      InitializeComponent(); 
     } 

     public class StateObject 
     { 
      // Client socket. 
      public Socket workSocket = null; 

      public const int BufferSize = 1024*100; 

      // Receive buffer. 
      public byte[] buffer = new byte[BufferSize]; 
     } 

    public static ManualResetEvent allDone = new ManualResetEvent(false); 

    public void StartListening() 
    { 
     byte[] bytes = new Byte[1024*1000]; 
     IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 9050); 
     Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     try 
     { 
      listener.Bind(ipEnd); 
      listener.Listen(100); 
      while (true) 
      { 
       allDone.Reset(); 
       listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
       allDone.WaitOne(); 

       if (endReceive) 
       { 
        listener.Disconnect(true); 
       } 
      } 
     }   
     catch (Exception ex) 
     { 

     } 

    } 
    public void AcceptCallback(IAsyncResult ar) 
    { 

     allDone.Set(); 
     Socket listener = (Socket)ar.AsyncState; 
     Socket handler = listener.EndAccept(ar); 
     StateObject state = new StateObject(); 
     state.workSocket = handler; 
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(ReadCallback), state);    
     flag = 0; 
    } 

    public void ReadCallback(IAsyncResult ar) 
    { 
     int fileNameLen = 1; 
     String content = String.Empty; 
     StateObject state = (StateObject)ar.AsyncState; 
     Socket handler = state.workSocket; 

     try 
     { 
      bytesRead= handler.EndReceive(ar); 

     } 
     catch (SocketException x) 
     { 
      MessageBox.Show("File Transfer was cancelled"); 
      Invoke(new MyDelegate(LabelWriter), new object[] { "Waiting for connections" }); 
      if (File.Exists(receivedPath)) 
      {      
       File.Delete(receivedPath); 
       return; 
      } 
     } 
     if (endReceive) 
     { 
      handler.Disconnect(true); 
      if (File.Exists(receivedPath)) 
      { 
       File.Delete(receivedPath); 
      } 
      return; 
     } 

     if (bytesRead > 0) 
     { 
      if (flag == 0) 
      {      
       fileNameLen = BitConverter.ToInt32(state.buffer, 0); 
       string fileName = Encoding.UTF8.GetString(state.buffer, 4, fileNameLen);      
       receivedPath = fileName;      
       Invoke(new MyDelegate(LabelWriter), new object[] { "Receiving File: " + fileName }); 
       flag++; 
      } 
       if (flag >= 1) 
       { 

        BinaryWriter writer = new BinaryWriter(File.Open(receivedPath, FileMode.Append)); 
        if (flag == 1) 
        { 
         writer.Write(state.buffer, 4 + fileNameLen, bytesRead - (4 + fileNameLen)); 
         flag++; 
         ReleaseMemory(); 
        } 
        else 
         writer.Write(state.buffer, 0, bytesRead); 
         writer.Close(); 
         try 
         { 
          handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
               new AsyncCallback(ReadCallback), state); 
         } 
         catch (SocketException exc) 
         { 
          MessageBox.Show("File Transfer was cancelled"); 
          Invoke(new MyDelegate(LabelWriter), new object[] { "Waiting for connections" }); 
          if (File.Exists(receivedPath)) 
          {          
           File.Delete(receivedPath); 
           return; 
          } 
         }             
       } 
     } 
     else    
      Invoke(new MyDelegate(LabelWriter), new object[] {"Data Received"});   
    } 

我想达到的是取消转移发生的能力。我想到的是将布尔值“EndReceive”设置为false,并且每次调用ReadCallBack方法时都检查EndReceive。如果它是假的,我断开插座。它在停止接收文件时起作用,然而,发件人应用程序只是冻结。这基本上是我发送的:

while (true) 
     { 
      int index = 0; 
      while (index < fs.Length) 
      { 
       int bytesRead = fs.Read(fileData, index, fileData.Length - index); 
       if (bytesRead == 0) 
       { 
        break; 
       } 

       index += bytesRead; 
      } 
      if (index != 0) 
      { 
       try 
       { 
        clientSock.Send(fileData, index, SocketFlags.None); 
       } 
       catch (Exception sexc) 
       { 
        MessageBox.Show("Transfer Cancelled"); 
        return; 
       } 
       ReleaseMemory(); 
       if ((progressBar1.Value + (1024 * 1000)) > fs.Length) 
       { 
        progressBar1.Value += ((int)fs.Length - progressBar1.Value); 
       } 
       else 
        progressBar1.Value += (1024 * 1000); 

       lblSent.Text = index.ToString(); 
      } 

      if (index != fileData.Length) 
      { 
       ReleaseMemory(); 
       progressBar1.Value = 0; 
       clientSock.Close(); 
       fs.Close();     
       break; 


      } 
     } 

有什么想法?

+1

如果我没有错,如果你没有做适当的连接关系,你会看到你继续接收,但所有0字节。我做了一个应用程序之前,客户端将自动重新连接,如果连接丢失。所以当连接丢失时,我将接收到0字节,所以在那一刻,我只关闭客户端,并重新建立连接。 – 2011-04-19 01:51:22

回答

2

我认为很难强制执行中断来处理您正在进行的批量传输,并使用TCP完全关闭中断。如果你的块大小为1024,并且在每次传输完数据后,发送一个快速的ACK或者NACK字节到接收方?表示转移的Nack将被中断,确认表示继续。

不幸的是,这需要接收器/发送器完全双工,并且要小心!即使它是异步IO,如果您计划并从同一个套接字读写,您也需要在单独的线程上调用BeginReceive和BeginSend。