Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
原创征文
rt-thread 移植 eRPC 之 Transport (winsock2)
发布于 2022-09-02 15:18:54 浏览:834
订阅该版
[tocm] ## 前言 嗯\~\~\~ 一个跨平台框架,如果说它[不支持 win 系统](https://github.com/EmbeddedRPC/erpc/issues/299),总感觉有点儿怪怪的。既然[官方的精力不在这里](https://github.com/EmbeddedRPC/erpc/issues/299#issuecomment-1200950586),那么就自己动手。 ### 可行性及工作量评估 因 eRPC 已有 linux (或 cygwin) 平台的 tcp socket 实现。如果能借助已有的代码,在原有的代码上进行平台扩展,使其能兼容 linux cygwin win(MINGW)。原来的源码不做修改,通过系统宏定义在合适的位置添加目标平台上的实现。还是比较可行的。 考虑到 tcp socket 需要使用到的操作无非 `socket` `connect` `bind` `listen` `accept` `write/send` `read/recv` `close` 等。 涉及到修改的文件有两个 "erpc_tcp_transport.h" "erpc_tcp_transport.cpp" ### 扩展过程 #### TCPTransport 类接口说明 它有三个 public 函数:`configure` `open` `close`。顾名思义,分别是配置、打开、关闭 Transport 接口。 还有五个 protected 函数:`connectClient` `underlyingReceive` `underlyingSend` `serverThread` `serverThreadStub` 。 `connectClient` 用来创建 socket 客户端并连接服务端; `underlyingReceive` `underlyingSend` 封装了收发过程; `serverThread` 则是服务端创建 socket 服务并等待连接的线程。 `serverThreadStub` 就认为是线程入口回调函数吧。 特别说明一下 `underlyingReceive` `underlyingSend` 两个函数。 `underlyingReceive` 的函数原型:`virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size);`。官方说明,这个函数返回值有三种:成功、接收失败、socket 关闭。第一个参数是已申请内存的空间首地址指针,第二个参数是“预读取字节数据量”!笔者提醒:当且仅当读取到 `size` 个字节数据后才算成功,其它情况都应该算是错误。比如:读等待超时、读错误、连接异常关闭等等。 `underlyingSend` 的函数原型:`virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size);`。官方说明,这个函数返回值也有三种:成功、发送错误、socket 关闭。第一个参数是预发送数据首地址指针,第二个参数是预发送数据字节数。当且仅当发送成功字节数等于 `size` 才算成功,其它情况都算错误。比如:写错误、连接异常关闭等等。 #### "erpc_tcp_transport.h" 添加 winsock2 引用 ``` #if defined(__linux__) || defined(__CYGWIN__) #elif defined(__MINGW32__) #include
#endif ``` #### 修改 m_socket 成员变量类型 ``` #if defined(__linux__) || defined(__CYGWIN__) int m_socket; /*!< Socket number. */ #elif defined(__MINGW32__) SOCKET m_socket; /*!< Socket number. */ #endif ``` #### "erpc_tcp_transport.cpp" 添加 winsock2 头文件引用 ``` #elif defined(__MINGW32__) #include
#include
#include
#endif ``` #### 添加两个宏定义 这两个宏定义没找到在哪个头文件定义的,也不知道应该添加哪个头文件包含,只在微软 MSDN 上搜到了定义的值。权且这么定义了用吧 ``` #elif defined(__MINGW32__) #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0x00000008 // Servicename must be a numeric port number #endif ``` #### 修改构造函数,初始化成员变量 ``` #if defined(__linux__) || defined(__CYGWIN__) , m_socket(-1) #elif defined(__MINGW32__) , m_socket(INVALID_SOCKET) #endif , m_serverThread(serverThreadStub) , m_runServer(true) { #if defined(__linux__) || defined(__CYGWIN__) #elif defined(__MINGW32__) WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); #endif } ``` 特别注意后面 WS 的初始化操作。 #### 修改 sock 变量类型及返回值错误判断 变量类型由 int 改成 SOCKET; 初始化初值由 -1 改成 INVALID_SOCKET; ``` #if defined(__linux__) || defined(__CYGWIN__) int sock = -1; #elif defined(__MINGW32__) SOCKET sock = INVALID_SOCKET; #endif ``` 原来错误值是负数(-1),在 MINGW 环境里是 INVALID_SOCKET。后面类似的地方还有很多。 ``` #if defined(__linux__) || defined(__CYGWIN__) if (m_socket != -1) #elif defined(__MINGW32__) if (m_socket != INVALID_SOCKET) #endif ``` #### `setsockopt` `setsockopt` 函数第三个参数在 linux 系统里是 `const void *` ,在 win 系统里是 `const char *` #### close socket linux 里用 `close` 函数关闭一个 socket 文件描述符。 win 里用 `closesocket` 关闭一个 socket。 #### send 数据 linux 里用 `write` 比较常见,也可以用 `send`。但是 eRPC 用的 `write`。 换到 win 系统,就只能用 `send`了 ``` if defined(__linux__) || defined(__CYGWIN__) result = write(m_socket, data, size); #elif defined(__MINGW32__) result = ::send(m_socket, (const char *)data, size, 0); #endif ``` #### recv 数据 接收 socket 数据同理 ``` if defined(__linux__) || defined(__CYGWIN__) length = read(m_socket, data, size); #elif defined(__MINGW32__) length = ::recv(m_socket, (char *)data, size, 0); #endif ``` ### 提醒 win 系统下使用 winsock2 编译程序的时候需要添加库依赖 `-lws2_32`。 ## 结束语 在前一篇 [rt-thread 移植 eRPC 系列(二) 之 演示](https://club.rt-thread.org/ask/article/7b9ed79f35c8e568.html) 中,我们在 linux 环境下演示了两个小 demo 。有了本篇的工作,我们可以在 win 系统下 cygwin 环境或者 MINGW 环境运行小 demo 了。或者,和前面的 linux 系统来一个跨系统的 RPC。 本篇就不截图了,可以参见 [rt-thread 移植 eRPC 系列(二) 之 演示](https://club.rt-thread.org/ask/article/7b9ed79f35c8e568.html)。 需要注意的一点儿是跨系统的时候需要修改 client 程序中的 ip 地址。 鉴于此,我们对 main 函数做如下修改。 ``` const char *server = "192.168.2.56"; if (argc == 2) { server = argv[1]; } erpc_transport_t transport = erpc_transport_tcp_init(server, 5555, false); ``` ***相关文章*** [rt-thread 移植 eRPC 系列(一) 之 简介](https://club.rt-thread.org/ask/article/3acf471c19f2595f.html) [rt-thread 移植 eRPC 系列(二) 之 演示](https://club.rt-thread.org/ask/article/7b9ed79f35c8e568.html) [rt-thread 移植 eRPC 系列(三) 之 Porting](https://club.rt-thread.org/ask/article/1713a66f5576e9ae.html)
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1517
被采纳
342
关注TA
发私信
相关文章
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
线程
RT-Thread Nano
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
807
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部