从TCP服务器踢客户端

时间:2015-02-04 03:26:38

标签: c# sockets networking tcp server

我尝试向我的服务器添加一项功能,以启动特定客户端。但是客户端线程中的Read函数阻塞了循环,客户端的踢脚命令将被执行,直到客户端发送另一条消息。所以我把它添加到服务器中的客户端线程中; (顺便说一下,我真的不明白为什么我应该把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;
}

这一次,它在客户端的构造函数上给出了一个错误(这个构造函数将从Accept()函数返回的套接字作为参数)说:"不允许在非客户端执行操作阻止套接字。"。所以,我暂时将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;
}

我还将侦听器套接字的阻塞设置为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);
}

我觉得我在实施服务器方面走错了路。我准备听取任何建议。我也可以接受任何可能对我有帮助的开源项目或代码片段。

1 个答案:

答案 0 :(得分:1)

关于您发布的代码:

  1. 不要在阻塞和非阻塞之间来回切换套接字。如果.NET不想要NetworkStream对象的非阻塞套接字,那么设置一个套接字,你已经被NetworkStream设置为非阻塞,这只会导致问题
  2. 您不需要使用Socket.Poll()方法正确地执行此操作,但请务必注意,"微秒"之间的差异非常重要。 (在Poll()方法中使用)和"毫秒" (几乎在.NET中用于整数时间间隔的其他地方)。也许你真的想在Poll()方法中等待10微秒,但是你的帖子并不完全清楚你的意图,所以我想确保你知道差。
  3. 正确的方法是:

    1. 要做的第一件事是实现非阻塞服务器,但要正确执行。使用其中一个异步API选项。由于您使用的是NetworkStream,因此最明显的方法是使用ReadAsync()方法。
    2. 实现了非阻塞服务器,然后终止客户端连接就像在某个地方维护超时逻辑一样简单(你不会用I / O阻塞一个线程,但这也意味着你没有'你有一个可用于超时的I / O线程......你必须把那个超时逻辑放在其他地方。)
    3. 理想情况下,您将终止"具有优雅闭包的客户端,即调用Socket.Shutdown()方法,等待客户端关闭其结束(即,您看到完成的接收操作的长度为0字节)。但是,如果必须(例如Socket.Close()),您可能会重置连接。这两种方法都会导致异步读取操作完成,从而可以清理客户端信息。