Foothill Ответов: 0

Сокеты C# - можно ли их использовать повторно


Я все еще разбираюсь в этой низкоуровневой сетевой связи, так что потерпите.

В среде клиент-сервер (простое приложение для чата) с несколькими "подключенными" клиентами можно ли повторно использовать один и тот же сокет для трансляции сообщения всем клиентам? Я ставлю connected в кавычки, поскольку ни один клиент не поддерживает TCP-соединение на своем собственном сокете, но сервер поддерживает список IP-адресов/портов, которые прослушивают клиентские приложения. Я просто пытаюсь заставить широковещательную функцию работать и буду беспокоиться об обработке отключенных клиентов позже.

Теперь, когда подключен только один клиент, этот код работает просто отлично. Как только подключается другой клиент,он умирает, когда пытается выполнить цикл.
private void TransmitToAll(byte[] message)
{
 Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 foreach (ChatConnection conn in _connectedClients)
 {
   // it gets through one loop and dies here on the second attempt.
   soc.Connect(conn.Address, 25001);

   soc.Send(message);

   soc.Disconnect(true);
 }

 soc.Dispose();
}

Ошибка, которую он мне дает, такова:

Как только сокет был отключен, вы можете снова подключиться только асинхронно и только к другой конечной точке. BeginConnect должен быть вызван в потоке, который не выйдет до тех пор, пока операция не будет завершена.

Для этой первой попытки я хотел бы сохранить синхронный широковещательный процесс, поэтому использование асинхронных сокетов пока не обсуждается (это будет позже).

Что я уже пробовал:

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

Kornfeld Eliyahu Peter

Чтобы убедиться, что все данные отправлены и получены до закрытия сокета, вы должны вызвать Shutdown перед вызовом метода Disconnect.

Если вам нужно вызвать Disconnect без предварительного вызова Shutdown, вы можете установить для параметра DontLingerSocket значение false и указать ненулевой интервал тайм-аута, чтобы обеспечить отправку данных, поставленных в очередь для исходящей передачи. Затем отключите блоки до тех пор, пока данные не будут отправлены или пока не истечет указанный тайм-аут. Если вы установите DontLinger в false и укажете нулевой интервал тайм-аута, Close разблокирует соединение и автоматически отбросит исходящие данные в очереди.

https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.disconnect (v=vs. 110). aspx

Foothill

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

Мне удалось заставить его работать с шаблоном create->send->confirm->close, но если сервер заканчивается подключением десятков клиентов, кажется очень неэффективным создавать целый новый сокет только для того, чтобы отправить немного текста всем клиентам.

Kornfeld Eliyahu Peter

Если я подумаю во второй раз, ваша проблема заключается в том, что сервер соединяет клиентов, а не просто принимает соединения...

Foothill

Да, я начинаю думать, что то, что я пытаюсь сделать, просто невозможно с TCP/IP. Я думаю, что было бы лучше переключиться на UDP, чтобы я мог использовать сокет в режиме "огонь и забудь" для трансляции всем клиентам.

0 Ответов