开发者

Making Threads work in parallel in c#

I am using TcpClient object to transfer the files. There is only one object. So while transferring the file, I used to lock this obj开发者_JAVA技巧ect and transfer the file so the other threads waits until the TCPClient is released.

Is there a way I can make Threads work in parallel with a single object?


No, make each thread use its own connection.


kinda....

you can use NetworkStream.BeginWrite it will feel as if you are using it in paeallel....


BeginWrite/BeginRead will release your current thread and do stuff in the background. You can enqueue multiple writes with BeginWrite (and get a sense of parallel work). I wouldn't recommend it though, since the internal socket buffer can get full when sending files.

You can always switch to a Socket and use the SendFile method.

If you have multiple TcpClients or Sockets, you can use the BeginWrite/BeginRead methods to handle them all without having to create a new thread for each of them.

Below is a small example that will just connect to server, send a file and disconnect. It can handle any amount of open tcpclients. And as you see, it doesn't use any threads (it's done in the background by .Net framework)

/// <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; }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜