udp信息传递的方式分为三种
1 单播 客户端与服务器之间的点对点连接
2 广播 主机之间 1对所有的通讯模式 ()
3组播 主机之间1对1组的通讯模式 (局域网)
主要使用的是udp组播 和单播
然而在ip组播环中,数据包的目的地址不是一个,而是一组,形成组地址。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据立即开始向接收者传输,组中的所有成员都能接收到数据包。组播组中的成员是动态的,主机可以在任何时刻加入和离开组播组。
组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。
udp组播的基本步骤 1.建立socket 2.socket和端口绑定 3.加入一个组播组 4.通过sendto进行数据的收发 5.关闭socket
发送数据包 入口参数 服务器地址 端口号 消息体
static void send(String ServerIp, int Port, String Msg) {
udpSocket.beginPacket(ServerIp.c_str(), Port);//开始数据包
udpSocket.write(WIFI_MSG_FH);//写高八位
udpSocket.print(Msg);
udpSocket.write(WIFI_MSG_FT);//写第八位
udpSocket.endPacket();//结束数据包
}
udpSocket.beginPacket(ServerIp.c_str(), Port);//开始数据包
udpSocket.endPacket();//结束数据包
send(udpSocket.remoteIP().toString(), udpSocket.remotePort(), sendMsg);//发送远程数据包
ip 地址 端口号 和信息
一般发送远程数据包的时候需要把数据处理好之后sendmsg 再进行传输
static void detectValidMsgFromServer() //检测来自服务器的有效消息
和检测muc的逻辑大致一样
udpSocket.beginMulticast(IPAddress(MULTICAST_ADDR), UDP_LOCAL_PORT);
//开始组播
透传指令 app和主机之间的通讯 esp32作为一个转发者
void wifi_app_replay(String token, String msg)
{ wifi_remote_sendMsg(token, msg, String(reciveFrameNum), reciveUUUID); }
首先我们看下发送方:
1)构造socket
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
//如果需要绑定,记得绑定本地地址
2)指定发送的组播地址和端口
struct sockaddr_in mcast_addr;
memset(&mcast_addr, 0, sizeof(mcast_addr));
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_addr.s_addr = inet_addr(mcast_ip.c_str());
mcast_addr.sin_port = htons(mcast_port); 3)发送组播数据
//it为组播数据内容描述
int n = sendto(udp_socket, it.c_str(), it.length(),0,(struct sockaddr*)&mcast_addr,sizeof(mcast_addr));
4)关闭socket
close(udp_socket);
下面看看接收方的实现
1)同样是先构建socket
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
2)绑定本机地址
//
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//local_addr.sin_addr.s_addr = inet_addr(local_ip.c_str());//指定发送的网口
local_addr.sin_port = htons(mcast_port);
//建立本地捆绑(主机地址/端口号)
int err = -1;
err = bind(udp_socket,(struct sockaddr*)&local_addr, sizeof(local_addr));3)加入组播,才能接收到组播信息
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(mcast_ip.c_str());
if(local_ip.empty()){
mreq.imr_interface.s_addr = htonl(INADDR_ANY); //任意接口接收组播信息
}else{
mreq.imr_interface.s_addr = inet_addr(local_ip.c_str()); //指定接口接收组播信息
} err = setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
4)接收数据
sockaddr_in srv_Addr;//用于存储发送方信息
socklen_t addr_len = sizeof(srv_Addr);
char *buff = new char[buf_size]; memset(buff, 0, buf_size);
n = recvfrom(udp_socket, buff, buf_size, 0,(struct sockaddr*)&srv_Addr,&addr_len);
工程中的整体逻辑‘ 创建socket 绑定本地端口号 ip 然后加入组播组 检测数据包 数据写在buf中 发送指定的ip 端口号
也可以使用asyncudpclient库 进行传输
有组播 广播 单播的形式 引入了AsyncUDPPacket 异步udp数据包 发送或者接受数据