我正在使用TcpClient对象来传输文件。只有一个对象。因此,在传输文件时,我曾经锁定此对象并传输文件,以便其他线程等待,直到TCPClient被释放。
有没有办法让Threads与单个对象并行工作?
答案 0 :(得分:3)
不,让每个线程都使用自己的连接。
答案 1 :(得分:0)
...有点儿
你可以使用NetworkStream.BeginWrite,感觉就好像你在paeallel中使用它一样....
答案 2 :(得分:0)
BeginWrite / BeginRead将释放您当前的线程并在后台执行操作。您可以使用BeginWrite排队多次写入(并获得并行工作感)。我不建议这样做,因为内部套接字缓冲区在发送文件时可能会变满。
您始终可以切换到套接字并使用SendFile方法。
如果你有多个TcpClients或套接字,你可以使用BeginWrite / BeginRead方法来处理它们,而不必为每个方法创建一个新线程。
下面是一个小例子,它只是连接到服务器,发送文件并断开连接。它可以处理任何数量的开放tcpclients。如你所见,它不使用任何线程(它是在.Net框架的后台完成的)
/// <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; }
}