Как мне лучше обрабатывать клиентов с помощью TCPListener? - PullRequest
3 голосов
/ 23 июля 2010

У меня была проблема с слишком много подключений После нескольких испытаний я вычитал, что проблема с МОИМ сервером.Тот факт, что порт прослушивания сервера был на левой стороне, должен был сказать мне.

При запуске одного и того же клиентского кода с использованием сервера на другом компьютере я не открываю сотни портов.Когда мой сервер на моей локальной машине, я получаю> 200 подключений к моему порту прослушивания.Я думаю, что неправильно обращаюсь с клиентами.Мой код ниже со всем удаленным кодом не сервера и клиента

{
    TcpListener server = null;
    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();

    while (true)
    {
        var client = server.AcceptTcpClient();
        using(var stream = client.GetStream()) {
        ...
        stream.Read(...
        ...
        stream.Write(...
        } //using above should close this.
        client.Close();
    }
    server.Stop();
}

Я изменил код для использования асинхронных соединений, и он блокируется во второй раз, когда он выполняет поток..Connected)

    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();
    server.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), server);
    while (true)
        Thread.Sleep(1000); //infinite loop for testing




public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
    Byte[] bytes = new Byte[1024 * 4];
    TcpListener listener = (TcpListener)ar.AsyncState;
    using (TcpClient client = listener.EndAcceptTcpClient(ar))
    {
        using (var stream = client.GetStream())
        using (var ostream = new MemoryStream())
        {
            while (client.Connected)
            {
                int i;
                while ((i = stream.Read(bytes, 0, bytes.Length)) == bytes.Length)
                    ostream.Write(bytes, 0, i);

                ostream.Write(bytes, 0, i);
                szresults = Func(ostream)
                var obuf = Encoding.UTF8.GetBytes(szresults);
                stream.Write(obuf, 0, obuf.Length);
            }
        }
        client.Close();
    }
}

Ответы [ 2 ]

2 голосов
/ 23 июля 2010

Вы имеете дело с соединением в той же теме.Это означает, что вы можете активно обрабатывать только одно соединение за раз.Самый простой подход состоит в том, чтобы передать клиент в новый поток и работать с ним там.

Теперь это не очень хорошо масштабируется - использование полностью асинхронных операций везде позволит вам обслуживатьтакое же количество клиентов использует меньше потоков - но в большинстве случаев это будет работать достаточно хорошо, IME.Это, безусловно, куда я бы пошел дальше.

В идеале вы не хотите каждый раз создавать новый поток ОС - для этого, вероятно, разумно использовать пул системных потоков, так что поток может быть повторно использован послесоединение было полностью обработано.Существуют риски, связанные с заполнением пула потоков ОС, но я подозреваю, что это вряд ли вас укусит.

Наконец, я бы поместил TcpClient в оператор using, чтобы убедиться, что вы утилизируете его дажеесли что-то еще не получается.Конечно, если вы передаете его другому потоку, это должен быть тот поток, который немедленно использует оператор using.

0 голосов
/ 23 июля 2010

Вам необходимо создать потоки для каждого соединения и правильно закрыть сокет, используя методы socket.shutdown и s ocket.close. Как видно из вашего кода, вы не закрываете сокет и напрямую останавливаете сервер, из-за которого сокет остается открыт.

Я бы хотел, чтобы вы прочитали эту статью один раз. Я получил помощь из рисунка 5 этой статьи.

Вы можете также столкнуться с проблемой, с которой я столкнулся в этой статье здесь

...