|
楼主 |
发表于 2017-11-7 15:24:28
|
显示全部楼层
17.2 UDP的API函数
使用如下7个函数可以实现RL-TCPnet的UDP通信:
(1)udp_get_socket
(2)udp_open
(3)udp_close
(4)udp_release_socket
(5)udp_get_buf
(6)udp_send
(7)udp_mcast_ttl
关于这7个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件:
这里我们重点的说以下4个函数,因为本章节配套的例子使用的是这4个函数:
(1)udp_get_socket
(2)udp_open
(3)udp_get_buf
(4)udp_send
关于这些函数注意以下两点:
1、这些函数都不支持重入,也就是不支持多任务调用。
2、UDP接口函数通过UDP Socket做数据传输,主要用于不把数据可靠传输作为首选的场合。因为UDP没有确认机制,会有丢包问题。
17.2.1 函数udp_get_socket
函数原型:
- U8 udp_get_socket (
- U8 tos, /* UDP Socket服务类型 */
- U8 opt, /* 校验和选项 */
- U16 (*listener)( /* 回调函数 */
- U8 socket, /* UDP Socket句柄 */
- U8* remip, /* 远程设备的IP地址 */
- U16 port, /* 远程设备的端口号. */
- U8* buf, /* 接收到的数据地址 */
- U16 len )); /* 接收到的数据长度 */ [size=3][font=新宋体] [/font][/size]
复制代码
函数描述:
函数udp_get_socket用于获取一个UDP Socket。
(1)第1个参数用于指定服务类型,默认取零即可。
(2)第2个参数是校验和选项,有如下两种可选。
用户可以通过或操作将发送和接收校验和都选上UDP_OPT_CHK_CS | UDP_OPT_SEND_CS。如果这两个选项都不使用的话,设置此参数为0即可,这样一定程度上可以加快系统响应时间。
(3)第3个参数是回调函数,用于事件监听。
a. 回调函数第1个参数,UDP Socket的句柄,也就是函数tcp_get_socket的返回值。
b. 回调函数第2个参数,远程设备的IP地址。
c. 回调函数第3个参数,远程设备的端口号。
d. 回调函数第4个参数,接收到的数据地址。
e. 回调函数第5个参数,接收到的数据长度。
(4)返回值,如果获取成功,返回TCP Socket句柄,如果获取失败,返回0。
使用这个函数要注意以下问题:
1. 调用UDPSocket任何其它函数前,务必要调用此函数udp_get_socket。
2. 以太网数据包受到以太网CRC的保护。
3. 传输的数据包通过路由器、代理服务器、网关等,数据包是可以被修改的。
4. 使用函数udp_get_socket,第3个参数的回调函数务必要设置。
使用举例:
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- uint8_t udp_soc;
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: tcp_callback
- * 功能说明: TCP Socket的回调函数
- * 形 参: socket UDP Socket类型
- * remip 远程设备的IP地址
- * remport 远程设备的端口号
- * buf 远程设备发来的数据地址
- * len 远程设备发来的数据长度,单位字节
- * 返 回 值: 默认返回0即可,一般用不上
- *********************************************************************************************************
- */
- U16 udp_callback(U8 socket, U8 *remip, U16 remport, U8 *buf, U16 len)
- {
- char buffer[50];
- U16 i;
-
- /* 确保是udp_soc的回调 */
- if (socket != udp_soc)
- {
- return (0);
- }
-
- /* 发消息的远程IP,打印IP和端口号 */
- sprintf(buffer, "远程连接IP: %d.%d.%d.%d", remip[0], remip[1], remip[2], remip[3]);
- printf_debug("IP:%s port:%d\\r\\n", buffer, remport);
-
- /* 接收到的数据长度,单位字节 */
- printf_debug("Data length = %d\\r\\n", len);
- /* 打印接收到的消息 */
- for(i = 0; i < len; i++)
- {
- printf_debug("buf[%d] = %d\\r\\n", i, buf[i]);
- }
-
- return (0);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TCPnetTest
- * 功能说明: TCPnet应用
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TCPnetTest(void)
- {
- int32_t iCount;
- uint8_t *sendbuf;
- uint8_t res;
- uint8_t ucKeyCode;
-
-
- /* 初始化网络协议栈 */
- init_TcpNet ();
-
- /* 获取一个UDP Socket */
- udp_soc = udp_get_socket (0, UDP_OPT_SEND_CS | UDP_OPT_CHK_CS, udp_callback);
- if (udp_soc != 0)
- {
- /* 打开UDP端口号 */
- udp_open (udp_soc, LocalPort_NUM);
- }
-
- /* 省略 */
-
- }
复制代码
17.2.2 函数udp_open
函数原型:
- BOOL udp_open (
- U8 socket, /* UDP Socket句柄 */
- U16 locport); /* 端口号 */ [size=3][font=新宋体] [/font][/size]
复制代码
函数描述:
函数udp_open用于打开UDP通信。
(1)第1个参数是设置要监听的UDP Socket句柄。
(2)第2个参数是UDP端口号。
(3)返回值,打开成功返回__TRUE,打开失败返回__FALSE。
使用这个函数要注意以下问题:
1. 如果第二个参数填0的话,系统将为其自动分配一个未使用的UDP端口号。
使用举例:
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- uint8_t udp_soc;
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: tcp_callback
- * 功能说明: TCP Socket的回调函数
- * 形 参: socket UDP Socket类型
- * remip 远程设备的IP地址
- * remport 远程设备的端口号
- * buf 远程设备发来的数据地址
- * len 远程设备发来的数据长度,单位字节
- * 返 回 值: 默认返回0即可,一般用不上
- *********************************************************************************************************
- */
- U16 udp_callback(U8 socket, U8 *remip, U16 remport, U8 *buf, U16 len)
- {
- char buffer[50];
- U16 i;
-
- /* 确保是udp_soc的回调 */
- if (socket != udp_soc)
- {
- return (0);
- }
-
- /* 发消息的远程IP,打印IP和端口号 */
- sprintf(buffer, "远程连接IP: %d.%d.%d.%d", remip[0], remip[1], remip[2], remip[3]);
- printf_debug("IP:%s port:%d\\r\\n", buffer, remport);
-
- /* 接收到的数据长度,单位字节 */
- printf_debug("Data length = %d\\r\\n", len);
- /* 打印接收到的消息 */
- for(i = 0; i < len; i++)
- {
- printf_debug("buf[%d] = %d\\r\\n", i, buf[i]);
- }
-
- return (0);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TCPnetTest
- * 功能说明: TCPnet应用
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TCPnetTest(void)
- {
- int32_t iCount;
- uint8_t *sendbuf;
- uint8_t res;
- uint8_t ucKeyCode;
-
-
- /* 初始化网络协议栈 */
- init_TcpNet ();
-
- /* 获取一个UDP Socket */
- udp_soc = udp_get_socket (0, UDP_OPT_SEND_CS | UDP_OPT_CHK_CS, udp_callback);
- if (udp_soc != 0)
- {
- /* 打开UDP端口号 */
- udp_open (udp_soc, LocalPort_NUM);
- }
-
- /* 省略 */
-
- }
复制代码
17.2.3 函数udp_get_buf
函数原型:
- U8* udp_get_buf (
- U16 size); /* 申请缓冲区大小,单位字节 */
复制代码
函数描述:
函数udp_get_buf用于获取UDP发送缓冲区,用户将要发送的数据存到这个缓冲区中,然后通过函数udp_send发送。发送完毕后会释放申请的发送缓冲区。
(1)第1个参数是要申请的缓冲区大小,单位字节。
(2)返回值,返回获取的缓冲区地址。如果缓冲区申请失败,RL-TCPnet会调用函数sys_error,并触发里面的错误类型ERR_MEM_ALLOC。对于RL-TCPnet V4.60及其以上版本,如果用户将此函数的形参与0x8000进行或操作,即最高位设置为1,那么此函数申请失败的话会返回空指针,即数值0,并触发函数sys_error的调用。
使用这个函数要注意以下问题:
1. 每次发送都需要调用此函数获取发送缓冲区地址。
2. 申请的发送缓冲区大小不可超过最大数据包大小UDP Maximum Packet Size,即1472字节。
3. 操作缓冲区的时候,切不可超过申请的缓冲区大小,否则会造成RL-TCPnet崩溃。
使用举例:
- /*
- *********************************************************************************************************
- * 用于本文件的调试
- *********************************************************************************************************
- */
- #define PORT_NUM 1001 /* TCP服务器监听端口号 */
-
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- uint8_t udp_soc;
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: tcp_callback
- * 功能说明: TCP Socket的回调函数
- * 形 参: socket UDP Socket类型
- * remip 远程设备的IP地址
- * remport 远程设备的端口号
- * buf 远程设备发来的数据地址
- * len 远程设备发来的数据长度,单位字节
- * 返 回 值: 默认返回0即可,一般用不上
- *********************************************************************************************************
- */
- U16 udp_callback(U8 socket, U8 *remip, U16 remport, U8 *buf, U16 len)
- {
- char buffer[50];
- U16 i;
-
- /* 确保是udp_soc的回调 */
- if (socket != udp_soc)
- {
- return (0);
- }
-
- /* 发消息的远程IP,打印IP和端口号 */
- sprintf(buffer, "远程连接IP: %d.%d.%d.%d", remip[0], remip[1], remip[2], remip[3]);
- printf_debug("IP:%s port:%d\\r\\n", buffer, remport);
-
- /* 接收到的数据长度,单位字节 */
- printf_debug("Data length = %d\\r\\n", len);
- /* 打印接收到的消息 */
- for(i = 0; i < len; i++)
- {
- printf_debug("buf[%d] = %d\\r\\n", i, buf[i]);
- }
-
- return (0);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TCPnetTest
- * 功能说明: TCPnet应用
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TCPnetTest(void)
- {
- int32_t iCount;
- uint8_t *sendbuf;
- uint8_t res;
- uint8_t ucKeyCode;
-
-
- /* 初始化网络协议栈 */
- init_TcpNet ();
-
- /* 获取一个UDP Socket */
- udp_soc = udp_get_socket (0, UDP_OPT_SEND_CS | UDP_OPT_CHK_CS, udp_callback);
- if (udp_soc != 0)
- {
- /* 打开UDP端口号 */
- udp_open (udp_soc, LocalPort_NUM);
- }
-
- /* 创建一个周期是100ms的软定时器 */
- bsp_StartAutoTimer(0, 100);
-
- while (1)
- {
- /* TCP轮询 */
- tcpnet_poll();
-
- /* 按键消息的处理 */
- ucKeyCode = bsp_GetKey();
- if (ucKeyCode != KEY_NONE)
- {
- switch (ucKeyCode)
- {
- /* K1键按下,给远程UDP设备发送8字节数据 */
- case KEY_DOWN_K1:
- /* 用于设置发送次数 */
- iCount = 1;
- do
- {
- tcpnet_poll();
-
- /* 申请8字节的空间 */
- sendbuf = udp_get_buf (8);
-
- if(sendbuf != NULL)
- {
- /* 初始化8个字节变量 */
- sendbuf[0] = '1';
- sendbuf[1] = '2';
- sendbuf[2] = '3';
- sendbuf[3] = '4';
- sendbuf[4] = '5';
- sendbuf[5] = '6';
- sendbuf[6] = '7';
- sendbuf[7] = '8';
-
- res = udp_send (udp_soc, Rem_IP, PORT_NUM, sendbuf, 8);
-
- /* 保证发送成功了发送次数才可以减一,这里发送成功并不保证远程设备接受成功 */
- if(res == __TRUE )
- {
- iCount--;
- }
- }
-
- /*
- 由于UDP没有重发,应答,流控制等机制,这里简单的做个延迟,
- 保证远程设备可以接受到数据
- */
- bsp_DelayMS(10);
-
- }while(iCount > 0);
- break;
-
- /* 其他的键值不处理 */
- default:
- break;
- }
- }
- }
- }
复制代码
17.2.4 函数udp_send
函数原型:
- BOOL udp_send (
- U8 socket, /* UDP socket句柄 */
- U8* remip, /* 远程设备的IP地址 */
- U16 remport, /* 远程设备的端口号 */
- U8* buf, /* 要发送数据的地址 */
- U16 dlen ); /* 要发送数据的大小,单位字节 */
复制代码
函数描述:
函数udp_send用于发送数据包给远程设备。
(1)第1个参数是UDP Socket句柄。
(2)第2个参数是远程设备的IP地址。
(3)第3个参数是远程设备的端口号。
(4)第4个参数是要发送数据的地址。
(5)第5个参数是要发送数据的大小,单位字节。
(6)返回值,发送成功返回__TRUE,发送失败返回__FALSE。
使用这个函数要注意以下问题:
1. 调用函数udp_send前务必要调用函数udp_get_buf获得缓冲区。
2. 数据通信前,务必要通过函数udp_open打开。
3. 同一个端口号,同一个UDP Socket可以与多个远程设备通信,但需要用户管理好多个设备通信时的数据发送和接收。
使用举例:
- /*
- *********************************************************************************************************
- * 用于本文件的调试
- *********************************************************************************************************
- */
- #define PORT_NUM 1001 /* TCP服务器监听端口号 */
-
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- uint8_t udp_soc;
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: tcp_callback
- * 功能说明: TCP Socket的回调函数
- * 形 参: socket UDP Socket类型
- * remip 远程设备的IP地址
- * remport 远程设备的端口号
- * buf 远程设备发来的数据地址
- * len 远程设备发来的数据长度,单位字节
- * 返 回 值: 默认返回0即可,一般用不上
- *********************************************************************************************************
- */
- U16 udp_callback(U8 socket, U8 *remip, U16 remport, U8 *buf, U16 len)
- {
- char buffer[50];
- U16 i;
-
- /* 确保是udp_soc的回调 */
- if (socket != udp_soc)
- {
- return (0);
- }
-
- /* 发消息的远程IP,打印IP和端口号 */
- sprintf(buffer, "远程连接IP: %d.%d.%d.%d", remip[0], remip[1], remip[2], remip[3]);
- printf_debug("IP:%s port:%d\\r\\n", buffer, remport);
-
- /* 接收到的数据长度,单位字节 */
- printf_debug("Data length = %d\\r\\n", len);
- /* 打印接收到的消息 */
- for(i = 0; i < len; i++)
- {
- printf_debug("buf[%d] = %d\\r\\n", i, buf[i]);
- }
-
- return (0);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TCPnetTest
- * 功能说明: TCPnet应用
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TCPnetTest(void)
- {
- int32_t iCount;
- uint8_t *sendbuf;
- uint8_t res;
- uint8_t ucKeyCode;
-
-
- /* 初始化网络协议栈 */
- init_TcpNet ();
-
- /* 获取一个UDP Socket */
- udp_soc = udp_get_socket (0, UDP_OPT_SEND_CS | UDP_OPT_CHK_CS, udp_callback);
- if (udp_soc != 0)
- {
- /* 打开UDP端口号 */
- udp_open (udp_soc, LocalPort_NUM);
- }
-
- /* 创建一个周期是100ms的软定时器 */
- bsp_StartAutoTimer(0, 100);
-
- while (1)
- {
- /* TCP轮询 */
- tcpnet_poll();
-
- /* 按键消息的处理 */
- ucKeyCode = bsp_GetKey();
- if (ucKeyCode != KEY_NONE)
- {
- switch (ucKeyCode)
- {
- /* K1键按下,给远程UDP设备发送8字节数据 */
- case KEY_DOWN_K1:
- /* 用于设置发送次数 */
- iCount = 1;
- do
- {
- tcpnet_poll();
-
- /* 申请8字节的空间 */
- sendbuf = udp_get_buf (8);
-
- if(sendbuf != NULL)
- {
- /* 初始化8个字节变量 */
- sendbuf[0] = '1';
- sendbuf[1] = '2';
- sendbuf[2] = '3';
- sendbuf[3] = '4';
- sendbuf[4] = '5';
- sendbuf[5] = '6';
- sendbuf[6] = '7';
- sendbuf[7] = '8';
-
- res = udp_send (udp_soc, Rem_IP, PORT_NUM, sendbuf, 8);
-
- /* 保证发送成功了发送次数才可以减一,这里发送成功并不保证远程设备接受成功 */
- if(res == __TRUE )
- {
- iCount--;
- }
- }
-
- /*
- 由于UDP没有重发,应答,流控制等机制,这里简单的做个延迟,
- 保证远程设备可以接受到数据
- */
- bsp_DelayMS(10);
-
- }while(iCount > 0);
- break;
-
- /* 其他的键值不处理 */
- default:
- break;
- }
- }
- }
- }
复制代码 |
|