首页 > 其他分享 >Flutter局域网广播(UDP通信)与TCP通信

Flutter局域网广播(UDP通信)与TCP通信

时间:2024-09-19 19:22:50浏览次数:3  
标签:UDP socket 通信 TCP serverSocket print 服务器 客户端

前言

现在有一个需求,手机和ESP32通过WIFI进行通信。流程如下:

  • 手机创建TCP服务器
  • 手机向192.168.0.255的1002端口广播自己的ip地址以及TCP服务器的端口号
  • ESP32监听到1002的广播内容后,连接手机的TCP服务器。
  • 最后就是ESP32硬件和TCP服务器进行数据收发

因此我们要了解Flutter如何使用UDP进行广播、如何创建TCP服务器以及通过TCP进行通信

验证工具

假如我们代码写好了,和硬件直接调试发现出现了错误,我们就无法定位是Flutter的代码问题还是硬件的问题。因此需要一个验证工具来验证是哪方面出现了问题

这里我们使用验证工具是“山外多功能调试助手”

模拟TCP服务器

  • 打开山外多功能调试助手
  • 点击网络调试助手,再点击TCP服务器

  • 输入端口号点击监听,硬件根据ip地址和端口号进行连接,在消息区我们可以看到是否有设备连接

  • ESP32能够连接这个软件说明错误问题在手机程序中

模拟TCP客户端

  • 前端创建好了TCP服务端后,可以通过这个软件进行连接测试
  • 打开“山外多功能调试助手”,点击网络调试助手,点击TCP客户端
  • 输入服务器IP地址以及端口号,点击连接后查看消息是否连接成功

如果能够连接成功则说明我们的TCP服务器创建成功

模拟UDP广播

  • 点击网络调试助手——>点击UDP,输入广播的端口号后点击连接
  • 手机程序发送一个广播,在消息区可以看到广播的内容

创建TCP服务器

要在Flutter中创建TCP服务器,您可以使用dart:io库中的ServerSocket类。

下面代码使用ServerSocket.bind()方法绑定服务器的地址和端口。然后,我们使用server.listen()来监听来自客户端的连接。当客户端连接到服务器时,我们打印连接信息并向客户端发送欢迎消息。

接下来,我们通过socket.listen()来监听客户端发送的数据。当接收到数据时,我们打印收到的消息,并向客户端发送回复消息。如果在接收数据时出现错误或客户端断开连接,我们关闭与客户端的连接。

startServer() async {
  try {
    _serverSocket?.close();
    _serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, 5556);
    print( '服务器已启动,地址:${_serverSocket?.address.address}:${_serverSocket?.port}');
    _serverSocket?.listen(serverOnReceive);
  } catch (e, stackTrace) {
    print('e---------:$e');
  }
}
serverOnReceive(Socket socket) {
  _socket = socket;
  print('客户端已连接: ${socket.remoteAddress}:${socket.remotePort}');
  socket.writeln('欢迎连接到服务器'); // 向客户端发送欢迎消息
 
  _socket?.listen(
    (data) {
      print('接收到客户端消息: $data');
      socket.writeln('服务器收到消息: $data'); // 回复客户端收到的消息
    },
    one rror: (error) {
      print('接收数据时出现错误: $error');
      socket.close(); // 关闭与客户端的连接
    },
    onDone: () {
      print('客户端已断开连接');
      socket.close(); // 关闭与客户端的连接
    },
  );
}

局域网广播

权限设置

android

在Flutter中发送广播消息所涉及的权限取决于您的目标平台和网络环境。以下是一些常见的权限,您可能需要在Flutter应用程序中配置以发送广播消息:

对于Android平台:

  • android.permission.INTERNET:用于访问互联网。
  • android.permission.ACCESS_NETWORK_STATE:用于访问网络状态信息。
  • android.permission.ACCESS_WIFI_STATE:用于访问Wi-Fi状态信息。
  • android.permission.CHANGE_WIFI_MULTICAST_STATE:用于更改Wi-Fi多播状态。
对于ios平台
  • NSLocalNetworkUsageDescription:描述应用程序使用本地网络的目的,添加该键值对到应用程序的Info.plist文件中。

示例Info.plist文件中的键值对配置部分:

<key>NSLocalNetworkUsageDescription</key>

<string>需要使用本地网络以发送广播消息。</string>
具体代码

在Flutter中,可以使用dart:io库中的RawDatagramSocket类来发送广播消息。以下是一个简单的示例代码,演示如何在Flutter中发送广播消息:

void sendBroadcastMessage() {
  String message = 'BB192.168.0.174:5556';
  print(utf8.encode(message));
  RawDatagramSocket.bind(InternetAddress.anyIPv4, 0)
      .then((RawDatagramSocket socket) {
    rawDatagramSocket = socket;
    var broadcastAddr = InternetAddress('255.255.255.255');
    var port = 1002; // 广播目标端口
 
    socket.broadcastEnabled = true;
 
    socket.send(utf8.encode(message), broadcastAddr, port);
 
    socket.close();
  }).catchError((error) {
    print('发送广播消息时出现错误: $error');
  });
}

全部代码

import 'dart:convert';
import 'dart:io';
 
import 'package:flutter/material.dart';
 
ServerSocket? _serverSocket;
Socket? _socket;
RawDatagramSocket? rawDatagramSocket;
 
class TCPServe extends StatefulWidget {
  const TCPServe({super.key});
 
  @override
  State<TCPServe> createState() => _TCPServeState();
}
 
class _TCPServeState extends State<TCPServe> {
  startServer() async {
    print("InternetAddress.anyIPv4:${InternetAddress.loopbackIPv4}");
    try {
      _serverSocket?.close();
      // _serverSocket = await ServerSocket.bind("localhost", 1234);
      _serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, 5556);
 
      print(
          '服务器已启动,地址: ${_serverSocket?.address.address}:${_serverSocket?.port}');
      _serverSocket?.listen(serverOnReceive);
    } catch (e, stackTrace) {
      print('e---------:$e');
    }
  }
 
  serverOnReceive(Socket socket) {
    _socket = socket;
    print('客户端已连接: ${socket.remoteAddress}:${socket.remotePort}');
    socket.writeln('欢迎连接到服务器'); // 向客户端发送欢迎消息
 
    _socket?.listen(
      (data) {
        print('接收到客户端消息: $data');
        socket.writeln('服务器收到消息: $data'); // 回复客户端收到的消息
      },
      one rror: (error) {
        print('接收数据时出现错误: $error');
        socket.close(); // 关闭与客户端的连接
      },
      onDone: () {
        print('客户端已断开连接');
        socket.close(); // 关闭与客户端的连接
      },
    );
  }
 
  clean() async {
    await _socket?.close();
    print("_socket关闭");
    await _serverSocket?.close();
    print("_serverSocket关闭");
  }
 
  void sendBroadcastMessage() {
    String message = 'BB192.168.0.174:5556';
    print(utf8.encode(message));
    RawDatagramSocket.bind(InternetAddress.anyIPv4, 0)
        .then((RawDatagramSocket socket) {
      rawDatagramSocket = socket;
      var broadcastAddr = InternetAddress('255.255.255.255');
      var port = 1002; // 广播目标端口
 
      socket.broadcastEnabled = true;
 
      socket.send(utf8.encode(message), broadcastAddr, port);
 
      socket.close();
    }).catchError((error) {
      print('发送广播消息时出现错误: $error');
    });
  }
 
  cleanRawDatagramSocket() {
    rawDatagramSocket?.close();
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("TCP服务端测试")),
      body: Center(
        child: Column(
          children: [
            TextButton(
              onPressed: startServer,
              child: const Text("创建服务"),
            ),
            TextButton(
              onPressed: clean,
              child: const Text("关闭服务"),
            ),
            TextButton(
              onPressed: () {
                _socket?.writeln('REVERSE_LED');
              },
              child: const Text("发送REVERSE_LED"),
            ),
            TextButton(
              onPressed: sendBroadcastMessage,
              child: const Text("开始广播"),
            ),
            TextButton(
              onPressed: cleanRawDatagramSocket,
              child: const Text("关闭广播"),
            ),
          ],
        ),
      ),
    );
  }
}

标签:UDP,socket,通信,TCP,serverSocket,print,服务器,客户端
From: https://blog.csdn.net/nonagontech/article/details/142341660

相关文章

  • 传输层——TCP协议
    文章目录TCP协议段格式确认应答(ACK)机制超时重传机制三次握手四次挥手滑动窗口流量控制拥塞控制延迟应答捎带应答TCP协议段格式源/目的端口号:从哪个进程来到哪个进程去;32位序号/32位确认序号:分别代表TCP报文当中每个字节数据的编号以及对对方的确认,是TCP保证可......
  • TCP三次握手与四次挥手
    一、三次握手什么是三次握手?第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,SequenceNumber为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置AcknowledgmentNum......
  • 操作系统:线程间通信方式(上):锁机制详解
    操作系统:线程间通信方式(上):锁机制详解在多线程编程中,多个线程共享资源是常见的需求,但资源竞争会导致数据不一致和冲突问题。锁机制是一种用于控制线程对共享资源访问的同步方式,确保同一时刻只有一个线程能够访问临界区(CriticalSection)。本文将详细介绍线程间通信中的锁机......
  • Vue 依赖注入组件通信:provide / inject 使用详解
    引言在Vue.js中,我们经常会遇到组件之间需要共享数据的情况。一种常见的解决方案是通过props和$emit事件来进行数据传递,但对于多层嵌套的组件结构或共享状态的场景,这种方式显得繁琐而不直观。幸运的是,Vue.js提供了一个稍微优雅的解方案:依赖注入-provide和inject。......
  • 11 - TCPClient实验
    在上一个章节的UDP通信测试中,尽管通信的实现过程相对简洁,但出现了通信数据丢包的问题。因此,本章节将基于之前建立的WIFI网络连接,构建一个基础的TCPClient连接机制。我们利用网络调试助手工具来发送数据,测试网络通信中接收到的数据能够准确无误地回传。本节课目标:在本次实验......
  • C# udp通讯 多网卡/虚拟机指定某个网卡通讯
    LocalIP=GetAllAdaptersIPAddress();Task.Run(()=>{try{//接收广播UdpClientudpClient=newUdpClient(newIPEndPoint(IPAddress.Any,6789));while(true){IPEndPointAnyIP=newIPEndPoint(IPAddress.Any,0);byte[]data=udpClient.Receive(refAnyIP);......
  • C++基于select和epoll的TCP服务器
    select版本服务器#include<arpa/inet.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<unistd.h>#include<sys/socket.h>#include<string>#include<pthread.h>#include<sys/select.h>......
  • ModbusTCP报文详解
    ModbusTCP与ModbusRtu(ASCI)数据帧的区别总结:ModbusTCP就是在ModbusRtu(ASCI)基础上去掉CRC,再加上六个0一个6ModbusTCPMBAP报文头域长度描述客户机服务器事务处理标识符2字节Modbus请求/响应事务处理的识别客户机启动服务器从接收的请求中重新复制协议标识符2字节0=M......
  • UDP实现cmd服务
    cmd_server.c/*编译:gcccmd_server.c-lpthread*/#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<string.h>#include<unistd.h>#include<stdlib.h>#include<......
  • scapy函数 TCP() 使用说明
    前言全局说明scapy函数TCP()使用说明一、说明环境:Ubuntu18.04.6LTS(Linuxqt-vm5.4.0-150-generic#167~18.04.1-UbuntuSMPWedMay2400:51:42UTC2023x86_64x86_64x86_64GNU/Linux)pythonPython2.7.17(default,Mar82023,18:40:28)[GCC7.5.0]onli......