之前看到的一些博客主要分享的是linux环境下的c++和python的UDP通信,虽然有基础的可以很快的上手,但是对于小白来说用起来还是不太方便,所以在这里我再写一下win环境下的通信,附带源码。

本文的使用背景是,我使用C++搭建了一个飞机模型文件,但是飞机的航迹无法实时显示,给调试带来了困难。所以使用python中pygame库的画图功能,实时显示飞机位置,打印飞机航迹。但是C++的数据如何传输给python呢?这就用到了c++和python之间的UDP传输。(我深刻同意另一位博主的话,凡是和文件有关联的我都不喜欢)。

WIN下UDP发送

废话少说,先来看win下的代码,这里主要使用了两个函数,一个是UDPSend,另一个是UDPInfoSend。

UDPSend的功能就是调用UDP发送数据,UDPInfoSend是我用来写入需要发送数据的。没有耐心的小伙伴可以直接复制粘贴UDPSend使用,了解其使用方式就可以了,有兴趣的可以在附录里了解下原理。关于UDPSend的使用原理在下文会提到。

对了,不要忘了加入win下的socket头文件,他们是:

#include <time.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <vector>
#include <cstdio>
#include <stdio.h>
#include <iostream>

源代码如下:

void UDPSend(char* p, int size)
{
    //创建套接字
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(1, 1);

    /*发送数据*/
    char* SendData = (char*)malloc(sizeof(char) * size);
    memcpy(SendData, p, size);

    int err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return;
    }
    if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return;
    }
    SOCKET sockSen = socket(AF_INET, SOCK_DGRAM, 0);
    SOCKADDR_IN addrSen;
    addrSen.sin_family = AF_INET;//协议簇
    addrSen.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addrSen.sin_port = htons(8888);
    sendto(sockSen, SendData, strlen(SendData), 0, (SOCKADDR*)&addrSen, sizeof(SOCKADDR));
    /*int WSAAPI sendto(
        SOCKET s,                //s 申请的通讯套接字
        const char* buf,        //* buf 要发送的缓冲区
        int len,                //len 发送的长度
        int flags,                //flags 调用的方式,一般写为 0
        const sockaddr * to,    //* to 目的地址指针
        int tolen                //tolen 地址结构长度
    );*/

    free(SendData);
    SendData = NULL;

    //关闭Socket对象
    closesocket(sockSen);
    WSACleanup();
}
void UDPInfoSend(PlaneModel* plane)
{
    while (1)
    {
        int start, end, Head, test;
        start = clock();
        //将需要传递的内容转换为char
        char buffer1[10], buffer2[10];
        sprintf(buffer1, "%.8f", plane->PlaneInfo.Lati);   
        sprintf(buffer2, "%.8f", plane->PlaneInfo.Long);   

        char DataSend[20];
        memcpy(DataSend, buffer1, 10);
        memcpy(DataSend + 10, buffer2, 10);
        UDPSend(DataSend, 20);
        end = clock();
        if ((end - start) < 40)
            Sleep(40 - (end - start));
    }
}

这里主要讲解UDPInfoSend怎么调用UDPSend,实现发送功能的。

第〇步,设置好UDP的传输地址("127.0.0.1")和端口(8888),主要是上述26/27行的内容。如果你也是c++到python的转换,直接复制源代码就行,不用理解。

首先,UDP传输的都是字节,而在传输之前,使用char 作为容器是最好的。

发送的第①步如下:将从C++向python发送所以需要将原本是double类型的飞机经纬度,转换成为文本文件。这里使用了cstdio库中的sprintf函数,具体解释如下。

sprintf(buffer1, "%.8f", plane->PlaneInfo.Lati);  
//代表将plane->PlaneInfo.Lati保留八位小数,写入buffer1中

发送的第②步:将所需要发送的数据通过memcpy,拷贝到一个大的容器里,集中起来。

char DataSend[20];
memcpy(DataSend, buffer1, 10);//将buffer1拷贝到DataSend的1-10位
memcpy(DataSend + 10, buffer2, 10);//将buffer2拷贝到DataSend的11-20位

发送的第③步:将这个大的容器发送出去,调用DataSend

UDPSend(DataSend, 20);//前边是char*类型的数组,后边是数组的内有效数据的字节数,这里是20

这样一次UDP发送就完成了。

*建议UDP发送使用thread单独开一个线程去做,不要写在主函数里占用时间

Python下UDP接收

# udp 通信地址,IP+端口号
    udp_addr = ('127.0.0.1', 8888)
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口
    udp_socket.bind(udp_addr)
    while True:
        recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数
        # 打印接收到的数据
        #print(f"[From {recv_data[1][0]}:{recv_data[1][1]}]:{recv_data[0]}")
        json_data = {'latitude': float(recv_data[0][:10])*57.2958, 'longitude': float(recv_data[0][10:20])*57.2958}

Python下的操作一样,先要设置地址和端口号,确保两边地址和端口号一致。然后在收到数据后对数据进行处理,20位的数据前10位是lat,后10位是lon。我这里使用了json文件,方便后续的画图操作。

json_data = {'latitude': float(recv_data[0][:10]), 'longitude': float(recv_data[0][10:20])} 
//folat是强制类型转换,recv_data[0]是收到的数据,recv_data[0][:10]是截取1-10位的数据,同理recv_data[0][10:20]就是截取10到20位的数据

*Python这里也可以单独开一个thread进行接收操作

最后的结果就是可以正常通信,并且可以实时画图显示




python与VC之间同步 python与c++通信_python与VC之间同步


python与VC之间同步 python与c++通信_python与VC之间同步_02


将飞机数据显示在图上。

附录