这几乎是一个非常菜鸟的程序,但是搞了我半天。
最近一直在学习linux C++程序设计,于是想写一个简单的UDP 收发程序,与STM32F429的Mbed OS 进行通信。Linux 是华硕笔记本上Windows WSL (ubuntu)。
Mbed OS上的程序比较简单,是一个UDP echo server。
#include "UDPSocket.h"
#include "math.h"
#include "arm_math.h"
#define ECHO_SERVER_PORT 8000
#define SERVER_ADDR "192.168.31.30"
static const char* mbedIp = "192.168.31.106"; //IP
static const char* mbedMask = "255.255.255.0"; // Mask
static const char* mbedGateway = "192.168.31.1"; //Gateway
int main (void) {
EthernetInterface eth;
eth.set_network(mbedIp,mbedMask,mbedGateway);
eth.connect();
printf("\nServer IP Address is %s\n", eth.get_ip_address());
UDPSocket server;
server.open(ð);
server.bind(eth.get_ip_address(),ECHO_SERVER_PORT);
SocketAddress client_addr;
char buffer[1024];
while (true) {
int n = server.recvfrom(&client_addr, buffer, sizeof(buffer));
server.sendto(client_addr.get_ip_address(),ECHO_SERVER_PORT, buffer, 1024);
}
}
为了屏蔽掉网络编程的细节,方便应用程序的使用。我将网络部分抽象成为一个类UDPClient
UDPClient.h
#ifndef UDPClient_H
#define UDPClient_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class UDPClient
{
private:
int sock;
int port;
struct sockaddr_in addr;
public:
UDPClient();
bool setup( int port);
int sendUDP( const char * address,char *buffer,int size);
int recvUDP(char *buffer,int size);
bool UDPbind();
void exit();
};
#endif
UDPClient.cpp
#include "UDPClient.h"
UDPClient::UDPClient(){
port=0;
sock=-1;
}
bool UDPClient::setup(int port)
{int reuse = 0;
if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket failed");
return false ;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopet error\n");
return -1;
}
memset( &addr, 0, sizeof(addr) );
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
return true;
}
bool UDPClient::UDPbind()
{
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind error:");
return false;
}
return true;
}
int UDPClient::sendUDP( const char * address,char *buffer,int size)
{
addr.sin_addr.s_addr = inet_addr(address);
int len=sendto( sock, buffer, 1024, 0, (struct sockaddr *)&addr, sizeof(addr));
return len;
}
int UDPClient::recvUDP(char *buffer,int size)
{
int len,recv_num;
len = sizeof(addr);
addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
recv_num = recvfrom(sock, buffer, size, 0, (struct sockaddr *)&addr, (socklen_t *)&len);
return recv_num;
}
void UDPClient::exit()
{
close( sock );
}
#include "UDPClient.h"
#define MY_PORT 8000
int main( void )
{ int i;
char buffer[1024];
UDPClient client;
client.setup(MY_PORT);
client.UDPbind();
cout<<"UDP Test"<
clang++ UDPClient.cpp clientTest.cpp -o clientTest
无法收到Mbed 返回的数据
我估计主要是sock 没有bind,接收端口无法确定。所以增加了bind(),并且在send 和recvfrom 之前,切换
addr.sin_addr.s_addr = inet_addr(address);
sendto....
和
addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
recvfrom.....
增加了bind 之后,又发现,Ctr-C 退出后,再次运行会出现
Address already in use
于是在setup中增加了
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopet error\n");
return -1;
}
运行时,很不可靠,以太网运行一段时间,就断掉了。我分析可能是华硕笔记本是1Gbps 网速,而Mbed 是100base T,所以发送不能太快。我现在设置了usleep(4000),也就是4ms。使用任务管理器看网速只有4Mbps不到。这个我不是太明白为啥在window WSL 的linux 下网络为啥如此慢?
我使用的路由器是cisco的。