Проблемы стабильности сервера .NET TCP - PullRequest
1 голос
/ 08 сентября 2010

Я создал базовую .NET-серверную клиентскую инфраструктуру, используя TcpListener и SocketClient.Он многопоточный и асинхронный.Проблема в том, что сервер падает в какой-то момент, когда более 30 клиентов подключены одновременно.

Я пока не могу найти причину сбоев, хотя я использую довольно много блоков Try-Catch, чтобы регистрировать все исключения.

Так что я думаю, я могу бытьделать что-то неправильно концептуально в коде сервера.Я надеюсь, что вы, ребята, сможете помочь мне найти причину этих сбоев.Код следующий:

Запуск сервера и прослушивание соединения:

 public void StartServer()
    {
        isConnected = true;
        listener.Start();
        connectionThread = new Thread(new ThreadStart(ListenForConnection));
        connectionThread.Start();
    }

    private void ListenForConnection()
    {
        while (isConnected)
        {
            try
            {
                TcpClient client = listener.AcceptTcpClient();
                ClientConnection connection = new ClientConnection(this, client);
                connections.Add(connection);
            }
            catch (Exception ex)
            {
                log.Log("Exception in ListenForConnection: " + ex.Message, LogType.Exception);
            }
        }
    }

Класс ClientConnection:

 public class ClientConnection : IClientConnection
{
    private TcpClient client;
    private ISocketServer server;
    private byte[] data;
    private object metaData;

    public TcpClient TcpClient
    {
        get { return client; }
    }

    internal ClientConnection(ISocketServer server, TcpClient client)
    {
        this.client = client;
        this.server = server;

        data = new byte[client.ReceiveBufferSize];

        lock (client.GetStream())
        {
            client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
        }
    }

    internal void ReceiveMessage(IAsyncResult ar)
    {
        int bytesRead;

        try
        {
            lock (client.GetStream())
            {
                bytesRead = client.GetStream().EndRead(ar);
            }

            if (bytesRead < 1)
                return;

            byte[] toSend = new byte[bytesRead];
            for (int i = 0; i < bytesRead; i++)
                toSend[i] = data[i];

            // Throws an Event with the data in the GUI Dispatcher Thread
            server.ReceiveDataFromClient(this, toSend);

            lock (client.GetStream())
            {
                client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
            }
        }
        catch (Exception ex)
        {
            Disconnect();
        }
    }

    public void Disconnect()
    {
        // Disconnect Client
    }


}

И отправка данных с сервера на одинили все клиенты:

public void SendDataToAll(byte[] data)
    {
        BinaryWriter writer;

        try
        {
            foreach (IClientConnection connection in connections)
            {
                writer = new BinaryWriter(connection.TcpClient.GetStream());
                writer.Write(data);
                writer.Flush();
            }
        }
        catch (Exception ex)
        {
            // Log
        }
    }

    public void SendDataToOne(IClientConnection client, byte[] data)
    {
        BinaryWriter writer;

        try
        {
            writer = new BinaryWriter(client.TcpClient.GetStream());
            writer.Write(data);
            writer.Flush();
        }
        catch (Exception ex)
        {
            // Log
        }
    }

В какой-то момент происходит сбой сервера, и у меня действительно не было отправной точки, где даже искать проблему.При необходимости я могу предоставить больше кода.

Любая помощь очень ценится :-) Андрей

Ответы [ 2 ]

1 голос
/ 08 сентября 2010

Вы должны сделать доступ к потоку поля безопасным.

В SendData вы перебираете соединения и отправляете данные каждому клиенту. Если новый клиент подключается во время выполнения цикла foreach, вы получите исключение с сообщением «Коллекция была изменена; операция перечисления может не выполняться», поскольку коллекция изменяется во время итерации по ней, что недопустимо.

Изменить строку в SendDataToAll на

foreach (IClientConnection connection in connections.ToList())

для устранения проблемы (решение предоставлено Коллекция была изменена; операция перечисления может не выполняться ).

0 голосов
/ 08 сентября 2010

Возможно, что вызов Disconnect в блоке catch метода ClientConnection.ReceiveMessage выдает исключение, которое затем распространяется из перехвата и не обрабатывается.

Чтобы быть уверенным в перехвате всех исключений и их регистрации, попробуйте зарегистрировать обработчик событий в событии AppDomain.CurrentDomain.UnhandledException. Кроме того, если вы используете сервер в качестве службы Windows, в журнале событий приложений может быть запись об исключении .NET.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...