簡體   English   中英

限制連接數量和時間TcpListener。 如何正確關閉\\停止TcpListener和TcpClient?

[英]Limit amount and time of connections TcpListener. How correct close\stop TcpListener and TcpClient?

我有一些代碼:

    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. 服務器收到未知數​​據包時,如何正確關閉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類上使用了阻塞方法,但是,當然你會想要使用非阻塞方法。

限制客戶端連接數量:

TcpListener.Start方法(Int32)

如何設置超時:

tcpListener.Server.ReceiveTimeout = 1000;
tcpListener.Server.SendTimeout = 1000;

正確的方法來阻止聽眾:

正確的方法來停止TcpListener

在服務器收到未知數​​據包時關閉TCPClient的正確方法

這有點復雜,具體取決於您要實現的協議。

  • 最簡單的方法是關閉傳入連接。
  • 如果你想要更聰明的東西,你需要考慮如何讓客戶知道有一個意外的包,並重新發送或重新開始。 基本上設計一個錯誤處理機制(那里有很多)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM