UDP是面向非连接的网络交互协议,在UDP交互中,存在客户端和服务端,客户端(Client)主要来发送报文,服务端(Server)接收来自客户端的报文,在进行报文交互的时候,UDP是非连接的,客户端发送一个报文到指定端口,然后服务端监听了这个端口,如果收到这个报文,然后就进行处理,如果收不到,或者因为处理报文的消息队列太大,被抛弃了,就导致服务端无法收到这个报文。给大家举个例子,敌人扔了一个手雷过来,队长喊了一声“卧倒!”,有的士兵耳朵正好听到,就立马卧倒了,有的士兵可能正在带着耳机听音乐,没听到这个“报文”,结果就。。。了,所以,UDP的广播是一种不可靠的可以一对多的网络交互。
1、主要利用C++的 socket 创建一个udp socket.
2、利用setsockopt() 对socket进行设置参数选项
3、创建一个struct sockaddr_in 类型的对象,并进行初始化协议类型(ipv4或ipv6)、接收地址(广播地址)和接收端口号。
4、利用 sendto() 函数将udp报文进行发送。
client头文件
#ifndef UDPCLIENT_H
#define UDPCLIENT_H
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <string>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
using namespace std;
class UdpClient
{
public:
UdpClient();
void Init(const int port);
void StartBroadCast(const string info);
static void* UdpBroadCast(void * arg);
private:
struct sockaddr_in m_clientAddr;
string m_sendMsg;
pthread_t m_tids;
};
#endif // UDPCLIENT_H
client cpp文件
#include "udpclient.h"
#include <QDebug>
#include <qjsondocument.h>
#include <QJsonParseError>
#include <QFile>
#include <QJsonObject>
#include <QJsonArray>
#include <QStringLiteral>
UdpClient::UdpClient()
{
bzero(&m_clientAddr, sizeof(m_clientAddr));
m_tids = 0;
}
void UdpClient::Init(const int port)
{
m_clientAddr.sin_family = AF_INET;
m_clientAddr.sin_addr.s_addr = INADDR_BROADCAST; //广播 IP
m_clientAddr.sin_port = htons(port); //指定接收端口
}
void UdpClient::StartBroadCast(string info)
{
m_sendMsg = info;
if (m_tids == 0) {
pthread_create(&m_tids, NULL, UdpBroadCast, (void *)this); // 启动线程来发送报文,将类指针传递到线程内
}
}
void* UdpClient::UdpBroadCast(void * arg)
{
int udpSocket = socket(AF_INET, SOCK_DGRAM, 0);// 创建socket对象
UdpClient *udp = (UdpClient *)arg; // 接收线程传递的类对象指针
unsigned long addr = INADDR_BROADCAST; // 广播地址
while (1) {
// 设置socket的参数
int ret = setsockopt(udpSocket, SOL_SOCKET, SO_REUSEADDR | SO_BROADCAST, &addr, sizeof(addr));
if (ret != 0) {
qDebug()<<"[Client] set udp client options failed";
close(udpSocket);
return NULL;
}
string sendMsg =udp->m_sendMsg;
size_t sendLen = sendto(udpSocket, udp->m_sendMsg.c_str(), udp->m_sendMsg.length(),
0, (struct sockaddr*)&udp->m_clientAddr, sizeof(udp->m_clientAddr));
// 发送成功后,会返回发送报文的长度,如果返回长度和报文长度一致,则认为发送成功
if (sendLen != udp->m_sendMsg.length()) {
qDebug()<<QString("[CLIENT]send msg lenth error: src len: %1 send len: %2")
.arg(sendMsg.length()).arg((int)sendLen);
} else {
qDebug()<<"[CLIENT]send success:"<<QString::fromStdString(sendMsg);
}
sleep(5); // 等待5s后发送
}
close(udpSocket);
return NULL;
}
1、创建struct sockaddr_in 变量,设置协议族,接收地址,接收端口。
2、创建socket 变量,设置协议族
3、bind() 函数绑定socket
4、recvfrom() 来获取当前的udp报文
server 头文件
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <string>
#include <unistd.h>
#include <iostream>
#include <pthread.h>
#include <functional>
using namespace std;
typedef std::function<void(string)> Fun;
typedef void(*CallFun)(string);
class UdpServer
{
public:
UdpServer();
int Init(const int port, const Fun callbackFun = NULL); //callbackFun 为收到报文的处理函数
void setCallBack(Fun func); //设置回调函数
int startListen(); //开始监听接口
static void* recv(void *args); // 接收消息函数
private:
struct sockaddr_in m_srvAddr;
int m_udpSocket;
Fun m_msgProcFun;
};
#endif // UDPSERVER_H
server cpp文件
#include "udpserver.h"
#include <string.h>
#include <qdebug.h>
UdpServer::UdpServer()
{
bzero(&m_srvAddr, sizeof(m_srvAddr));
m_msgProcFun = NULL;
}
int UdpServer::Init(const int port, const Fun callbackFun)
{
m_srvAddr.sin_family = AF_INET;
m_srvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
m_srvAddr.sin_port = htons(port);
m_msgProcFun = callbackFun;
return startListen();
}
int UdpServer::startListen()
{
m_udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
int ret = bind(m_udpSocket,(sockaddr*)&m_srvAddr,sizeof(sockaddr));
if (ret != 0) {
return ret;
}
pthread_t tids;
ret = pthread_create(&tids, NULL, recv, (void *)this); // 采用线程来处理udp报文
if (ret != 0) {
qDebug()<<"[SERVER]create thread failed";
return ret;
}
return 0;
}
void* UdpServer::recv(void *args)
{
sockaddr_in srv_Addr;
UdpServer* udp = (UdpServer*)args;
socklen_t addr_len = sizeof(srv_Addr);
char *buff = new char[100];
while(1) {
memset(buff, 0, 100);
size_t sz = recvfrom(udp->m_udpSocket, buff, 100, 0,(struct sockaddr*)&srv_Addr,&addr_len);
qDebug()<<buff;
string data = buff;
data = data.substr(16); // 取前16个字节的数据
if (udp->m_msgProcFun) {
udp->m_msgProcFun(data);
}
}
return NULL;
}
void UdpServer::setCallBack(Fun func)
{
m_msgProcFun = func;
}