C#TCP服务器等待2个客户端响应

时间:2015-03-05 13:02:17

标签: c# multithreading tcp client server

我目前正在研究服务器/客户端项目。 我的问题是,服务器如何等待两个特定的连接响应?

服务器:

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天的东西,但找不到一个好办法。你们有什么建议吗?

2 个答案:

答案 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。