我目前正在研究服务器/客户端项目。 我的问题是,服务器如何等待两个特定的连接响应?
服务器:
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&gt; = 2(计时器每20秒检查一次),新线程应该是startet,等待来自两个客户端的响应超时10秒。我试图找出3天的东西,但找不到一个好办法。你们有什么建议吗?
答案 0 :(得分:0)
这是一个简单的基于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();
}
}
}
答案 1 :(得分:0)
首先关注QueueTimer_Tick()函数。在其中您有以下代码:
c1 = new Connection();
c1 = (Connection)queue.Dequeue();
不需要第一行,它会创建一个新的Connection对象,该对象会立即被您从队列中取出的任何内容覆盖。 Alos什么不使用类型化队列的方式与使用类型化列表相同?
回答你的问题我认为你所追求的是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的Socket。