简体   繁体   中英

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. 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.)

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.". So, I set Blocking true temporarily like this;

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() .

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.
  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). 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.

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. Since you are using NetworkStream , the most obvious approach would be to use the ReadAsync() method.
  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).
  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). But you can probably get away with resetting the connection if you must (ie Socket.Close() ). Either will cause the asynchronous read operation to complete, allowing you to clean up the client information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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