2009-12-21 35 views
0

我正在使用TcpClient對象來傳輸文件。只有一個對象。因此,在傳輸文件時,我用來鎖定該對象並傳輸文件,以便其他線程等待,直到TCPClient被釋放。讓線程在c中並行工作#

有沒有一種辦法可以讓線程並行工作,與單個對象?

回答

3

No,讓每個線程使用其自己的連接。

+0

tcpclient.connect(遠程主機,端口) (它是由.NET Framework中後臺執行),如果我發送其他的端口則用於製作連接,然後它拋出一個錯誤(拒絕連接),同時使用相同的端口,使其相同的對象。 – marshalprince 2009-12-21 12:31:26

+0

但是,如果您使用一個連接,服務器將如何知道哪些數據屬於一起? – 2009-12-21 13:14:18

+0

什麼我做的是,爲使連接我使用一個的TcpClient 並對此我發送\接收我創造另一個的TcpClient但現在我需要鎖定用於連接的第一個即文件。但是,如果我需要使用另一個線程發送數據(我爲數據創建一個新的TCPClient),但是對於連接,TCPClient已被鎖定。所以我怎樣才能發送另一個文件 – marshalprince 2009-12-22 12:14:05

0

有點兒....

你可以用它NetworkStream.BeginWrite會覺得如果你在paeallel使用它....

0

BeginWrite /的BeginRead將釋放你的當前線程做的東西在的背景。您可以使用BeginWrite將多個寫入入隊(並獲得並行工作感)。我不會推薦它,因爲發送文件時內部套接字緩衝區可能會變滿。

您可以隨時切換到Socket和使用方法SENDFILE。

如果你有多個TcpClients或插座,您可以使用BeginWrite /的BeginRead方法來處理他們所有,而無需創建一個新的線程爲他們每個人。

下面是一個小例子,這將只是連接到服務器,發送文件和斷開。它可以處理任何數量的開放tcpclients。正如你看到的,它不使用任何線程

/// <summary> 
/// Thread safe queue of client ids 
/// </summary> 
internal class FileSender 
{ 
    /// <summary> 
    /// A write operation have completed 
    /// </summary> 
    /// <param name="ar"></param> 
    private void OnWriteCompleted(IAsyncResult ar) 
    { 
     // We passed the context to this method, cast it back 
     var context = (ClientContext) ar.AsyncState; 

     // end the write 
     context.TcpClient.GetStream().EndWrite(ar); 

     // we've completed. 
     if (context.BytesSent >= context.FileStream.Length) 
     { 
      // notify any listener 
      Completed(this, new CompletedEventArgs(context.RemoteEndPoint, context.FileStream.Name)); 
      context.TcpClient.Close(); 
      return; 
     } 

     // Send more data from the file to the server. 
     int bytesRead = context.FileStream.Read(context.Buffer, 0, context.Buffer.Length); 
     context.BytesSent += bytesRead; 
     context.TcpClient.GetStream().BeginWrite(context.Buffer, 0, bytesRead, OnWriteCompleted, context); 
    } 

    /// <summary> 
    /// Send a file 
    /// </summary> 
    /// <param name="endPoint"></param> 
    /// <param name="fullPath"></param> 
    public void SendFile(IPEndPoint endPoint, string fullPath) 
    { 
     // Open a stream to the file 
     var stream = new FileStream(fullPath, FileMode.Open, FileAccess.Read); 

     // Create a client and connect to remote end 
     var client = new TcpClient(); 
     client.Connect(endPoint); 

     // Context is used to keep track of this client 
     var context = new ClientContext 
          { 
           Buffer = new byte[65535], 
           FileStream = stream, 
           TcpClient = client, 
           RemoteEndPoint = endPoint 
          }; 

     // read from file stream 
     int bytesRead = stream.Read(context.Buffer, 0, context.Buffer.Length); 

     // and send the data to the server 
     context.BytesSent += bytesRead; 
     client.GetStream().BeginWrite(context.Buffer, 0, bytesRead, OnWriteCompleted, context); 
    } 

    /// <summary> 
    /// File transfer have been completed 
    /// </summary> 
    public event EventHandler<CompletedEventArgs> Completed = delegate { }; 

    #region Nested type: ClientContext 

    /// <summary> 
    /// Used to keep track of all open connections 
    /// </summary> 
    private class ClientContext 
    { 
     /// <summary> 
     /// Gets or sets buffer used to send file 
     /// </summary> 
     public byte[] Buffer { get; set; } 

     /// <summary> 
     /// Gets or sets number of bytes sent. 
     /// </summary> 
     public int BytesSent { get; set; } 

     /// <summary> 
     /// Gets or sets file to send 
     /// </summary> 
     public FileStream FileStream { get; set; } 

     public IPEndPoint RemoteEndPoint { get; set; } 

     /// <summary> 
     /// Gets or sets client sending the file 
     /// </summary> 
     public TcpClient TcpClient { get; set; } 
    } 

    #endregion 
} 

internal class CompletedEventArgs : EventArgs 
{ 
    public CompletedEventArgs(IPEndPoint endPoint, string fullPath) 
    { 
     EndPoint = endPoint; 
     FullPath = fullPath; 
    } 

    public IPEndPoint EndPoint { get; private set; } 
    public string FullPath { get; private set; } 
}