Для отправки через сокет требуется задержка для цели localhost - PullRequest
0 голосов
/ 24 марта 2019

В данный момент я работаю над проектом C / server / client и столкнулся со странной проблемой, решение которой заняло у меня некоторое время, но я не совсем доволен решением или, более точно, зачем мне это нужно.По сути, я обнаружил, что отправка сообщений сокета tcp более 10 Кбайт на локальный хост требует задержки в 1 мс.

В качестве фона у меня есть сервер на компьютере, к которому подключаются многие клиенты и передают информацию туда и обратно, и всеКажется, работает нормально.У меня также есть клиенты, которые являются локальными по отношению к серверу, который также подключается. Проблема, с которой я столкнулся, заключалась в том, что, когда размеры сообщений превышали ~ 10 КБ, сообщения не проходили.Я только что заметил это, потому что большинство отправленных сообщений были размером около 1-2 КБ, но клиент, подключенный к тому же компьютеру, что и сервер (localhost), является в большей степени клиентом для управления и поэтому отправляет / получает больше данных.

Настоящая проблема заключалась в том, что сервер (отправитель) возвращал истину / успех из команд отправки C # о том, что данные отправляются, однако получатель указал, что пройдет только первый чанк (если я буферизовал) или ничего не произошло.Поэтому я закончил тем, что включил wireshark и увидел, что, хотя отправка вызовов завершена успешно, никакие данные на самом деле не будут отправляться по проводной связи (помня об этом на локальном интерфейсе обратной связи).отправляю данные и пробую все разные вызовы (NetworkStream.Write / NetworkStream.WriteAsync / Socket.Send / Socket.SendAsync / Socket.BeginSend) вместе с буферизацией данных или отправляю их все одним нажатием.Казалось, ничто не имеет значения, пока я не установлю задержку между вызовами отправки в цикле, тогда все будет работать идеально (я протестировал до 1,5 ГБ потока данных без проблем).

Я также нашел задержкучто-то меньше 1 мс / 10000 тиков снова вызовет проблемы, я получу так много звонков на работу, что они просто остановятся снова.Установка TcpClient.NoDelay в true также, похоже, не оказала большого влияния.

Ниже приведен фрагмент моего кода отправки в качестве примера с различными командами отправки, которые я пробовал, что все они имеют одинаковое поведение.

// _client is an abstracted/based off a TcpClient object (the target)
byte[] dataBytes = Serializer.SerializeMessage(message); 
int    bytesSent = 0;

while (bytesSent < dataBytes.Length) {
   int bytesToSend = ((dataBytes.Length - bytesSent) < 8192) ? (dataBytes.Length - bytesSent) : 8192;
   //_client.Socket.Send(dataBytes, bytesSent, bytesToSend, SocketFlags.Partial);
   //_client.NetworkStream.Write(dataBytes, bytesSent, bytesToSend);
   //_client.Socket.BeginSend(dataBytes, bytesSent,bytesToSend,SocketFlags.None, ar => {int bytes = ((Socket)ar.AsyncState).EndSend(ar);}, _client.Socket);
   _ = _client.NetworkStream.WriteAsync(dataBytes, bytesSent, bytesToSend);

   bytesSent += bytesToSend;
   Thread.Sleep(TimeSpan.FromTicks(10000));
}

Так что, хотя сейчас это работает нормально, мой вопрос - зачем это вообще нужно, из предыдущего опыта я всегда нахожу, что если вам нужно «отложить», есть что-то еще, что не так.Кроме того, без задержки ничего не выводится, во всех отчетах о вызовах они успешно отправили байты, но wireshark не показывает передаваемых данных.Я думал только о том, что в библиотеке что-то обнаружит, что это локальная цель, и использует какой-то внутренний по имени абстрагированный от меня канал и где-то заполнится буфер?

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

Ответы [ 2 ]

0 голосов
/ 30 марта 2019

Таким образом, проблема оказалась в том, что что-то на самом компьютере (или, точнее, на некоторых наших устройствах разработки) оказало влияние на любую службу, размещаемую / подключаемую на привязке локального хоста. Это включало ряд сетевых сервисов, включая даже IISExpress и IIS, если хостинг был локальным. Это приводит к тому, что любые данные размером более ~ 10 Кбайт никогда не отправляются / не принимаются.

После нескольких дней попыток выяснить, что влияло на соединения с локальным хостом, мы закончили перестраивать наши dev-боксы, и проблема теперь исчезла (хотя мы до сих пор не знаем, почему / что вызвало проблему).

0 голосов
/ 24 марта 2019

из предыдущего опыта Я всегда нахожу, что если вам нужно «задержать», то есть что-то еще не так.

Право.Здесь я подозреваю, что вы предполагаете, что чтение на сокете вернет полное сообщение.

Но TCP / IP - это потоковый протокол, который не включает в себя понятие сообщений.Чтобы успешно использовать TCP / IP напрямую, вы должны определить «протокол формирования сообщений», чтобы сообщить удаленному хосту, сколько байтов ожидать.Я не вижу, чтобы вы что-то писали перед сообщением, поэтому я подозреваю, что этого не хватает.

Простое решение, которое используют многие люди, - это всегда отправлять 4-байтовое целое число в начале сообщения, указывающего номербайтов, которые будут отправлены.Затем считыватель может выполнить 4-байтовое чтение, после чего следует цикл чтения, пока не будет прочитано ожидаемое количество байтов.

...