linux C++ UDP通信工具类

linux C++ UDP通信工具类

  • 1 头文件UdpSocket.h
    • 1.1 头文件引用
    • 1.2 函数定义
    • 1.2 参数定义
  • 2 cpp文件UdpSocket.cpp
    • 2.1 构造函数及析构函数
    • 2.2 初始化函数
    • 2.3 发送数据
    • 2.4 监听线程开启
    • 2.5 线程结束
  • 3 udp工具类使用
  • 4 参考资源

UDP的通信原理,在此不做描述,以下仅分享linux下基于udp的通信的C++工具类。

1 头文件UdpSocket.h

头文件包含udp通信的初始化,发送数据,开启监听线程,结束监听线程等函数的定义。

1.1 头文件引用

头文件引用中,Signal.h 为基于poco库编写的信号类,用于实现信号的发送与槽函数的绑定(类似QT的信号与槽效果)。此处可以不使用,将其头文件及相关的信号函数进行注释屏蔽即可。

	#include 
	#include 
	#include 
	#include 
	#include 
	#include 
	#include 
	#include 

1.2 函数定义

public:
    UdpSocket(/* args */);
    /**
     * int localPort                
     * int remotePort
     * const char* localAddress
     * const char* remoteAddress
    */
    UdpSocket(int localPort, int remotePort, const char* localAddress, const char* remoteAddress);

    ~UdpSocket();
	/**
     * int localPort    本地端口            
     * int remotePort	目标端口
     * const char* localAddress		本地IP
     * const char* remoteAddress	目标IP
    */
    bool init(int localPort, int remotePort, const char* localAddress, const char* remoteAddress);
     /**
     * const char *byteArray	待发送数据
     * int length				发送数据长度
     * 返回成功发送数据的长度
    */
    int sendData(const char *byteArray, int length);
    /**
     * open listening thread	开启监听线程
    */
    void udpThread();//open listening thread
    /**
     * close listening thread	结束监听线程
    */
    void closeTread();//close listening thread

1.2 参数定义

private:
    bool isThreadOpen = false;//thread opening state
    int socket_fd;//参数sockfd: 正在监听端口的套接口文件描述符,通过socket获得
    struct sockaddr_in addr_local;//本地地址结构体
    struct sockaddr_in addr_remote;//目标地址结构体
    char readBuff[1024];//数据读取缓存buffer 

2 cpp文件UdpSocket.cpp

2.1 构造函数及析构函数

UdpSocket::UdpSocket(/* args */){
}
//含参构造函数
UdpSocket::UdpSocket(int localPort, int remotePort, const char* localAddress, const char* remoteAddress){
	//调用初始化函数
    init(localPort, remotePort, localAddress, remoteAddress);
}
//销毁对象时,需要结监听线程,释放资源
UdpSocket::~UdpSocket(){
    closeTread();
}

2.2 初始化函数

bool UdpSocket::init(int localPort, int remotePort, const char* localAddress, const char* remoteAddress){
    // 1.创建一个通信的socket
    /**
     * AF_INET : ipv4
     * SOCK_DGRAM : UDP
     * return -1 : error
    */
    socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    
    if(socket_fd == -1) {
        perror("socket");
        exit(-1);
    }   
    //local
    addr_local.sin_family = AF_INET;//ipv4
    addr_local.sin_port = htons(localPort);//port
    addr_local.sin_addr.s_addr = inet_addr(localAddress);
    //remote
    addr_remote.sin_family = AF_INET;//ipv4
    addr_remote.sin_port = htons(remotePort);//port
    addr_remote.sin_addr.s_addr = inet_addr(remoteAddress);
 
    // 2.绑定
    int ret = bind(socket_fd, (struct sockaddr *)&addr_local, sizeof(addr_local));
    if(ret == -1) {
        perror("bind");
        exit(-1);
    }
}

2.3 发送数据

/*
- sendto接口的参数:
    - socket_fd: 通信的fd
    - byteArray: 要发送的数据
    - length: 发送数据的长度
    - flags : 0
    - (struct sockaddr *)&addr_remote: 通信的另外一端的地址信息
    - sizeof(addr_remote): 地址的内存大小
- 返回:
    -n :发送字节的数量 
    -0 :失败
*/
int UdpSocket::sendData(const char *byteArray, int length){
    return sendto(socket_fd, byteArray, length, 0, (struct sockaddr *)&addr_remote, sizeof(addr_remote));
}

2.4 监听线程开启

void UdpSocket::udpThread(){
    isThreadOpen = true;
    char ipbuf[16];
    //打印本地IP和端口
    printf("Server-IP : %s, Port : %d\n", 
         inet_ntop(AF_INET, &addr_local.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
         ntohs(addr_local.sin_port));

    thread serverThread(
        [&]()->void
        {
            while (isThreadOpen)
            {
            	//缓存buffer需要清除数据,避免数据读取时错误
                memset(readBuff,0,sizeof(readBuff));                
                //阻塞 read and emit data
                /*
                - recvfrom接口的参数:
				    - socket_fd: 通信的fd
				    - readBuff: 缓存buffer
				    - sizeof(readBuff):  缓存buffer的长度
				    - flags : 0表示阻塞读取数据,MSG_DONTWAIT表示非阻塞读取数据
				    - NULL: 通信的另外一端的地址信息,不需要可以填NULL
				    - NULL: 地址的内存大小,不需要可以填NULL
				- 返回:
				    -n :接收字节的数量 
				    -0 :失败
                */
                //接收数据与处理,可根据自己的处理方式进行调整,比如接收并打印

                int length = recvfrom(socket_fd, readBuff,sizeof(readBuff), 0, NULL, NULL);
                std::cout<< length <<":"<<readBuff;

            }
            return;
        });
    serverThread.detach();
}

监听线程采用detach方式(不建议join方式),通过控制标志位isThreadOpen,让线程自行判断是否结束。

2.5 线程结束

void UdpSocket::closeTread(){
    isThreadOpen = false;
}

3 udp工具类使用

#include "UdpSocket.h"
#define IP "192.168.31.190"	//根据需要填写
#define localPort 4321	//根据需要填写
#define remotePort 1234	//根据需要填写


void local(){
    std::cout << "local--ID:" << std::this_thread::get_id() << std::endl;
    
    UdpSocket udp_local(localPort, remotePort, IP, IP);
    udp_local.udpThread();
    int i = 0;
    char a[4];
    a[0] = 'l';
    a[1] = 'o';
    a[2] = 'c';
    while (i<20)
    {
        udp_local.sendData(a,3);
        i++;
        sleep(1);
    }
    udp_local.closeTread();
}

void remote(){
    std::cout << "remote--ID:" << std::this_thread::get_id() << std::endl;
    UdpSocket udp_remote(remotePort, localPort, IP,IP);
    
    udp_remote.udpThread();
    int i = 0;
    char a[4];
    a[0] = 'r';
    a[1] = 'e';
    a[2] = 'm';
    while (i<20)
    {
        udp_remote.sendData(a,3);
        i++;
        sleep(1);
    }
    udp_remote.closeTread();
}

int main()
{
    
    std::cout << "主线程\t";
    std::cout << "main--ID:" << std::this_thread::get_id() << std::endl;
    thread t_remote(remote);
    thread t_local(local);
    
    t_remote.join();
    t_local.join();
    
    std::cout << "子线程结束.\n";
    return 0;
}

以上分享希望能对大家有所帮助,错误的地方欢迎留言指正,大家共同学习,共同进步。

4 参考资源

基于linux的UDP C++ 工具类及使用完整工程:https://download.csdn.net/download/qq_40778196/87715886

你可能感兴趣的:(Linux,C++,linux,c++,udp)