简体   繁体   English

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

[英]C# TCP server wait for 2 clients to respond

I'm currently working on a server/client project. 我目前正在处理服务器/客户端项目。 My question is, how the server can wait for two specific connections to respond? 我的问题是,服务器如何等待两个特定的连接响应?

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

Each connection gets placed in queue and if queue.count >= 2 (timer checks every 20 seconds) a new thread should be startet which waits for a responds from both of the clients with a 10 seconds timeout. 每个连接都放入队列,并且如果queue.count> = 2(计时器每20秒检查一次),则应该启动一个新线程,该线程等待两个客户端的响应都以10秒超时。 I tried to figure something out for 3 days but cannot find a good way to do it. 我尝试了3天,但找不到一种好的方法。 Do you guys have any suggestions? 你们有什么建议吗?

Here is a simple TPL based listener/responder without needing to dedicate a thread to the process. 这是一个简单的基于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();
        }
    }
}

First off a point about your QueueTimer_Tick() function. 首先要介绍您的QueueTimer_Tick()函数。 In it you have the following code: 其中包含以下代码:

c1 = new Connection();
c1 = (Connection)queue.Dequeue();

The first line of this isn't needed, it creates a new Connection object that is immediately overwritten by whatever you pull off the queue. 不需要此行的第一行,它会创建一个新的Connection对象,该对象将立即被您退出队列的所有对象覆盖。 Alos what not use a typed queue in the same way as you use a typed List? 还不能像使用类型列表一样使用类型队列吗?

To answer your question what I think you are after is the Socket.Select() method. 要回答您的问题,我想您需要使用的是Socket.Select()方法。 It will take a list of sockets and check them for readability and it also allows a timeout to be specified. 它将获取套接字列表并检查它们的可读性,并且还允许指定超时。

To acheive what you want you'll need to call Select() in a loop where each time you check for readability of the clients who haven't yet become readable. 为了实现所需的功能,您需要循环调用Select(),在该循环中,每次检查尚未可读的客户端的可读性时。 You'll also need to work out how much of your 10 second delay each call to select has used and adjust the timeout accordingly. 您还需要确定每次选择的呼叫在10秒延迟中使用了多少,并相应地调整超时。

So in psuedo code: 所以在伪代码中:

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

NB: The TcpClient.Client() method gets the Socket for a TcpClient. 注意:TcpClient.Client()方法获取TcpClient的套接字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM