Веб-серверный клиент Python для сервера mWebSocket

#python #html #sockets #websocket #arduino

Вопрос:

Я пытаюсь создать клиент WebSocket на python, который каждую секунду подключается к Arduino Uno по кабелю Ethernet, на котором установлен сервер WebSocket, основанный на библиотеке mWebSocket. Рабочий код Arduino показан ниже:

 #include <WebSocketServer.h>
using namespace net;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[]{0xA8, 0x61, 0x0A, 0xAE, 0x69, 0x13};
IPAddress ip(198, 162, 1, 177);
IPAddress gateway(0,0,0,0);
IPAddress DNSserver(0,0,0,0);
IPAddress subnet(255,255,255,0);

constexpr uint16_t port = 80;
WebSocketServer wss{port};

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  
  Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy   2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Ethernet WebServer Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac,ip,DNSserver,gateway,subnet);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());

  wss.onConnection([](WebSocket amp; ws) {
    const auto protocol = ws.getProtocol(); 
    if (protocol) {
      Serial.print(F("Client protocol: "));
      Serial.println(protocol);
    }

    ws.onMessage([](WebSocket amp; ws, const WebSocket::DataType dataType,
    const char *message, uint16_t length) {
      switch (dataType) {
        case WebSocket::DataType::TEXT:
          Serial.print(F("Received: "));
          Serial.println(message);
          break;
        case WebSocket::DataType::BINARY:
          Serial.println(F("Received binary data"));
          break;
      }

      ws.send(dataType, message, length);
    });

    ws.onClose([](WebSocket amp;, const WebSocket::CloseCode, const char *,
    uint16_t) {
      Serial.println(F("Disconnected"));
    });

    Serial.print(F("New client: "));
    Serial.println(ws.getRemoteIP());

    const char message[] {"Hello from Arduino server!"};
    ws.send(WebSocket::DataType::TEXT, message, strlen(message));
  });

  wss.begin();
  Serial.println(Ethernet.localIP());
}

void loop() {
  wss.listen();
}
 

Я создал клиент сокета python для взаимодействия с этим Arduino и, надеюсь, распечатываю сообщение «Привет с сервера Arduino!» клиенту при каждом подключении.

 #!/usr/bin/python3
import asyncio
import websockets
import socket
import time
import datetime
import struct

starttime = time.time() # start value for timed data acquisition

# setup socket 1
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect(("198.162.1.177",80))
s1.sendall(b'GET / HTTP/1.1 400')
if True:
    print('Connected')
def acquire():
    
    data = s1.recv(10000)
    print(data)
        
while True:
   acquire()
   time.sleep(1.0 - ((time.time() - starttime) % 1.0)) # continue every  (2.0 seconds)

s1.close()
 

Однако, когда я запускаю приведенный выше код. Я получаю:

 Connected
b'H'
b'TTP/1.1 400 Bad Requestrn'
b''
b''
b''
b''
b''
 

Что я здесь упускаю, я предполагаю, что соединение не полностью установлено, хотя я могу пропинговать Arduino со своего компьютера. Нужно ли мне по-другому учитывать HTTP-заголовок для клиента WebSocket?

Ответ №1:

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

Кроме того, поскольку вы импортируете веб-пакеты в свой клиентский код. Вы можете использовать функции библиотеки, которые выполняют эту работу за вас, и вы просто делаете запрос GET с «ws/wss», указанным в URL-адресе вашего запроса.

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

1. Хорошо, я вижу, я довольно новичок в общении с сокетами, так что мне нужно добавить в скрипт python?