[英]C# TCP server wait for 2 clients to respond
我目前正在處理服務器/客戶端項目。 我的問題是,服務器如何等待兩個特定的連接響應?
服務器:
private TcpListener tcpListener;
private Thread listenThread;
private List<Connection> ConList = new List<Connection>();
Queue queue = new Queue();
public struct Connection
{
public Stream stream;
public StreamWriter streamw;
public StreamReader streamr;
public TcpClient tcpC;
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
try
{
Connection c = new Connection();
c.tcpC = this.tcpListener.AcceptTcpClient();
c.stream = c.tcpC.GetStream();
c.streamr = new StreamReader(c.stream);
c.streamw = new StreamWriter(c.stream);
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(c);
queue.Enqueue(c);
}
catch()
{
break;
}
}
}
private void HandleClientComm(Object client)
{
Connection con;
con = (Connection)client;
ConList.Add(con);
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
bytesRead = con.stream.Read(message, 0, 4096);
string s = Encoding.UTF8.GetString(message, 0, message.Length);
}
catch
{
//Socket error
break;
}
if (bytesRead == 0)
{
//Client lost connection
con.stream.Close();
con.tcpC.Close();
ConList.Remove(con);
con = null;
break;
}
}
}
private void QueueTimer_Tick(object sender, EventArgs e)
{
if (queue.count >= 2)
{
Connection c1;
Connection c2;
c1 = new Connection();
c1 = (Connection)queue.Dequeue();
c2 = new Connection();
c2 = (Connection)queue.Dequeue();
//Start thread which waits for a response from both connections
}
}
每個連接都放入隊列,並且如果queue.count> = 2(計時器每20秒檢查一次),則應該啟動一個新線程,該線程等待兩個客戶端的響應都以10秒超時。 我嘗試了3天,但找不到一種好的方法。 你們有什么建議嗎?
這是一個簡單的基於TPL的偵聽器/響應器,而無需將線程專用於進程。
private TcpListener _listener;
public void OnStart(CommandLineParser commandLine)
{
_listener = new TcpListener(IPAddress.Any, commandLine.Port);
_listener.Start();
Task.Run((Func<Task>) Listen);
}
private async Task Listen()
{
IMessageHandler handler = MessageHandler.Instance;
while (true)
{
var client = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);
// Without the await here, the thread will run free
var task = ProcessMessage(client);
}
}
public void OnStop()
{
_listener.Stop();
}
public async Task ProcessMessage(TcpClient client)
{
try
{
using (var stream = client.GetStream())
{
var message = await SimpleMessage.DecodeAsync(stream);
_handler.MessageReceived(message);
}
}
catch (Exception e)
{
_handler.MessageError(e);
}
finally
{
(client as IDisposable).Dispose();
}
}
}
首先要介紹您的QueueTimer_Tick()函數。 其中包含以下代碼:
c1 = new Connection();
c1 = (Connection)queue.Dequeue();
不需要此行的第一行,它會創建一個新的Connection對象,該對象將立即被您退出隊列的所有對象覆蓋。 還不能像使用類型列表一樣使用類型隊列嗎?
要回答您的問題,我想您需要使用的是Socket.Select()方法。 它將獲取套接字列表並檢查它們的可讀性,並且還允許指定超時。
為了實現所需的功能,您需要循環調用Select(),在該循環中,每次檢查尚未可讀的客戶端的可讀性時。 您還需要確定每次選擇的呼叫在10秒延遲中使用了多少,並相應地調整超時。
所以在偽代碼中:
create L1 a list of sockets that are to be readable
set the timeout T to 10 seconds
while L1 is not empty
copy L1 to a tempory list L2
Socket.Select(L2,T)
If a timeout then exit loop
Remove the socket(s) that are readable from L1
recalculate T based on how long the Select took
End While
注意:TcpClient.Client()方法獲取TcpClient的套接字。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.