之前看到的一些博客主要分享的是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

#include

#include

#include

#include

#include

#include

源代码如下:

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进行接收操作

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

将飞机数据显示在图上。

附录

咕咕

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: