c# - 限制连接的数量和时间 TcpListener。如何正确close\stop TcpListener 和TcpClient?

标签 c# tcpclient tcplistener

我有一些代码:

    protected TcpListener ClientListener;
    protected TcpClient ClientSocket;
    protected Thread th1;
    public static string server_ip = string.Empty;
    public static string server_port = string.Empty;

    internal void start_potok()
    {
        Protection.Ban.ban_del();
        th1 = new Thread(start_listener);
        th1.IsBackground = true;
        th1.Start();
    }

    internal void stop_potok()
    {
        th1.Abort();
        if (ClientSocket != null)
        {
            ClientSocket.Close();
        }
        ClientListener.Stop();
    }

    private void start_listener() 
    {
        try
        {
            ClientListener = new TcpListener(IPAddress.Parse(server_ip), Convert.ToInt32(server_port));
            ClientListener.Start();
            ClientSocket = default(TcpClient);
            while (true)
            {
                ClientSocket = ClientListener.AcceptTcpClient();
                client_connected(ClientSocket);
            }
        catch (ThreadAbortException ex)
        {
            //not catch this exception
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.Message);
        }
    }

    private void client_connected(TcpClient client)
    {
        //check bans and other
        LoginClientProc lcp = new LoginClientProc(client);
    }

听力等级:

class LoginClientProc
{
    internal EndPoint address;
    internal TcpClient client;
    internal NetworkStream stream;
    private byte[] buffer;

    internal LoginClientProc(TcpClient Client)
    {
        address = Client.Client.RemoteEndPoint;
        client = Client;
        stream = Client.GetStream();

        new System.Threading.Thread(read).Start();
    }

    void read()
    {
        try
        {
            buffer = new byte[2];
            stream.BeginRead(buffer, 0, 2, new AsyncCallback(OnReceiveCallbackStatic), null);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void OnReceiveCallbackStatic(IAsyncResult result)
    {
        int rs = 0;
        try
        {
            rs = stream.EndRead(result);

            if (rs > 0)
            {
                short Length = BitConverter.ToInt16(buffer, 0);
                buffer = new byte[Length - 2];
                stream.BeginRead(buffer, 0, Length - 2, new AsyncCallback(OnReceiveCallback), result.AsyncState);
            }
            else
                //0 = client close connection
        }
        catch (Exception s)
        {
        }
    }

    private void OnReceiveCallback(IAsyncResult result)
    {
        stream.EndRead(result);

        byte[] buff = new byte[buffer.Length];
        buffer.CopyTo(buff, 0);
        if (!verify_packet)
        {
            //Exception
        }
        else
        {
            handle(buff);
            new System.Threading.Thread(read).Start();
        }
    }

    private void handle(byte[] buff)
    {
        byte id = buff[0];
        switch (id)
        {
            //cases for headers packets
            default:
                //unknown packet
                //Here need correct Close connection
                break;
        }
       //response for packet
}

所以,我有一些问题:

  1. 如何限制客户端连接数? (不超过10 用户,例如)
  2. 如何限制客户端连接的时间(生命周期)? (例如不超过 30 秒)
  3. 如何在应用程序关闭时正确停止监听线程(TcpListener、TcpClient)?
  4. 当Server收到未知数​​据包时如何正确关闭TcpClient?

感谢您的回答!

最佳答案

您可能需要使用队列。这是服务器端可能的解决方案的草图:

class Program
{
    Queue<Connection> queue = new Queue<Connection>();

    TcpListener listener;

    ManualResetEvent reset = new ManualResetEvent(true);

    static void Main(string[] args)
    {
        new Program().Start();
    }

    void Start()
    {
        new Thread(new ThreadStart(HandleConnection)).Start();

        while (true)
        {
            while (queue.Any())
            {
                var connection = queue.Dequeue();

                connection.DoStuff();

                if(!connection.Finished)
                    queue.Enqueue(connection);
            }

            reset.WaitOne();
        }
    }

    static readonly byte[] CONNECTION_REFUSED = Encoding.ASCII.GetBytes("Cannot accept a connection right now.");
    static readonly int CONNECTION_REFUSED_LENGTH = CONNECTION_REFUSED.Length;

    void HandleConnection()
    {
        listener.Start();

        while (true)
        {
            var client = listener.AcceptTcpClient();

            if (queue.Count <= 10)
            {
                queue.Enqueue(new Connection(client));
                reset.Set();
            }
            else
            {
                client.GetStream().Write(CONNECTION_REFUSED, 0, CONNECTION_REFUSED_LENGTH);
                client.Close();
            }
        }
    }

}

public sealed class Connection
{
    readonly TcpClient client;
    readonly Stopwatch stopwatch = new Stopwatch();

    public Connection(TcpClient client)
    {
        this.client = client;
        stopwatch.Start();
    }

    public void DoStuff()
    {

    }

    public void Abort()
    {
        //You can write out an abort message to the client if you like.
        client.Close();
        completed = true;
    }

    bool completed;

    public bool Finished
    {
        get
        {
            return stopwatch.ElapsedMilliseconds > 30 * 1000 || completed;
        }
    }
}

基本思想是使用一个线程将传入连接添加到队列中,然后使用另一个线程遍历队列以处理每个连接。当连接 Finished 时,连接将从队列中删除(或者更确切地说不重新排队)。

一个健壮的解决方案可能需要使用 lock 语句或 ConcurrentQueue 类。在我的草图中,为了简洁起见,我在 TCPClient 类上使用了阻塞方法,但是,当然您会希望使用非阻塞方法。

关于c# - 限制连接的数量和时间 TcpListener。如何正确close\stop TcpListener 和TcpClient?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21783422/

相关文章:

c# - .Net Core 中的异步服务器套接字 - 如何返回结果?

c# - 通过 TCP 发送大字符串 - Windows Phone

.net - TcpListener 超时/关于/某事?没有异步?

c# - 在 PictureBox 上绘图

c# - 如何用堆栈添加大数?

c# - asp.net mvc4 生成新的帐户确认 token

java - TCP 客户端接受对象

C# 使用 JavaScript 与浏览器通信

c# - 从运行时创建的对象订阅事件

c# - 如何在同一集合位置替换列表中的值