ESP32与自设计的Socket服务器通信

以下示例分别为EPS32连接笔记本已经运行socket服务器(确保在同一局域网内),ESP32自己作为服务器,笔记本通过C++实现socket服务搭建。

当您使用ESP32与Socket服务器通信时,需要执行以下步骤:

首先,您需要使用WiFi库连接到无线网络。在上面的示例中,使用了WiFiMulti类,它允许您添加多个可用的WiFi网络,并尝试连接到它们中的任何一个。

一旦连接到WiFi网络,您需要使用WiFiClient库与服务器建立TCP连接。在此示例中,我们将服务器的IP地址和端口硬编码为常量,但您可以根据需要进行更改。如果连接成功,您可以开始向服务器发送数据并接收响应。

为了使发送和接收数据过程异步运行,我们在此示例中使用了两个Thread对象。每个Thread对象都具有一个onRun方法,该方法定义要在线程中重复执行的代码。在此示例中,sendThread.onRun指定将数据发送到服务器的方法,而receiveThread.onRun指定从服务器接收数据的方法。

在setup函数中,我们启动这两个线程并设置它们的运行间隔。在此示例中,将其设置为5秒钟。通过将线程的enabled属性设置为true,我们确保线程在启动后立即开始运行。

在 sendData 和 receiveData 方法中,我们检查客户端连接是否仍然存在。如果连接仍然存在,则发送或接收数据。否则,我们打印错误消息并尝试重新连接服务器。如果重新连接成功,则继续发送或接收数据,否则我们将继续等待下一次运行。请注意,在发送数据时,您可以使用client.print或client.write方法来将数据发送到服务器。在接收到响应后,您可以使用client.available和client.readStringUntil方法解析服务器的响应。

最后,在loop函数中什么都没有做,因为我们在两个线程中处理所有的发送和接收数据操作。

需要注意的是,由于Arduino是单线程的,因此Thread对象实际上不会在不同的核心上并行运行。但是,它们仍然可以帮助您将发送和接收数据过程分离开来,并使代码更具可读性和易于维护。

#include 
#include 
#include 
#include 

const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

IPAddress serverIP(192, 168, 1, 100); // Socket服务器的IP地址
int serverPort = 8080; // Socket服务器的端口

WiFiMulti wifiMulti;
WiFiClient client;

Thread sendThread = Thread();
Thread receiveThread = Thread();

void setup() {
  Serial.begin(115200);
  
  wifiMulti.addAP(ssid, password);

  while (wifiMulti.run() != WL_CONNECTED) {
    delay(100);
  }

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  if (!client.connect(serverIP, serverPort)) {
    Serial.println("Connection failed.");
  }
  else {
    Serial.println("Connected to server.");
    sendThread.onRun(sendData);
    receiveThread.onRun(receiveData);
    sendThread.setInterval(5000);
    receiveThread.setInterval(5000);
    sendThread.enabled = true;
    receiveThread.enabled = true;
  }
}

void loop() {
  // nothing to do here
}

void sendData() {
  if (client.connected()) {
    // 在此处添加要发送给服务器的数据
    String dataToSend = "Hello, Server!";
    client.print(dataToSend);
    Serial.println("Sent data to server.");
  }
  else {
    Serial.println("Connection lost. Reconnecting...");
    client.stop();
    if (client.connect(serverIP, serverPort)) {
      Serial.println("Reconnected to server.");
    }
    else {
      Serial.println("Reconnection failed.");
    }
  }
}

void receiveData() {
  if (client.connected()) {
    while (client.available()) {
      // 在此处解析从服务器接收到的数据
      String dataReceived = client.readStringUntil('\n');
      Serial.println("Received data from server: " + dataReceived);
    }
  }
  else {
    Serial.println("Connection lost. Reconnecting...");
    client.stop();
    if (client.connect(serverIP, serverPort)) {
      Serial.println("Reconnected to server.");
    }
    else {
      Serial.println("Reconnection failed.");
    }
  }
}

 在这个示例中,我们使用WiFiServer库创建了一个TCP服务器,监听本地网络上的指定端口。在setup函数中,我们启动WiFi连接并开始监听客户端连接。

在loop函数中,我们使用server.available方法检查是否有新的客户端连接。如果有,我们打印一条消息,然后进入一个while循环,该循环在客户端连接关闭之前一直运行。在循环中,我们使用client.available和client.readStringUntil方法从客户端接收数据,并将其打印到串口。然后,我们在此处构造响应并使用client.print方法将其发送回客户端。

需要注意的是,在处理客户端连接时,您可能需要添加适当的错误检查和处理代码。例如,如果客户端在向服务器发送数据时突然断开连接,您的代码可能会陷入无限循环,因为它仍然等待客户端发送更多数据。因此,您需要确保您的代码具有恰当的超时和错误处理机制,以便在不同的情况下正确地处理连接。

#include 
#include 
#include 

const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

WiFiServer server(8080); // 服务器监听的端口号

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
  }

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();

  if (client) {
    Serial.println("New client connected.");
    
    while (client.connected()) {
      if (client.available()) {
        // 在此处解析从客户端接收到的数据
        String dataReceived = client.readStringUntil('\n');
        Serial.println("Received data from client: " + dataReceived);
        
        // 在此处发送响应给客户端
        String response = "Hello, Client!";
        client.print(response);
        Serial.println("Sent data to client.");
      }
    }
    
    Serial.println("Client disconnected.");
  }
}

 这个示例代码使用了Windows套接字API(Winsock)来创建一个简单的TCP服务器。在main函数中,我们初始化Winsock并创建一个SOCKET对象来监听来自客户端的连接。

在通过bind方法将IP地址和端口号绑定到SOCKET对象后,我们使用listen方法开始监听传入的连接。然后,我们使用accept方法等待客户端连接。一旦客户端连接,我们打印一条消息并进入一个while循环,在该循环中接收来自客户端的数据和发送响应。

在Visual Studio 2019中配置这个例子非常简单。只需按照以下步骤操作:

创建一个新的空项目。
在“解决方案资源管理器”窗口中,右键单击项目名称并选择“属性”选项。
在左侧窗格中选择“C/C++”和“预处理器”选项卡。
在“预处理器定义”框中添加宏_WIN32_WINNT=0x0601,以便支持Windows Sockets版本2。
在左侧窗格中选择“链接器”和“输入”选项卡。
在“附加依赖项”框中添加ws2_32.lib库文件。

点击“应用”按钮,然后点击“确定”按钮。
完成上述步骤后,您可以将C++代码粘贴到源文件中并构建项目。如果一切顺利,您应该能够在Windows上运行一个简单的TCP服务器。

需要注意的是,为了避免防火墙和安全软件的干扰,您可能需要在Windows防火墙中添加一个入站规则,以允许传入的连接通过所选端口。此外,如果您需要在不同的机器之间进行通信,则需要确保它们都在同一个网络上,并且客户端始终能够连接到服务器的IP地址和端口号。

#include 
#include 
#include 
#include 

#pragma comment(lib, "ws2_32.lib")

int main() {
    // 初始化Winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    int wsOk = WSAStartup(ver, &wsData);
    if (wsOk != 0) {
        std::cerr << "Can't initialize Winsock! Quitting" << std::endl;
        return 1;
    }

    // 创建socket
    SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET) {
        std::cerr << "Can't create a socket! Quitting" << std::endl;
        return 1;
    }

    // 绑定IP地址和端口号
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(8080);
    hint.sin_addr.S_un.S_addr = INADDR_ANY;

    bind(listening, (sockaddr*)&hint, sizeof(hint));

    // 开始监听
    listen(listening, SOMAXCONN);

    // 等待连接
    sockaddr_in client;
    int clientSize = sizeof(client);
    char host[NI_MAXHOST];
    char service[NI_MAXSERV];

    SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);

    ZeroMemory(host, NI_MAXHOST);
    ZeroMemory(service, NI_MAXSERV);

    if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
        std::cout << host << " connected on port " << service << std::endl;
    }
    else {
        inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
        std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
    }

    // 与客户端通信
    char buf[4096];

    while (true) {
        ZeroMemory(buf, 4096);

        int bytesReceived = recv(clientSocket, buf, 4096, 0);
        if (bytesReceived == SOCKET_ERROR) {
            std::cerr << "Error in recv(). Quitting" << std::endl;
            break;
        }

        if (bytesReceived == 0) {
            std::cout << "Client disconnected." << std::endl;
            break;
        }

        std::cout << "Received data from client: " << std::string(buf, 0, bytesReceived) << std::endl;

        // 发送响应给客户端
        std::string response = "Hello, Client!";
        send(clientSocket, response.c_str(), response.size() + 1, 0);
    }

    // 关闭socket
    closesocket(clientSocket);

    // 清理Winsock
    WSACleanup();

    return 0;
}

 

你可能感兴趣的:(笔记,网络,物联网)