Обзор: Я настроил сервер и клиент, где оба пытаются обнаружить друг друга с помощью UDP. Когда сервер запускается, он отправляет многоадресное сообщение (239.1.1.1), что он жив. Когда клиент запускается, он отправляет многоадресное сообщение (239.1.1.2), что он жив. И сервер, и клиент подписаны на многоадресные сообщения друг друга для получения своих передач. Таким образом, независимо от того, какое приложение (сервер или клиент) запускается первым, одно или другое будет уведомлено об их существовании.
На стороне клиента я делаю следующее:
- Настройка прослушивающего сокета для подписки и получения многоадресных сообщений от сервера.
- Настройка приемного сокета для получения ответов сервера на многоадресную рассылку клиента
сообщение за № 3 ниже.
- Отправка сообщения многоадресной рассылки (для приема и ответа сервера), на котором работает клиент.
- Получение ответа сервера на многоадресное сообщение клиента, отправленное в # 3.
Вопрос: Все работает нормально, за исключением того, что оба принимающих сокета в итоге получают ответ сервера (не многоадресный) на клиент. Мне не ясно, ожидается ли это поведение или нет. Можно ли уменьшить два приемных разъема до одного? # 1 подписан на многоадресную рассылку сервера, а # 2 просто прослушивает прямую передачу с сервера на тот же порт (не-многоадресное сообщение от сервера). Можно ли безопасно удалить вторую приемную розетку?
См. Исходный код ниже (я удалил обработку исключений для упрощения представления кода).
Код клиента:
// 1. Set up a socket and asynchronously listen for server startup multicasts.
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
listenSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, 1);
listenSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
listenSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse("239.1.1.1")));
EndPoint clientEndPoint = new IPEndPoint(0, 0);
listenSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, ref clientEndPoint,
new AsyncCallback(OnServerMessageReceived), (object)this);
// 2. Set up socket to receive the server's response to client's multicast.
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
receiveSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, 1);
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
receiveSocket.ReceiveTimeout = 3000; // Timeout after 3 seconds.
// 3. Send a multicast message for server to respond to.
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
EndPoint multicastEndPoint = new IPEndPoint(IPAddress.Parse("239.1.1.2"), 50000);
sendSocket.SendTo(packet, packet.Length, SocketFlags.None, multicastEndPoint);
// 4. Wait for server to respond to the multicast message (timeout = 3 seconds).
byte[] receiveBuff = new byte[2048];
EndPoint serverEndPoint = new IPEndPoint(0, 0);
int bytesRead = receiveSocket.ReceiveFrom(receiveBuff, ref serverEndPoint);
Код сервера:
// Receive multicast message sent from client (in asynchronous callback method).
EndPoint clientEndPoint = new IPEndPoint(0, 0);
int bytesRead = listenSocket.EndReceiveFrom(asyncResult, ref clientEndPoint);
// Send response back to the client (change port to 50000).
EndPoint destination = new IPEndPoint((clientEndPoint as IPEndPoint).Address,
50000);
Socket responseSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
responseSocket.SendTo(response, response.Length, SocketFlags.None, destination);