简体   繁体   English

从TCP服务器踢客户端

[英]Kicking clients from TCP server

I tried to add a functionality to my server to kick specific clients. 我试图向服务器添加功能以踢特定的客户端。 But Read function in client's thread is blocking the loop and client's kicked command won't be executed until client sends an another message. 但是客户端线程中的Read函数阻塞了循环,并且客户端发送另一条消息之前,不会执行客户端的kicked命令。 So I added this to client's thread in server; 所以我将其添加到服务器中客户端的线程中; (By the way, I can't really understand why I should put Poll there but it throws an error without it.) (顺便说一句,我真的不明白为什么我应该把Poll放在那儿,但是如果没有它就会抛出错误。)

if (client.Socket.Poll(10, SelectMode.SelectRead))
{
    readMessageSize = client.Stream.Read(readMessage, 0, _packetSize); 
}
else
{
    if (client.Kicked)
    {
        Console.WriteLine("The client [" + client.IP + "] has been kicked.");
        break;
    }

    Thread.Sleep(10);
    continue;
}

This time, it gives an error on client's constructor (this constructor takes the socket that returns from Accept() function as parameter) says: "The operation is not allowed on a non-blocking Socket.". 这次,它给客户端的构造函数带来了错误(该构造函数将从Accept()函数返回的套接字作为参数)说:“在非阻塞套接字上不允许进行该操作。” So, I set Blocking true temporarily like this; 因此,我暂时将Blocking设置为true;

public ClientSocket(Socket client)
{
    _socket = client;
    _socket.Blocking = true;

    try
    {
        Stream = new NetworkStream(_socket);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    _socket.Blocking = false;
}

I also set listener socket's Blocking to false and changed it because when I tried to Abort() listener thread it won't, because it's stucked at Accept() . 我还将侦听器套接字的Blocking设置为false并更改了它,因为当我尝试Abort()侦听器线程时,它不会,因为它卡在了Accept()

while (Running)
{
    try
    {
        if (_socket.Poll(10, SelectMode.SelectRead))
        {
            var newClientSocket = _socket.Accept();
            AddClient(newClientSocket);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        StopListen();
        break;
    }

    Thread.Sleep(250);
}

I feel like I'm going a wrong way implemeting the server. 我感觉实现服务器的方式错误。 I'm ready to listen any advice. 我准备好听听任何建议。 I can also accept any open source projects or code snippets which might help me with this. 我也可以接受任何可能对我有帮助的开源项目或代码段。

With respect to the code you posted: 关于您发布的代码:

  1. Don't switch a socket back and forth between blocking and non-blocking. 不要在阻塞和非阻塞之间来回切换套接字。 If .NET doesn't want a non-blocking socket for a NetworkStream object, setting a socket you've given to a NetworkStream to non-blocking later is just going to cause problems. 如果.NET不想为NetworkStream对象提供非阻塞套接字,则稍后将您分配给NetworkStream的套接字设置为非阻塞只会造成问题。
  2. You won't need to use the Socket.Poll() method to do this correctly, but it's very important to note that there's a difference between "microseconds" (used in the Poll() method) and "milliseconds" (used almost everywhere else in .NET for integer time intervals). 您无需使用Socket.Poll()方法即可正确执行此操作,但请务必注意,“微秒”(用于Poll()方法)与“毫秒”(几乎在所有地方使用)之间存在差异NET中的整数时间间隔)。 Maybe you really mean to wait only 10 microseconds in the Poll() method, but it's not entirely clear from your post what you meant to do, so I want to make sure you're aware of the difference. 也许您真的想在Poll()方法中只等待10微秒,但是从您的帖子中并不清楚您打算做什么,所以我想确保您知道其中的区别。

As far as the right way to do this goes: 就执行此操作的正确方法而言:

  1. The first thing to do is to implement a non-blocking server, but to do it correctly. 首先要做的是实现一个非阻塞服务器,但要正确执行。 Use one of the asynchronous API options. 使用异步API选项之一。 Since you are using NetworkStream , the most obvious approach would be to use the ReadAsync() method. 由于您使用的是NetworkStream ,所以最明显的方法是使用ReadAsync()方法。
  2. Having implemented a non-blocking server, then terminating a client connection is as simple as maintaining the timeout logic somewhere (you won't be blocking a thread with I/O, but that also means you don't have an I/O thread you can use for the timeout…you'll have to put that timeout logic somewhere else). 实现了非阻塞服务器之后,终止客户端连接就像在某个地方维护超时逻辑一样简单(您不会使用I / O阻塞线程,但这也意味着您没有I / O线程您可以使用超时...,您必须将超时逻辑放在其他位置)。
  3. Ideally, you will "terminate" the client with a graceful closure, ie calling the Socket.Shutdown() method, waiting for the client to close its end (ie you see a receive operation complete with 0-byte length). 理想情况下,您将使用一个正常的关闭来“终止”客户端,即调用Socket.Shutdown()方法,等待客户端关闭其末尾(即,您看到一个长度为0字节的接收操作)。 But you can probably get away with resetting the connection if you must (ie Socket.Close() ). 但是如果需要的话,您可能可以摆脱重置连接的Socket.Close()Socket.Close() )。 Either will cause the asynchronous read operation to complete, allowing you to clean up the client information. 这两种方法都会导致异步读取操作完成,从而使您可以清除客户端信息。

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

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