views:

394

answers:

3

I am using TcpClient object to transfer the files. There is only one object. So while transferring the file, I used to lock this object 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?

+3  A: 

No, make each thread use its own connection.

Lasse V. Karlsen
tcpclient.connect(remotehost, port)if I send the port other then the used for making connection then it throws a error(refuse connection) while making with same port, makes it same object.
marshalprince
But if you use one connection, how will the server know which data belongs together?
Lasse V. Karlsen
what I am doing is, for making a connection I am using one TCPClientand for which I am sending\receiving the file I am creating another TCPClient but now I need to lock the first one i.e used for connection. But in between if I need to send the data with another thread(I make a new TCPClient for data) but for connection TCPClient is locked already. So how can I send the another file
marshalprince
You're not answering my question. Think of two threads using the same TCP connection object as two people on the other end of the telephone, both talking. How will you reliably tell them apart if they sound the same?
Lasse V. Karlsen
A: 

kinda....

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

Hellfrost
A: 

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; }
}
jgauffin