Обмен данными с сокетами в среде локальной сети

#c# #tcpsocket

#c# #tcpsocket

Вопрос:

У меня есть следующая настройка:

Сервер будет подключаться через Bluetooth к нескольким устройствам, которые посылают дискретный сигнал. Тогда будет n клиентов, которые могут запрашивать сервер (возможно, через веб-службы), к каким устройствам подключены, и прослушивать сигнал с нужных им устройств.

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

Но у меня возникли некоторые проблемы с реализацией сокета. Как я могу создать и записать сигнал на локальный порт?

Это то, что я получил до сих пор:

 class Device {
    ...
    public EndPoint Connect() {
        // create a bt connection to the device

        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        var endPoint = new IPEndPoint(IPAddress.Parse(_localIp), 0);
        _socket.Bind(endPoint);

        return endPoint;
    }

    private void OnBtDataReceived(object sender, wclDataEventArgs e) {
        _socket.Send(e.Data);
    }
}
  

Но при достижении _socket.Отправить (например, данные); я получаю следующее исключение:

Запрос на отправку или получение данных был запрещен, поскольку сокет не подключен и (при отправке в сокет дейтаграммы с использованием вызова sendto) адрес не был указан

Это правильный подход, но для чтения данных кто-то должен быть подключен к сокету?

Комментарии:

1. Как указано в ошибке — сокет не имеет соединения… что вы хотите, чтобы сокет делал с данными, которые вы отправляете? буферизовать его? отказаться от него?

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

3. Если потеря данных допустима, я бы настоятельно рекомендовал широковещательную передачу UDP (которая является «бесконтактной») — она больше похожа на «радио», и тому, кто хочет слушать, нужно только знать, какой порт прослушивать…

4. Да, либо используйте UDP, который является протоколом без установления соединения, как предложил Яхиа; или вы можете буферизировать данные в MemoryStream (или какой-либо другой механизм буферизации), а затем отправлять их при подключении клиента. Если вы хотите «отправить и забыть», как только будут получены данные BT, то я думаю, что UDP — это правильный путь.

5. Спасибо @Yahia и Parmenion, собираюсь прочитать некоторую документацию по трансляции UDP и попробовать.

Ответ №1:

Вы можете использовать широковещательную передачу UDP, как следует из комментариев, где вам не нужно устанавливать соединение. Сервер просто отправляет данные на один порт, и любой заинтересованный клиент может получить эти данные на этом порту.

Если вы хотите различать свои устройства, вам, возможно, придется передавать данные каждого устройства на отдельный порт. Это может быть много (ненужного) сетевого трафика, когда у вас много устройств.

Другой вариант — использование TCP. Ваш сервер для прослушивания входящих подключений от ваших клиентов:

 _socket.Bind(new IPEndPoint(IPAddress.Any, 1234));
_socket.Listen(10);
_socket.BeginAccept(onAccept, _socket);
  

В onAccept у вас есть доступ к clientsocket и вы можете отправлять данные или сохранять ссылку на сокет где-нибудь для последующей отправки данных:

 private static void onAccept(IAsyncResult ar)
{
    Socket clientSocket = ((Socket) ar.AsyncState).EndAccept(ar);

    // begin to accept the next client connection
    _socket.BeginAccept(onAccept, _socket);

    // this is the socket you can send data to the connected client:
    clientSocket.Send(data);
}
  

Преимущество подхода TCP заключается в том, что ваш сервер отправляет данные только тогда, когда есть подключенные клиенты, и вашему серверу известно количество подключенных клиентов.

Комментарии:

1. Я хочу различать устройства, но в худшем случае это 7, поскольку BT не разрешает больше подключений. Подход TPC кажется достаточно простым.

Ответ №2:

При использовании TCP вам не нужно вызывать Bind() , но вам нужно вызвать Connect() .

 _socket.Connect(endPoint);
  

Предполагается, что в вашем коде _localIp указан IP-адрес в локальной сети, к которой вы хотите подключиться, а не IP-адрес сетевого адаптера на локальном компьютере, который вы хотите использовать для подключения.

Что Bind() нужно, так это привязать сокет к локальной (т. Е. На текущем компьютере) конечной точке. Если вам все равно, какой сетевой адаптер используется (что означает, что вы позволяете системе решать это на основе целевого IP-адреса), и вам также все равно, какой локальный порт используется, нет необходимости вызывать Bind() .

Комментарии:

1. _localIp — это IP-адрес локального компьютера. Я использую bind() для назначения свободного порта на текущем компьютере. Мне все равно, какой порт используется, я просто хочу, чтобы свободный порт отправлял туда данные, чтобы другие компьютеры могли их получать.