VB.NET Асинхронные пакеты сокетов теряются

#.net #vb.net #sockets #asynchronous #packet-loss

#.net #vb.net #сокеты #асинхронный #потеря пакетов

Вопрос:

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

Вот код клиента в PasteBin. Он показывает, как клиент подключается к серверу, а затем отправляет 100 сообщений в цикле For на сервер.

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

Ответ №1:

Я также ответил на ваш вопрос на reddit, но решил, что отвечу здесь на случай, если кто-то еще ищет подобные вещи.

У вас две проблемы с тем, как ваш сервер обрабатывает чтения. Прежде всего, конструктор вашего клиентского объекта:

 Public Sub New(ByVal client As TcpClient)
    'New client connects
    Me.client = client
    client.GetStream().BeginRead(New Byte() {0}, 0, 0, AddressOf Read, Nothing)
End Sub
  

BeginRead ожидает, что вы будете собирать свои данные таким образом, чтобы их можно было передать методу обратного вызова; в данном случае «Read». Как правило, это делается путем создания нового объекта для хранения «Состояния» этой асинхронной операции и передачи его в качестве последнего параметра для BeginRead . Ваш вызов метода здесь создает новый массив байтов, но не содержит ссылки на него для передачи в качестве последнего аргумента метода. Это означает, что данные, которые считываются этим вызовом, просто исчезнут после чтения, поскольку они никогда не передаются в метод для их хранения.

Во-вторых, ваша операция чтения:

 Public Sub Read(ByVal ar As IAsyncResult)
    Dim reader As New StreamReader(client.GetStream())
    clientPacket amp;= reader.ReadLine()
    client.GetStream().BeginRead(New Byte() {0}, 0, 0, AddressOf Read, Nothing)
End Sub
  

Поскольку вы не передаете данные, которые были прочитаны в асинхронном вызове, вы создаете здесь новый StreamReader для получения дополнительных данных от клиента. Это не асинхронный вызов метода. Ваш вызов reader.ReadLine() будет блокироваться до тех пор, пока не будет обнаружена новая строка, после чего данные будут добавлены в clientPacket. Затем вы снова вызываете BeginRead с той же проблемой, что и указано выше, что означает, что вы потеряете больше данных.

Кроме того, вы никогда не очищаете свои объекты AsyncResult, вызывая EndRead() в потоке, что в конечном итоге приведет к нехватке ресурсов, когда среда CLR исчерпает рабочие потоки для ваших асинхронных операций.

Вот пример того, как я бы реализовал такую задачу. Это на C #, так как это то, что мне больше всего нравится, так что извините за это. 😉

Клиентский код

Серверный код

Я надеюсь, что это поможет!