第26章     RL-TCPnet之DHCP应用

本章节为大家讲解RL-TCPnet的DHCP应用,学习本章节前,务必要优先学习第25章的DHCP基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的效果。

本章教程含STM32F407开发板和STM32F429开发板。

26.1  初学者重要提示

26.2  DHCP函数

26.3  DHCP配置说明(Net_Config.c)

26.4  DHCP调试说明(Net_Debug.c)

26.5  DHCP检测过程

26.6  网络调试助手和板子的操作步骤

26.7  实验例程说明(RTX)

26.8  总结

26.1  初学者重要提示

  1. 学习本章节前,务必保证已经学习了第25章的基础知识。
  2. 本章相对比较简单,配套的例子中实现了一种8秒内无法通过DHCP Client获取动态IP的情况下,使用配置向导文件Net_Config.c中设置的静态IP地址。

26.2  DHCP函数

涉及到DHCP的,仅有如下两个函数:

  • dhcp_disable

此函数比较简单,用于禁止DHCP。

  • dhcp_cbfunc

此函数是DHCP的回调函数,实际测试发现,这个函数没有任何效果,也就是此函数没有被调用到。

关于这2个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件:

注意,这两个函数都不支持重入,也就是不支持多任务调用。

26.3  DHCP配置说明(Net_Config.c)

(本章节配套例子的配置与本小节的说明相同)

RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:

RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。

System Definitions

(1)Local Host Name

局域网域名。

这里起名为armfly,使用局域网域名限制为15个字符。

(2)Memory Pool size

参数范围1536-262144字节。

内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。

(3)Tick Timer interval

可取10,20,25,40,50,100,200,单位ms。

系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。

Ethernet Network Interface

以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP

(1)MAC Address

局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。

(2)IP Address

IP地址。

(3)Subnet mask

子网掩码。

(4)Default Gateway

默认网关。

Ethernet Network Interface

以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。

(1)NetBIOS Name Service

NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。

(2)Dynaminc Host Configuration

即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。

(3)Vendor Class Identifier

厂商ID,如果设置了的话,会将其加到DHCP的请求消息中,用于识别网络设备的不同厂商。

(4)Bootfile Name

从DHCP 服务器获取的引导文件名。

(5)NTP Servers

从DCHP服务器获得NTP服务器列表。

UDP Sockets

UDP Sockets配置,打上对勾就使能了此项功能

(1)Number of UDP Sockets

用于配置可创建的UDP Sockets数量,这里配置了5个。

范围1 – 20。

TCP Sockets

TCP Sockets配置,打上对勾就使能了此项功能

(1)Number of TCP Sockets

用于配置可创建的TCP Sockets数量。

(2)Number of Retries

范围0-20。

用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。

(3)Retry Timeout in seconds

范围1-10,单位秒。

重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。

(4)Default Connect Timeout in seconds

范围1-600,单位秒。

用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。

(5)Maximum Segment Size

范围536-1460,单位字节。

MSS定义了TCP数据包能够传输的最大数据分段。

(6)Receive Window Size

范围536-65535,单位字节。

TCP接收窗口大小。

BSD Socket Interface

BSD Socket配置,打上对勾就使能了此项功能

(1)BSD_NUMSOCKS

用于配置可创建的BSD Socket数量。

范围1-20。

(2)BSD_SRVSOCKS

定义的BSD Socket中可以采用TCP通信协议的服务器个数。

(3)BSD_RCVTOUT

socket接收函数recv工作在阻塞状态时的溢出时间设置,单位秒。

范围0-600秒,配置为0的话,表示无限等待。

(4)BSD_GETHOSTEN

启用或禁用Berkeley风格的主机名解。

26.4 DHCP调试说明(Net_Debug.c)

(重要说明,RL-TCPnet的调试是通过串口打印出来的)

RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:

Print Time Stamp

勾选了此选项的话,打印消息时,前面会附带时间信息。

其它所有的选项

默认情况下,所有的调试选项都关闭了,每个选项有三个调试级别可选择,这里我们以DHCP Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Full debug三个调试级别可供选择,每个调试选项里面都是这三个级别。

Off:表示关闭此选项的调试功能。

Errors only:表示仅在此选项出错时,将其错误打印出来。

Full debug:表示此选项的全功能调试。

下面是对DHCP Debug配置为Full debug时,打印出来的消息:

26.5 DHCP检测过程

本章节配套的程序中对DHCP检测过程做了一个简单的判断,8秒内不能获得动态IP地址的话,将使用配置向导文件Net_Config.c里面设置的固定IP地址:192.168.1.100。

检测代码如下:

  1. 1 /*
  2. 2
  3. 3 **********************************************************************************************************
  4. 4
  5. 5 外部调用
  6. 6
  7. 7 **********************************************************************************************************
  8. 8
  9. 9 */
  10. 10
  11. 11 #define DHCP_TOUT 80 /* DHCP动态IP获取的溢出时间设置为8秒 */
  12. 12
  13. 13 #define MY_IP localm[NETIF_ETH].IpAdr
  14. 14
  15. 15 extern LOCALM localm[];
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21 /*
  22. 22
  23. 23 **********************************************************************************************************
  24. 24
  25. 25 变量
  26. 26
  27. 27 **********************************************************************************************************
  28. 28
  29. 29 */
  30. 30
  31. 31 uint32_t dhcp_tout;
  32. 32
  33. 33 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",
  34. 34
  35. 35 "Waiting for DHCP"};
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41 /*
  42. 42
  43. 43 *********************************************************************************************************
  44. 44
  45. 45 * 函 数 名: main
  46. 46
  47. 47 * 功能说明: 标准c程序入口。
  48. 48
  49. 49 * 形 参: 无
  50. 50
  51. 51 * 返 回 值: 无
  52. 52
  53. 53 *********************************************************************************************************
  54. 54
  55. 55 */
  56. 56
  57. 57 static void dhcp_check(void)
  58. 58
  59. 59 {
  60. 60
  61. 61
  62. 62
  63. 63 /* 检测是否通过DHCP自动获得IP */
  64. 64
  65. 65 if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
  66. 66
  67. 67 {
  68. 68
  69. 69 /* 已经获得IP */
  70. 70
  71. 71 dhcp_tout = 0;
  72. 72
  73. 73 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  74. 74
  75. 75 MY_IP[2], MY_IP[3]);
  76. 76
  77. 77 sprintf((char *)DHCP_Status[1],"DHCP Success");
  78. 78
  79. 79 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  80. 80
  81. 81 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  82. 82
  83. 83 return;
  84. 84
  85. 85 }
  86. 86
  87. 87
  88. 88
  89. 89 /* 每100ms进行一次减减操作 */
  90. 90
  91. 91 if (--dhcp_tout == 0)
  92. 92
  93. 93 {
  94. 94
  95. 95 /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
  96. 96
  97. 97 dhcp_disable ();
  98. 98
  99. 99 sprintf((char *)DHCP_Status[1],"DHCP Failed" );
  100. 100
  101. 101 /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
  102. 102
  103. 103 dhcp_tout = 80 | 0x80000000;
  104. 104
  105. 105 return;
  106. 106
  107. 107 }
  108. 108
  109. 109
  110. 110
  111. 111 /* 设置固定IP的8秒时间到 */
  112. 112
  113. 113 if (dhcp_tout == 0x80000000)
  114. 114
  115. 115 {
  116. 116
  117. 117 dhcp_tout = 0;
  118. 118
  119. 119 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  120. 120
  121. 121 MY_IP[2], MY_IP[3]);
  122. 122
  123. 123 sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
  124. 124
  125. 125 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  126. 126
  127. 127 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  128. 128
  129. 129 }
  130. 130
  131. 131 }
  132. 132
  133. 133
  134. 134
  135. 135 /*
  136. 136
  137. 137 *********************************************************************************************************
  138. 138
  139. 139 * 函 数 名: TCPnetTest
  140. 140
  141. 141 * 功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
  142. 142
  143. 143 * 形 参: 无
  144. 144
  145. 145 * 返 回 值: 无
  146. 146
  147. 147 *********************************************************************************************************
  148. 148
  149. 149 */
  150. 150
  151. 151 void TCPnetTest(void)
  152. 152
  153. 153 {
  154. 154
  155. 155 uint32_t tstart, tend;
  156. 156
  157. 157
  158. 158
  159. 159 /* 初始化变量 */
  160. 160
  161. 161 dhcp_tout = DHCP_TOUT;
  162. 162
  163. 163 tstart = os_time_get();
  164. 164
  165. 165
  166. 166
  167. 167 while (1)
  168. 168
  169. 169 {
  170. 170
  171. 171 /* 每100ms做一次DHCP检测 */
  172. 172
  173. 173 if(dhcp_tout != 0)
  174. 174
  175. 175 {
  176. 176
  177. 177 tend = os_time_get() - tstart;
  178. 178
  179. 179 //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
  180. 180
  181. 181 if(tend >= 100)
  182. 182
  183. 183 {
  184. 184
  185. 185 tstart = os_time_get();
  186. 186
  187. 187 dhcp_check();
  188. 188
  189. 189 }
  190. 190
  191. 191 }
  192. 192
  193. 193
  194. 194
  195. 195 os_evt_wait_and(0x0001, 0xFFFF);
  196. 196
  197. 197 while (main_TcpNet() == __TRUE);
  198. 198
  199. 199 }
  200. 200
  201. 201 }

26.6 网络调试助手和板子的操作步骤

因为这个例子是基于前面第19章BSD Socket服务器的例子简单修改而来,所以操作步骤直接看第19章的19.9小节即可。

26.7 实验例程说明(RTX)

26.7.1 STM32F407开发板实验

配套例子:

V5-1033_RL-TCPnet实验_DHCP应用(RTX)

实验目的:

  1. 学习RL-TCPnet的DHCP应用。

实验内容:

  1. DHCP已经使能,如果插上网线8秒内无法从路由器/交换机获得IP地址,将使用固定IP:192.168.1.100。此固定IP是在配置向导文件Net_Config.c里面设置的。
  2. 本例程创建了一个socket服务器,采用TCP通信协议,而且使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获得板子的IP地址,本地端口被设置为1024。
  3. 用户可以在电脑端用网络调试软件创建TCP Client连接此服务器。
  4. 网络调试助手发送命令字符1,板子回复字符1到8以及回车和换行两个字符,共10个。
  5. 网络调试助手发送命令字符2,板子回复1024个字符,前4个字符是abcd,最后4个字符是efgh,中间的1016个全部是字符0。

实验操作:

详见本章节26.6小节。

配置向导文件设置(Net_Config.c):

详见本章节26.3小节。

调试文件设置(Net_Debug.c):

详见本章节26.4小节。

RTX配置:

RTX配置向导详情如下:

Task Configuration

(1)Number of concurrent running tasks

允许创建7个任务,实际创建了如下6个任务:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     :LED闪烁。

AppTaskMsgPro任务 :按键检测。

AppTaskSocket任务  :socket服务器任务。

AppTaskTCPMain任务:RL-TCPnet网络主任务。

AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

(2)Number of tasks with user-provided stack

创建的6个任务都是采用自定义堆栈方式。

(3)Run in privileged mode

设置任务运行在非特权级模式。

RTX任务调试信息:

程序设计:

任务栈大小分配:

static uint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */

static uint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */

static uint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */

static uint64_t AppTaskSocketStk[2048/8];   /* 任务栈 */

static uint64_t AppTaskTCPMainStk[2048/8]; /* 任务栈 */

static uint64_t AppTaskStartStk[1024/8];     /* 任务栈 */

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。

系统栈大小分配:

RTX初始化:

  1. /*
  2.  
  3. *********************************************************************************************************
  4.  
  5. * 函 数 名: main
  6.  
  7. * 功能说明: 标准c程序入口。
  8.  
  9. * 形 参: 无
  10.  
  11. * 返 回 值: 无
  12.  
  13. *********************************************************************************************************
  14.  
  15. */
  16.  
  17. int main (void)
  18.  
  19. {
  20.  
  21. /* 初始化外设 */
  22.  
  23. bsp_Init();
  24.  
  25. /* 创建启动任务 */
  26.  
  27. os_sys_init_user (AppTaskStart, /* 任务函数 */
  28.  
  29. 6, /* 任务优先级 */
  30.  
  31. &AppTaskStartStk, /* 任务栈 */
  32.  
  33. sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  34.  
  35. while(1);
  36.  
  37. }

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

  1. /*
  2.  
  3. *********************************************************************************************************
  4.  
  5. * 函 数 名: bsp_Init
  6.  
  7. * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  8.  
  9. * 形 参:无
  10.  
  11. * 返 回 值: 无
  12.  
  13. *********************************************************************************************************
  14.  
  15. */
  16.  
  17. void bsp_Init(void)
  18.  
  19. {
  20.  
  21. /*
  22.  
  23. 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  24.  
  25. 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  26.  
  27. 系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  28.  
  29. */
  30.  
  31. /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  32.  
  33. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  34.  
  35. bsp_InitDWT(); /* 初始化DWT */
  36.  
  37. bsp_InitUart(); /* 初始化串口 */
  38.  
  39. bsp_InitKey(); /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  40.  
  41. bsp_InitLed(); /* 初始LED指示灯端口 */
  42.  
  43. }

RTX任务创建:

  1. 1 /*
  2. 2
  3. 3 *********************************************************************************************************
  4. 4
  5. 5 * 函 数 名: AppTaskCreate
  6. 6
  7. 7 * 功能说明: 创建应用任务
  8. 8
  9. 9 * 形 参: 无
  10. 10
  11. 11 * 返 回 值: 无
  12. 12
  13. 13 *********************************************************************************************************
  14. 14
  15. 15 */
  16. 16
  17. 17 static void AppTaskCreate (void)
  18. 18
  19. 19 {
  20. 20
  21. 21 HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */
  22. 22
  23. 23 1, /* 任务优先级 */
  24. 24
  25. 25 &AppTaskUserIFStk, /* 任务栈 */
  26. 26
  27. 27 sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  28. 28
  29. 29
  30. 30
  31. 31 HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */
  32. 32
  33. 33 2, /* 任务优先级 */
  34. 34
  35. 35 &AppTaskLEDStk, /* 任务栈 */
  36. 36
  37. 37 sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */
  38. 38
  39. 39
  40. 40
  41. 41 HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */
  42. 42
  43. 43 3, /* 任务优先级 */
  44. 44
  45. 45 &AppTaskMsgProStk, /* 任务栈 */
  46. 46
  47. 47 sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  48. 48
  49. 49
  50. 50
  51. 51 HandleTaskSocket = os_tsk_create_user(AppTaskSocket, /* 任务函数 */
  52. 52
  53. 53 4, /* 任务优先级 */
  54. 54
  55. 55 &AppTaskSocketStk, /* 任务栈 */
  56. 56
  57. 57 sizeof(AppTaskSocketStk)); /* 任务栈大小,单位字节数 */
  58. 58
  59. 59
  60. 60
  61. 61 HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain, /* 任务函数 */
  62. 62
  63. 63 5, /* 任务优先级 */
  64. 64
  65. 65 &AppTaskTCPMainStk, /* 任务栈 */
  66. 66
  67. 67 sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
  68. 68
  69. 69 }

六个RTX任务的实现:

  1. 1 /*
  2. 2
  3. 3 *********************************************************************************************************
  4. 4
  5. 5 * 函 数 名: AppTaskUserIF
  6. 6
  7. 7 * 功能说明: 按键消息处理
  8. 8
  9. 9 * 形 参: 无
  10. 10
  11. 11 * 返 回 值: 无
  12. 12
  13. 13 * 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
  14. 14
  15. 15 *********************************************************************************************************
  16. 16
  17. 17 */
  18. 18
  19. 19 __task void AppTaskUserIF(void)
  20. 20
  21. 21 {
  22. 22
  23. 23 uint8_t ucKeyCode;
  24. 24
  25. 25
  26. 26
  27. 27 while(1)
  28. 28
  29. 29 {
  30. 30
  31. 31 ucKeyCode = bsp_GetKey();
  32. 32
  33. 33
  34. 34
  35. 35 if (ucKeyCode != KEY_NONE)
  36. 36
  37. 37 {
  38. 38
  39. 39 switch (ucKeyCode)
  40. 40
  41. 41 {
  42. 42
  43. 43 /* K1键按下 */
  44. 44
  45. 45 case KEY_DOWN_K1:
  46. 46
  47. 47 printf("K1键按下\r\n");
  48. 48
  49. 49 break;
  50. 50
  51. 51
  52. 52
  53. 53 /* K2键按下 */
  54. 54
  55. 55 case KEY_DOWN_K2:
  56. 56
  57. 57 printf("K2键按下\r\n");
  58. 58
  59. 59 break;
  60. 60
  61. 61
  62. 62
  63. 63 /* K3键按下 */
  64. 64
  65. 65 case KEY_DOWN_K3:
  66. 66
  67. 67 printf("K3键按下\r\n");
  68. 68
  69. 69 break;
  70. 70
  71. 71
  72. 72
  73. 73 /* 其他的键值不处理 */
  74. 74
  75. 75 default:
  76. 76
  77. 77 break;
  78. 78
  79. 79 }
  80. 80
  81. 81 }
  82. 82
  83. 83
  84. 84
  85. 85 os_dly_wait(20);
  86. 86
  87. 87 }
  88. 88
  89. 89 }
  90. 90
  91. 91
  92. 92
  93. 93 /*
  94. 94
  95. 95 *********************************************************************************************************
  96. 96
  97. 97 * 函 数 名: AppTaskLED
  98. 98
  99. 99 * 功能说明: LED闪烁。
  100. 100
  101. 101 * 形 参: 无
  102. 102
  103. 103 * 返 回 值: 无
  104. 104
  105. 105 * 优 先 级: 2
  106. 106
  107. 107 *********************************************************************************************************
  108. 108
  109. 109 */
  110. 110
  111. 111 __task void AppTaskLED(void)
  112. 112
  113. 113 {
  114. 114
  115. 115 const uint16_t usFrequency = 500; /* 延迟周期 */
  116. 116
  117. 117
  118. 118
  119. 119 /* 设置延迟周期 */
  120. 120
  121. 121 os_itv_set(usFrequency);
  122. 122
  123. 123
  124. 124
  125. 125 while(1)
  126. 126
  127. 127 {
  128. 128
  129. 129 bsp_LedToggle(2);
  130. 130
  131. 131
  132. 132
  133. 133 /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  134. 134
  135. 135 os_itv_wait();
  136. 136
  137. 137 }
  138. 138
  139. 139 }
  140. 140
  141. 141
  142. 142
  143. 143 /*
  144. 144
  145. 145 *********************************************************************************************************
  146. 146
  147. 147 * 函 数 名: AppTaskMsgPro
  148. 148
  149. 149 * 功能说明: 按键检测
  150. 150
  151. 151 * 形 参: 无
  152. 152
  153. 153 * 返 回 值: 无
  154. 154
  155. 155 * 优 先 级: 3
  156. 156
  157. 157 *********************************************************************************************************
  158. 158
  159. 159 */
  160. 160
  161. 161 __task void AppTaskMsgPro(void)
  162. 162
  163. 163 {
  164. 164
  165. 165 while(1)
  166. 166
  167. 167 {
  168. 168
  169. 169 bsp_KeyScan();
  170. 170
  171. 171 os_dly_wait(10);
  172. 172
  173. 173 }
  174. 174
  175. 175 }
  176. 176
  177. 177
  178. 178
  179. 179 /*
  180. 180
  181. 181 *********************************************************************************************************
  182. 182
  183. 183 * 函 数 名: AppTaskSocket
  184. 184
  185. 185 * 功能说明: RL-TCPnet测试任务
  186. 186
  187. 187 * 形 参: 无
  188. 188
  189. 189 * 返 回 值: 无
  190. 190
  191. 191 * 优 先 级: 4
  192. 192
  193. 193 *********************************************************************************************************
  194. 194
  195. 195 */
  196. 196
  197. 197 __task void AppTaskSocket(void)
  198. 198
  199. 199 {
  200. 200
  201. 201 while (1)
  202. 202
  203. 203 {
  204. 204
  205. 205 SocketTest();
  206. 206
  207. 207 }
  208. 208
  209. 209 }
  210. 210
  211. 211
  212. 212
  213. 213 /*
  214. 214
  215. 215 *********************************************************************************************************
  216. 216
  217. 217 * 函 数 名: AppTaskTCPMain
  218. 218
  219. 219 * 功能说明: RL-TCPnet网络主任务
  220. 220
  221. 221 * 形 参: 无
  222. 222
  223. 223 * 返 回 值: 无
  224. 224
  225. 225 * 优 先 级: 5
  226. 226
  227. 227 *********************************************************************************************************
  228. 228
  229. 229 */
  230. 230
  231. 231 __task void AppTaskTCPMain(void)
  232. 232
  233. 233 {
  234. 234
  235. 235 while (1)
  236. 236
  237. 237 {
  238. 238
  239. 239 TCPnetTest();
  240. 240
  241. 241 }
  242. 242
  243. 243 }
  244. 244
  245. 245
  246. 246
  247. 247 /*
  248. 248
  249. 249 *********************************************************************************************************
  250. 250
  251. 251 * 函 数 名: AppTaskStart
  252. 252
  253. 253 * 功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
  254. 254
  255. 255 * 形 参: 无
  256. 256
  257. 257 * 返 回 值: 无
  258. 258
  259. 259 * 优 先 级: 6
  260. 260
  261. 261 *********************************************************************************************************
  262. 262
  263. 263 */
  264. 264
  265. 265 __task void AppTaskStart(void)
  266. 266
  267. 267 {
  268. 268
  269. 269 /* 初始化RL-TCPnet */
  270. 270
  271. 271 init_TcpNet ();
  272. 272
  273. 273
  274. 274
  275. 275 /* 创建任务 */
  276. 276
  277. 277 AppTaskCreate();
  278. 278
  279. 279
  280. 280
  281. 281 os_itv_set (100);
  282. 282
  283. 283
  284. 284
  285. 285 while(1)
  286. 286
  287. 287 {
  288. 288
  289. 289 os_itv_wait ();
  290. 290
  291. 291
  292. 292
  293. 293 /* RL-TCPnet时间基准更新函数 */
  294. 294
  295. 295 timer_tick ();
  296. 296
  297. 297 }
  298. 298
  299. 299 }

RL-TCPnet网络主任务

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet的网络主任务,实现动态IP获取和网络协议栈主函数main_TcpNet的调用。

  1. 1 #include "includes.h"
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11 /*
  12. 12
  13. 13 *********************************************************************************************************
  14. 14
  15. 15 * 用于本文件的调试
  16. 16
  17. 17 *********************************************************************************************************
  18. 18
  19. 19 */
  20. 20
  21. 21 #if 1
  22. 22
  23. 23 #define printf_tcpdbg printf
  24. 24
  25. 25 #else
  26. 26
  27. 27 #define printf_tcpdbg(...)
  28. 28
  29. 29 #endif
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35 /*
  36. 36
  37. 37 **********************************************************************************************************
  38. 38
  39. 39 外部调用
  40. 40
  41. 41 **********************************************************************************************************
  42. 42
  43. 43 */
  44. 44
  45. 45 #define DHCP_TOUT 80 /* DHCP动态IP获取的溢出时间设置为8秒 */
  46. 46
  47. 47 #define MY_IP localm[NETIF_ETH].IpAdr
  48. 48
  49. 49 extern LOCALM localm[];
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55 /*
  56. 56
  57. 57 **********************************************************************************************************
  58. 58
  59. 59 变量
  60. 60
  61. 61 **********************************************************************************************************
  62. 62
  63. 63 */
  64. 64
  65. 65 uint32_t dhcp_tout;
  66. 66
  67. 67 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",
  68. 68
  69. 69 "Waiting for DHCP"};
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75 /*
  76. 76
  77. 77 *********************************************************************************************************
  78. 78
  79. 79 * 函 数 名: main
  80. 80
  81. 81 * 功能说明: 标准c程序入口。
  82. 82
  83. 83 * 形 参: 无
  84. 84
  85. 85 * 返 回 值: 无
  86. 86
  87. 87 *********************************************************************************************************
  88. 88
  89. 89 */
  90. 90
  91. 91 static void dhcp_check(void)
  92. 92
  93. 93 {
  94. 94
  95. 95
  96. 96
  97. 97 /* 检测是否通过DHCP自动获得IP */
  98. 98
  99. 99 if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
  100. 100
  101. 101 {
  102. 102
  103. 103 /* 已经获得IP */
  104. 104
  105. 105 dhcp_tout = 0;
  106. 106
  107. 107 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  108. 108
  109. 109 MY_IP[2], MY_IP[3]);
  110. 110
  111. 111 sprintf((char *)DHCP_Status[1],"DHCP Success");
  112. 112
  113. 113 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  114. 114
  115. 115 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  116. 116
  117. 117 return;
  118. 118
  119. 119 }
  120. 120
  121. 121
  122. 122
  123. 123 /* 每100ms进行一次减减操作 */
  124. 124
  125. 125 if (--dhcp_tout == 0)
  126. 126
  127. 127 {
  128. 128
  129. 129 /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
  130. 130
  131. 131 dhcp_disable ();
  132. 132
  133. 133 sprintf((char *)DHCP_Status[1],"DHCP Failed" );
  134. 134
  135. 135 /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
  136. 136
  137. 137 dhcp_tout = 80 | 0x80000000;
  138. 138
  139. 139 return;
  140. 140
  141. 141 }
  142. 142
  143. 143
  144. 144
  145. 145 /* 设置固定IP的8秒时间到 */
  146. 146
  147. 147 if (dhcp_tout == 0x80000000)
  148. 148
  149. 149 {
  150. 150
  151. 151 dhcp_tout = 0;
  152. 152
  153. 153 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  154. 154
  155. 155 MY_IP[2], MY_IP[3]);
  156. 156
  157. 157 sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
  158. 158
  159. 159 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  160. 160
  161. 161 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  162. 162
  163. 163 }
  164. 164
  165. 165 }
  166. 166
  167. 167
  168. 168
  169. 169 /*
  170. 170
  171. 171 *********************************************************************************************************
  172. 172
  173. 173 * 函 数 名: TCPnetTest
  174. 174
  175. 175 * 功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
  176. 176
  177. 177 * 形 参: 无
  178. 178
  179. 179 * 返 回 值: 无
  180. 180
  181. 181 *********************************************************************************************************
  182. 182
  183. 183 */
  184. 184
  185. 185 void TCPnetTest(void)
  186. 186
  187. 187 {
  188. 188
  189. 189 uint32_t tstart, tend;
  190. 190
  191. 191
  192. 192
  193. 193 /* 初始化变量 */
  194. 194
  195. 195 dhcp_tout = DHCP_TOUT;
  196. 196
  197. 197 tstart = os_time_get();
  198. 198
  199. 199
  200. 200
  201. 201 while (1)
  202. 202
  203. 203 {
  204. 204
  205. 205 /* 每100ms做一次DHCP检测 */
  206. 206
  207. 207 if(dhcp_tout != 0)
  208. 208
  209. 209 {
  210. 210
  211. 211 tend = os_time_get() - tstart;
  212. 212
  213. 213 //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
  214. 214
  215. 215 if(tend >= 100)
  216. 216
  217. 217 {
  218. 218
  219. 219 tstart = os_time_get();
  220. 220
  221. 221 dhcp_check();
  222. 222
  223. 223 }
  224. 224
  225. 225 }
  226. 226
  227. 227
  228. 228
  229. 229 os_evt_wait_and(0x0001, 0xFFFF);
  230. 230
  231. 231 while (main_TcpNet() == __TRUE);
  232. 232
  233. 233 }
  234. 234
  235. 235 }

Socket 服务器任务

这里专门创建了一个app_socket_lib.c文件用于socket服务器任务。

  1. 1 #include "includes.h"
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9 /*
  10. 10
  11. 11 *********************************************************************************************************
  12. 12
  13. 13 * 用于本文件的调试
  14. 14
  15. 15 *********************************************************************************************************
  16. 16
  17. 17 */
  18. 18
  19. 19 #if 1
  20. 20
  21. 21 #define printf_debug printf
  22. 22
  23. 23 #else
  24. 24
  25. 25 #define printf_debug(...)
  26. 26
  27. 27 #endif
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33 /*
  34. 34
  35. 35 *********************************************************************************************************
  36. 36
  37. 37 * 宏定义,本地端口
  38. 38
  39. 39 *********************************************************************************************************
  40. 40
  41. 41 */
  42. 42
  43. 43 /* 这个是本地端口 */
  44. 44
  45. 45 #define LocalPort_NUM 1001
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51 /*
  52. 52
  53. 53 *********************************************************************************************************
  54. 54
  55. 55 * 变量
  56. 56
  57. 57 *********************************************************************************************************
  58. 58
  59. 59 */
  60. 60
  61. 61 /* RL-TCPnet API的返回值 */
  62. 62
  63. 63 const char * ReVal_Table[]=
  64. 64
  65. 65 {
  66. 66
  67. 67 " 0: SCK_SUCCESS Success ",
  68. 68
  69. 69 "-1: SCK_ERROR General Error ",
  70. 70
  71. 71 "-2: SCK_EINVALID Invalid socket descriptor ",
  72. 72
  73. 73 "-3: SCK_EINVALIDPARA Invalid parameter ",
  74. 74
  75. 75 "-4: SCK_EWOULDBLOCK It would have blocked. ",
  76. 76
  77. 77 "-5: SCK_EMEMNOTAVAIL Not enough memory in memory pool ",
  78. 78
  79. 79 "-6: SCK_ECLOSED Connection is closed or aborted ",
  80. 80
  81. 81 "-7: SCK_ELOCKED Socket is locked in RTX environment ",
  82. 82
  83. 83 "-8: SCK_ETIMEOUT Socket, Host Resolver timeout ",
  84. 84
  85. 85 "-9: SCK_EINPROGRESS Host Name resolving in progress ",
  86. 86
  87. 87 "-10: SCK_ENONAME Host Name not existing ",
  88. 88
  89. 89 };
  90. 90
  91. 91
  92. 92
  93. 93 uint8_t sendbuf[1024];
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99 /*
  100. 100
  101. 101 *********************************************************************************************************
  102. 102
  103. 103 * 函 数 名: SocketTest
  104. 104
  105. 105 * 功能说明: Socket应用
  106. 106
  107. 107 * 形 参: 无
  108. 108
  109. 109 * 返 回 值: 无
  110. 110
  111. 111 *********************************************************************************************************
  112. 112
  113. 113 */
  114. 114
  115. 115 void SocketTest(void)
  116. 116
  117. 117 {
  118. 118
  119. 119 char dbuf[10];
  120. 120
  121. 121 int len;
  122. 122
  123. 123 int sock, sd, res;
  124. 124
  125. 125 SOCKADDR_IN addr;
  126. 126
  127. 127 SOCKADDR_IN ReAddr;
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133 while (1)
  134. 134
  135. 135 {
  136. 136
  137. 137 /* 创建一个socket
  138. 138
  139. 139 第1个参数AF_INET:当前仅支持这个类型的地址族。
  140. 140
  141. 141 第2个参数SOCK_STREAM:表示数据流通信类型,即使用的TCP。
  142. 142
  143. 143 第3个参数0 :配置为0的话,自动跟第2个参数进行协议匹配,这里就是TCP协议。
  144. 144
  145. 145 */
  146. 146
  147. 147 sock = socket (AF_INET, SOCK_STREAM, 0);
  148. 148
  149. 149
  150. 150
  151. 151 /* 端口号设置为1001 */
  152. 152
  153. 153 addr.sin_port = htons(LocalPort_NUM);
  154. 154
  155. 155
  156. 156
  157. 157 /* 与函数socket中的AF_INET作用一样 */
  158. 158
  159. 159 addr.sin_family = PF_INET;
  160. 160
  161. 161 /*
  162. 162
  163. 163 INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或所有地址,
  164. 164
  165. 165 任意地址。用在这里的话就表示监控端口号为ddr.sin_port的所有IP地址消息。一般主要用
  166. 166
  167. 167 于有多个网卡或者IP地址的情况。开发板只用了DM9161的网口,就是监听这个网口的IP地址。
  168. 168
  169. 169 */
  170. 170
  171. 171 addr.sin_addr.s_addr = INADDR_ANY;
  172. 172
  173. 173
  174. 174
  175. 175 /* 给socket绑定IP和端口号 */
  176. 176
  177. 177 bind (sock, (SOCKADDR *)&addr, sizeof(addr));
  178. 178
  179. 179
  180. 180
  181. 181 /* 设置监听,最大监听1个连接 */
  182. 182
  183. 183 listen (sock, 1);
  184. 184
  185. 185
  186. 186
  187. 187 /*
  188. 188
  189. 189 等待soket连接请求,有的话,自动创建1个新的socket进行连接通信,没有的话,等待连接。
  190. 190
  191. 191 注意,能够accept的个数受到listen函数的限制,而listen函数又受到Net_Config.c中宏定义
  192. 192
  193. 193 BSD_NUMSOCKS 的限制。
  194. 194
  195. 195 */
  196. 196
  197. 197 len = sizeof(ReAddr);
  198. 198
  199. 199 sd = accept (sock, (SOCKADDR *)&ReAddr, &len);
  200. 200
  201. 201 printf_debug ("远程客户端请求连接IP: %d.%d.%d.%d\n", ReAddr.sin_addr.s_b1,
  202. 202
  203. 203 ReAddr.sin_addr.s_b2,
  204. 204
  205. 205 ReAddr.sin_addr.s_b3,
  206. 206
  207. 207 ReAddr.sin_addr.s_b4);
  208. 208
  209. 209 printf_debug ("远程客户端端口号: %d\n", ntohs(ReAddr.sin_port));
  210. 210
  211. 211
  212. 212
  213. 213 /* 关闭监听socket,这个监听socket是调用函数socket后自动创建的 */
  214. 214
  215. 215 closesocket (sock);
  216. 216
  217. 217 sock = sd;
  218. 218
  219. 219
  220. 220
  221. 221
  222. 222
  223. 223 while (1)
  224. 224
  225. 225 {
  226. 226
  227. 227 /*
  228. 228
  229. 229 socket数据接收函数,如果recv工作在阻塞模式,使用这个函数注意以下事项:
  230. 230
  231. 231 1. 此函数的溢出时间受到Net_Config.c中宏定义 BSD_RCVTOUT 的限制。溢出时间到会自动退出。
  232. 232
  233. 233 2. 这个函数接收到一次数据包就会返回,大于或者小于设置的缓冲区大小都没有关系,如果数据量
  234. 234
  235. 235 大于接收缓冲区大小,用户只需多次调用函数recv进行接收即可。
  236. 236
  237. 237 3. 实际接收到数据大小通过判断此函数的返回值即可。
  238. 238
  239. 239 */
  240. 240
  241. 241 res = recv (sock, dbuf, sizeof(dbuf), 0);
  242. 242
  243. 243 if (res <= 0)
  244. 244
  245. 245 {
  246. 246
  247. 247 printf_debug("退出接收函数,重新开始监听%s\r\n", ReVal_Table[abs(res)]);
  248. 248
  249. 249 break;
  250. 250
  251. 251 }
  252. 252
  253. 253 else
  254. 254
  255. 255 {
  256. 256
  257. 257 printf_debug("Receive Data Length = %d\r\n", res);
  258. 258
  259. 259 switch(dbuf[0])
  260. 260
  261. 261 {
  262. 262
  263. 263 /* 字符命令 1 */
  264. 264
  265. 265 case '1':
  266. 266
  267. 267 sendbuf[0] = '1';
  268. 268
  269. 269 sendbuf[1] = '2';
  270. 270
  271. 271 sendbuf[2] = '3';
  272. 272
  273. 273 sendbuf[3] = '4';
  274. 274
  275. 275 sendbuf[4] = '5';
  276. 276
  277. 277 sendbuf[5] = '6';
  278. 278
  279. 279 sendbuf[6] = '7';
  280. 280
  281. 281 sendbuf[7] = '8';
  282. 282
  283. 283 sendbuf[8] = '\r';
  284. 284
  285. 285 sendbuf[9] = '\n';
  286. 286
  287. 287 res = send (sock, (char *)sendbuf, 10, 0);
  288. 288
  289. 289 if (res < 0)
  290. 290
  291. 291 {
  292. 292
  293. 293 printf_debug("函数send发送数据失败\r\n");
  294. 294
  295. 295 }
  296. 296
  297. 297 else
  298. 298
  299. 299 {
  300. 300
  301. 301 printf_debug("函数send发送数据成功\r\n");
  302. 302
  303. 303 }
  304. 304
  305. 305 break;
  306. 306
  307. 307
  308. 308
  309. 309 /* 字符命令 2 */
  310. 310
  311. 311 case '2':
  312. 312
  313. 313 /* 将数据缓冲区清成字符0,方便网络调试助手查看数据 */
  314. 314
  315. 315 len = sizeof(sendbuf);
  316. 316
  317. 317 memset(sendbuf, 48, len);
  318. 318
  319. 319
  320. 320
  321. 321 /* 这里仅初始化了数据包的前4个字节和最后4个字节 */
  322. 322
  323. 323 sendbuf[0] = 'a';
  324. 324
  325. 325 sendbuf[1] = 'b';
  326. 326
  327. 327 sendbuf[2] = 'c';
  328. 328
  329. 329 sendbuf[3] = 'd';
  330. 330
  331. 331 sendbuf[len - 4] = 'e';
  332. 332
  333. 333 sendbuf[len - 3] = 'f';
  334. 334
  335. 335 sendbuf[len - 2] = 'g';
  336. 336
  337. 337 sendbuf[len - 1] = 'h';
  338. 338
  339. 339 res = send (sock, (char *)sendbuf, len, 0);
  340. 340
  341. 341 if (res < 0)
  342. 342
  343. 343 {
  344. 344
  345. 345 printf_debug("函数send发送数据失败%s\r\n", ReVal_Table[abs(res)]);
  346. 346
  347. 347 }
  348. 348
  349. 349 else
  350. 350
  351. 351 {
  352. 352
  353. 353 printf_debug("函数send成功发送数据 = %d字节\r\n", res);
  354. 354
  355. 355 }
  356. 356
  357. 357 break;
  358. 358
  359. 359
  360. 360
  361. 361 /* 其它数值不做处理 */
  362. 362
  363. 363 default:
  364. 364
  365. 365 break;
  366. 366
  367. 367 }
  368. 368
  369. 369 }
  370. 370
  371. 371
  372. 372
  373. 373 }
  374. 374
  375. 375
  376. 376
  377. 377 /*
  378. 378
  379. 379 溢出时间到,远程设备断开连接等,程序都会执行到这里,我们在这里关闭socket,
  380. 380
  381. 381 程序返回到第一个大while循环的开头重新创建socket并监听。
  382. 382
  383. 383 */
  384. 384
  385. 385 closesocket (sock);
  386. 386
  387. 387 }
  388. 388
  389. 389 }

26.7.2 STM32F429开发板实验

配套例子:

V6-1033_RL-TCPnet实验_DHCP应用(RTX)

实验目的:

  1. 学习RL-TCPnet的DHCP应用。

实验内容:

  1. DHCP已经使能,如果插上网线8秒内无法从路由器/交换机获得IP地址,将使用固定IP:192.168.1.100。此固定IP是在配置向导文件Net_Config.c里面设置的。
  2. 本例程创建了一个socket服务器,采用TCP通信协议,而且使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获得板子的IP地址,本地端口被设置为1024。
  3. 用户可以在电脑端用网络调试软件创建TCP Client连接此服务器。
  4. 网络调试助手发送命令字符1,板子回复字符1到8以及回车和换行两个字符,共10个。
  5. 网络调试助手发送命令字符2,板子回复1024个字符,前4个字符是abcd,最后4个字符是efgh,中间的1016个全部是字符0。

实验操作:

详见本章节26.6小节。

配置向导文件设置(Net_Config.c):

详见本章节26.3小节。

调试文件设置(Net_Debug.c):

详见本章节26.4小节。

RTX配置:

RTX配置向导详情如下:

Task Configuration

(1)Number of concurrent running tasks

允许创建7个任务,实际创建了如下6个任务:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     :LED闪烁。

AppTaskMsgPro任务 :按键检测。

AppTaskSocket任务  :socket服务器任务

AppTaskTCPMain任务:RL-TCPnet网络主任务。

AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

(2)Number of tasks with user-provided stack

创建的6个任务都是采用自定义堆栈方式。

(3)Run in privileged mode

设置任务运行在非特权级模式。

RTX任务调试信息:

程序设计:

任务栈大小分配:

static uint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */

static uint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */

static uint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */

static uint64_t AppTaskSocketStk[2048/8];   /* 任务栈 */

static uint64_t AppTaskTCPMainStk[2048/8]; /* 任务栈 */

static uint64_t AppTaskStartStk[1024/8];     /* 任务栈 */

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。

系统栈大小分配:

RTX初始化:

  1. /*
  2.  
  3. *********************************************************************************************************
  4.  
  5. * 函 数 名: main
  6.  
  7. * 功能说明: 标准c程序入口。
  8.  
  9. * 形 参: 无
  10.  
  11. * 返 回 值: 无
  12.  
  13. *********************************************************************************************************
  14.  
  15. */
  16.  
  17. int main (void)
  18.  
  19. {
  20.  
  21. /* 初始化外设 */
  22.  
  23. bsp_Init();
  24.  
  25. /* 创建启动任务 */
  26.  
  27. os_sys_init_user (AppTaskStart, /* 任务函数 */
  28.  
  29. 6, /* 任务优先级 */
  30.  
  31. &AppTaskStartStk, /* 任务栈 */
  32.  
  33. sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  34.  
  35. while(1);
  36.  
  37. }

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

  1. 1 /*
  2. 2
  3. 3 *********************************************************************************************************
  4. 4
  5. 5 * 函 数 名: bsp_Init
  6. 6
  7. 7 * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  8. 8
  9. 9 * 形 参:无
  10. 10
  11. 11 * 返 回 值: 无
  12. 12
  13. 13 *********************************************************************************************************
  14. 14
  15. 15 */
  16. 16
  17. 17 void bsp_Init(void)
  18. 18
  19. 19 {
  20. 20
  21. 21 /*
  22. 22
  23. 23 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  24. 24
  25. 25 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  26. 26
  27. 27
  28. 28
  29. 29 系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  30. 30
  31. 31 */
  32. 32
  33. 33 /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  34. 34
  35. 35 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  36. 36
  37. 37
  38. 38
  39. 39 SystemCoreClockUpdate(); /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  40. 40
  41. 41
  42. 42
  43. 43 bsp_InitDWT(); /* 初始化DWT */
  44. 44
  45. 45 bsp_InitUart(); /* 初始化串口 */
  46. 46
  47. 47 bsp_InitKey(); /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  48. 48
  49. 49
  50. 50
  51. 51 bsp_InitExtIO(); /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  52. 52
  53. 53 bsp_InitLed(); /* 初始LED指示灯端口 */
  54. 54
  55. 55 }

RTX任务创建:

  1. 1 /*
  2. 2
  3. 3 *********************************************************************************************************
  4. 4
  5. 5 * 函 数 名: AppTaskCreate
  6. 6
  7. 7 * 功能说明: 创建应用任务
  8. 8
  9. 9 * 形 参: 无
  10. 10
  11. 11 * 返 回 值: 无
  12. 12
  13. 13 *********************************************************************************************************
  14. 14
  15. 15 */
  16. 16
  17. 17 static void AppTaskCreate (void)
  18. 18
  19. 19 {
  20. 20
  21. 21 HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */
  22. 22
  23. 23 1, /* 任务优先级 */
  24. 24
  25. 25 &AppTaskUserIFStk, /* 任务栈 */
  26. 26
  27. 27 sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  28. 28
  29. 29
  30. 30
  31. 31 HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */
  32. 32
  33. 33 2, /* 任务优先级 */
  34. 34
  35. 35 &AppTaskLEDStk, /* 任务栈 */
  36. 36
  37. 37 sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */
  38. 38
  39. 39
  40. 40
  41. 41 HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */
  42. 42
  43. 43 3, /* 任务优先级 */
  44. 44
  45. 45 &AppTaskMsgProStk, /* 任务栈 */
  46. 46
  47. 47 sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  48. 48
  49. 49
  50. 50
  51. 51 HandleTaskSocket = os_tsk_create_user(AppTaskSocket, /* 任务函数 */
  52. 52
  53. 53 4, /* 任务优先级 */
  54. 54
  55. 55 &AppTaskSocketStk, /* 任务栈 */
  56. 56
  57. 57 sizeof(AppTaskSocketStk)); /* 任务栈大小,单位字节数 */
  58. 58
  59. 59
  60. 60
  61. 61 HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain, /* 任务函数 */
  62. 62
  63. 63 5, /* 任务优先级 */
  64. 64
  65. 65 &AppTaskTCPMainStk, /* 任务栈 */
  66. 66
  67. 67 sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
  68. 68
  69. 69 }

六个RTX任务的实现:

  1. 1 /*
  2. 2
  3. 3 *********************************************************************************************************
  4. 4
  5. 5 * 函 数 名: AppTaskUserIF
  6. 6
  7. 7 * 功能说明: 按键消息处理
  8. 8
  9. 9 * 形 参: 无
  10. 10
  11. 11 * 返 回 值: 无
  12. 12
  13. 13 * 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
  14. 14
  15. 15 *********************************************************************************************************
  16. 16
  17. 17 */
  18. 18
  19. 19 __task void AppTaskUserIF(void)
  20. 20
  21. 21 {
  22. 22
  23. 23 uint8_t ucKeyCode;
  24. 24
  25. 25
  26. 26
  27. 27 while(1)
  28. 28
  29. 29 {
  30. 30
  31. 31 ucKeyCode = bsp_GetKey();
  32. 32
  33. 33
  34. 34
  35. 35 if (ucKeyCode != KEY_NONE)
  36. 36
  37. 37 {
  38. 38
  39. 39 switch (ucKeyCode)
  40. 40
  41. 41 {
  42. 42
  43. 43 /* K1键按下 */
  44. 44
  45. 45 case KEY_DOWN_K1:
  46. 46
  47. 47 printf("K1键按下\r\n");
  48. 48
  49. 49 break;
  50. 50
  51. 51
  52. 52
  53. 53 /* K2键按下 */
  54. 54
  55. 55 case KEY_DOWN_K2:
  56. 56
  57. 57 printf("K2键按下\r\n");
  58. 58
  59. 59 break;
  60. 60
  61. 61
  62. 62
  63. 63 /* K3键按下 */
  64. 64
  65. 65 case KEY_DOWN_K3:
  66. 66
  67. 67 printf("K3键按下\r\n");
  68. 68
  69. 69 break;
  70. 70
  71. 71
  72. 72
  73. 73 /* 其他的键值不处理 */
  74. 74
  75. 75 default:
  76. 76
  77. 77 break;
  78. 78
  79. 79 }
  80. 80
  81. 81 }
  82. 82
  83. 83
  84. 84
  85. 85 os_dly_wait(20);
  86. 86
  87. 87 }
  88. 88
  89. 89 }
  90. 90
  91. 91
  92. 92
  93. 93 /*
  94. 94
  95. 95 *********************************************************************************************************
  96. 96
  97. 97 * 函 数 名: AppTaskLED
  98. 98
  99. 99 * 功能说明: LED闪烁。
  100. 100
  101. 101 * 形 参: 无
  102. 102
  103. 103 * 返 回 值: 无
  104. 104
  105. 105 * 优 先 级: 2
  106. 106
  107. 107 *********************************************************************************************************
  108. 108
  109. 109 */
  110. 110
  111. 111 __task void AppTaskLED(void)
  112. 112
  113. 113 {
  114. 114
  115. 115 const uint16_t usFrequency = 500; /* 延迟周期 */
  116. 116
  117. 117
  118. 118
  119. 119 /* 设置延迟周期 */
  120. 120
  121. 121 os_itv_set(usFrequency);
  122. 122
  123. 123
  124. 124
  125. 125 while(1)
  126. 126
  127. 127 {
  128. 128
  129. 129 bsp_LedToggle(2);
  130. 130
  131. 131
  132. 132
  133. 133 /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  134. 134
  135. 135 os_itv_wait();
  136. 136
  137. 137 }
  138. 138
  139. 139 }
  140. 140
  141. 141
  142. 142
  143. 143 /*
  144. 144
  145. 145 *********************************************************************************************************
  146. 146
  147. 147 * 函 数 名: AppTaskMsgPro
  148. 148
  149. 149 * 功能说明: 按键检测
  150. 150
  151. 151 * 形 参: 无
  152. 152
  153. 153 * 返 回 值: 无
  154. 154
  155. 155 * 优 先 级: 3
  156. 156
  157. 157 *********************************************************************************************************
  158. 158
  159. 159 */
  160. 160
  161. 161 __task void AppTaskMsgPro(void)
  162. 162
  163. 163 {
  164. 164
  165. 165 while(1)
  166. 166
  167. 167 {
  168. 168
  169. 169 bsp_KeyScan();
  170. 170
  171. 171 os_dly_wait(10);
  172. 172
  173. 173 }
  174. 174
  175. 175 }
  176. 176
  177. 177
  178. 178
  179. 179 /*
  180. 180
  181. 181 *********************************************************************************************************
  182. 182
  183. 183 * 函 数 名: AppTaskSocket
  184. 184
  185. 185 * 功能说明: RL-TCPnet测试任务
  186. 186
  187. 187 * 形 参: 无
  188. 188
  189. 189 * 返 回 值: 无
  190. 190
  191. 191 * 优 先 级: 4
  192. 192
  193. 193 *********************************************************************************************************
  194. 194
  195. 195 */
  196. 196
  197. 197 __task void AppTaskSocket(void)
  198. 198
  199. 199 {
  200. 200
  201. 201 while (1)
  202. 202
  203. 203 {
  204. 204
  205. 205 SocketTest();
  206. 206
  207. 207 }
  208. 208
  209. 209 }
  210. 210
  211. 211
  212. 212
  213. 213 /*
  214. 214
  215. 215 *********************************************************************************************************
  216. 216
  217. 217 * 函 数 名: AppTaskTCPMain
  218. 218
  219. 219 * 功能说明: RL-TCPnet网络主任务
  220. 220
  221. 221 * 形 参: 无
  222. 222
  223. 223 * 返 回 值: 无
  224. 224
  225. 225 * 优 先 级: 5
  226. 226
  227. 227 *********************************************************************************************************
  228. 228
  229. 229 */
  230. 230
  231. 231 __task void AppTaskTCPMain(void)
  232. 232
  233. 233 {
  234. 234
  235. 235 while (1)
  236. 236
  237. 237 {
  238. 238
  239. 239 TCPnetTest();
  240. 240
  241. 241 }
  242. 242
  243. 243 }
  244. 244
  245. 245
  246. 246
  247. 247 /*
  248. 248
  249. 249 *********************************************************************************************************
  250. 250
  251. 251 * 函 数 名: AppTaskStart
  252. 252
  253. 253 * 功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
  254. 254
  255. 255 * 形 参: 无
  256. 256
  257. 257 * 返 回 值: 无
  258. 258
  259. 259 * 优 先 级: 6
  260. 260
  261. 261 *********************************************************************************************************
  262. 262
  263. 263 */
  264. 264
  265. 265 __task void AppTaskStart(void)
  266. 266
  267. 267 {
  268. 268
  269. 269 /* 初始化RL-TCPnet */
  270. 270
  271. 271 init_TcpNet ();
  272. 272
  273. 273
  274. 274
  275. 275 /* 创建任务 */
  276. 276
  277. 277 AppTaskCreate();
  278. 278
  279. 279
  280. 280
  281. 281 os_itv_set (100);
  282. 282
  283. 283
  284. 284
  285. 285 while(1)
  286. 286
  287. 287 {
  288. 288
  289. 289 os_itv_wait ();
  290. 290
  291. 291
  292. 292
  293. 293 /* RL-TCPnet时间基准更新函数 */
  294. 294
  295. 295 timer_tick ();
  296. 296
  297. 297 }
  298. 298
  299. 299 }

RL-TCPnet网络主任务

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet的网络主任务,实现动态IP获取和网络协议栈主函数main_TcpNet的调用。

  1. 1 #include "includes.h"
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11 /*
  12. 12
  13. 13 *********************************************************************************************************
  14. 14
  15. 15 * 用于本文件的调试
  16. 16
  17. 17 *********************************************************************************************************
  18. 18
  19. 19 */
  20. 20
  21. 21 #if 1
  22. 22
  23. 23 #define printf_tcpdbg printf
  24. 24
  25. 25 #else
  26. 26
  27. 27 #define printf_tcpdbg(...)
  28. 28
  29. 29 #endif
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35 /*
  36. 36
  37. 37 **********************************************************************************************************
  38. 38
  39. 39 外部调用
  40. 40
  41. 41 **********************************************************************************************************
  42. 42
  43. 43 */
  44. 44
  45. 45 #define DHCP_TOUT 80 /* DHCP动态IP获取的溢出时间设置为8秒 */
  46. 46
  47. 47 #define MY_IP localm[NETIF_ETH].IpAdr
  48. 48
  49. 49 extern LOCALM localm[];
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55 /*
  56. 56
  57. 57 **********************************************************************************************************
  58. 58
  59. 59 变量
  60. 60
  61. 61 **********************************************************************************************************
  62. 62
  63. 63 */
  64. 64
  65. 65 uint32_t dhcp_tout;
  66. 66
  67. 67 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",
  68. 68
  69. 69 "Waiting for DHCP"};
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75 /*
  76. 76
  77. 77 *********************************************************************************************************
  78. 78
  79. 79 * 函 数 名: main
  80. 80
  81. 81 * 功能说明: 标准c程序入口。
  82. 82
  83. 83 * 形 参: 无
  84. 84
  85. 85 * 返 回 值: 无
  86. 86
  87. 87 *********************************************************************************************************
  88. 88
  89. 89 */
  90. 90
  91. 91 static void dhcp_check(void)
  92. 92
  93. 93 {
  94. 94
  95. 95
  96. 96
  97. 97 /* 检测是否通过DHCP自动获得IP */
  98. 98
  99. 99 if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
  100. 100
  101. 101 {
  102. 102
  103. 103 /* 已经获得IP */
  104. 104
  105. 105 dhcp_tout = 0;
  106. 106
  107. 107 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  108. 108
  109. 109 MY_IP[2], MY_IP[3]);
  110. 110
  111. 111 sprintf((char *)DHCP_Status[1],"DHCP Success");
  112. 112
  113. 113 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  114. 114
  115. 115 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  116. 116
  117. 117 return;
  118. 118
  119. 119 }
  120. 120
  121. 121
  122. 122
  123. 123 /* 每100ms进行一次减减操作 */
  124. 124
  125. 125 if (--dhcp_tout == 0)
  126. 126
  127. 127 {
  128. 128
  129. 129 /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
  130. 130
  131. 131 dhcp_disable ();
  132. 132
  133. 133 sprintf((char *)DHCP_Status[1],"DHCP Failed" );
  134. 134
  135. 135 /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
  136. 136
  137. 137 dhcp_tout = 80 | 0x80000000;
  138. 138
  139. 139 return;
  140. 140
  141. 141 }
  142. 142
  143. 143
  144. 144
  145. 145 /* 设置固定IP的8秒时间到 */
  146. 146
  147. 147 if (dhcp_tout == 0x80000000)
  148. 148
  149. 149 {
  150. 150
  151. 151 dhcp_tout = 0;
  152. 152
  153. 153 sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
  154. 154
  155. 155 MY_IP[2], MY_IP[3]);
  156. 156
  157. 157 sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
  158. 158
  159. 159 printf_tcpdbg("%s\r\n", DHCP_Status[0]);
  160. 160
  161. 161 printf_tcpdbg("%s\r\n", DHCP_Status[1]);
  162. 162
  163. 163 }
  164. 164
  165. 165 }
  166. 166
  167. 167
  168. 168
  169. 169 /*
  170. 170
  171. 171 *********************************************************************************************************
  172. 172
  173. 173 * 函 数 名: TCPnetTest
  174. 174
  175. 175 * 功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
  176. 176
  177. 177 * 形 参: 无
  178. 178
  179. 179 * 返 回 值: 无
  180. 180
  181. 181 *********************************************************************************************************
  182. 182
  183. 183 */
  184. 184
  185. 185 void TCPnetTest(void)
  186. 186
  187. 187 {
  188. 188
  189. 189 uint32_t tstart, tend;
  190. 190
  191. 191
  192. 192
  193. 193 /* 初始化变量 */
  194. 194
  195. 195 dhcp_tout = DHCP_TOUT;
  196. 196
  197. 197 tstart = os_time_get();
  198. 198
  199. 199
  200. 200
  201. 201 while (1)
  202. 202
  203. 203 {
  204. 204
  205. 205 /* 每100ms做一次DHCP检测 */
  206. 206
  207. 207 if(dhcp_tout != 0)
  208. 208
  209. 209 {
  210. 210
  211. 211 tend = os_time_get() - tstart;
  212. 212
  213. 213 //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
  214. 214
  215. 215 if(tend >= 100)
  216. 216
  217. 217 {
  218. 218
  219. 219 tstart = os_time_get();
  220. 220
  221. 221 dhcp_check();
  222. 222
  223. 223 }
  224. 224
  225. 225 }
  226. 226
  227. 227
  228. 228
  229. 229 os_evt_wait_and(0x0001, 0xFFFF);
  230. 230
  231. 231 while (main_TcpNet() == __TRUE);
  232. 232
  233. 233 }
  234. 234
  235. 235 }

Socket 服务器任务

这里专门创建了一个app_socket_lib.c文件用于socket服务器任务。

  1. 1 #include "includes.h"
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9 /*
  10. 10
  11. 11 *********************************************************************************************************
  12. 12
  13. 13 * 用于本文件的调试
  14. 14
  15. 15 *********************************************************************************************************
  16. 16
  17. 17 */
  18. 18
  19. 19 #if 1
  20. 20
  21. 21 #define printf_debug printf
  22. 22
  23. 23 #else
  24. 24
  25. 25 #define printf_debug(...)
  26. 26
  27. 27 #endif
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33 /*
  34. 34
  35. 35 *********************************************************************************************************
  36. 36
  37. 37 * 宏定义,本地端口
  38. 38
  39. 39 *********************************************************************************************************
  40. 40
  41. 41 */
  42. 42
  43. 43 /* 这个是本地端口 */
  44. 44
  45. 45 #define LocalPort_NUM 1001
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51 /*
  52. 52
  53. 53 *********************************************************************************************************
  54. 54
  55. 55 * 变量
  56. 56
  57. 57 *********************************************************************************************************
  58. 58
  59. 59 */
  60. 60
  61. 61 /* RL-TCPnet API的返回值 */
  62. 62
  63. 63 const char * ReVal_Table[]=
  64. 64
  65. 65 {
  66. 66
  67. 67 " 0: SCK_SUCCESS Success ",
  68. 68
  69. 69 "-1: SCK_ERROR General Error ",
  70. 70
  71. 71 "-2: SCK_EINVALID Invalid socket descriptor ",
  72. 72
  73. 73 "-3: SCK_EINVALIDPARA Invalid parameter ",
  74. 74
  75. 75 "-4: SCK_EWOULDBLOCK It would have blocked. ",
  76. 76
  77. 77 "-5: SCK_EMEMNOTAVAIL Not enough memory in memory pool ",
  78. 78
  79. 79 "-6: SCK_ECLOSED Connection is closed or aborted ",
  80. 80
  81. 81 "-7: SCK_ELOCKED Socket is locked in RTX environment ",
  82. 82
  83. 83 "-8: SCK_ETIMEOUT Socket, Host Resolver timeout ",
  84. 84
  85. 85 "-9: SCK_EINPROGRESS Host Name resolving in progress ",
  86. 86
  87. 87 "-10: SCK_ENONAME Host Name not existing ",
  88. 88
  89. 89 };
  90. 90
  91. 91
  92. 92
  93. 93 uint8_t sendbuf[1024];
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99 /*
  100. 100
  101. 101 *********************************************************************************************************
  102. 102
  103. 103 * 函 数 名: SocketTest
  104. 104
  105. 105 * 功能说明: Socket应用
  106. 106
  107. 107 * 形 参: 无
  108. 108
  109. 109 * 返 回 值: 无
  110. 110
  111. 111 *********************************************************************************************************
  112. 112
  113. 113 */
  114. 114
  115. 115 void SocketTest(void)
  116. 116
  117. 117 {
  118. 118
  119. 119 char dbuf[10];
  120. 120
  121. 121 int len;
  122. 122
  123. 123 int sock, sd, res;
  124. 124
  125. 125 SOCKADDR_IN addr;
  126. 126
  127. 127 SOCKADDR_IN ReAddr;
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133 while (1)
  134. 134
  135. 135 {
  136. 136
  137. 137 /* 创建一个socket
  138. 138
  139. 139 第1个参数AF_INET:当前仅支持这个类型的地址族。
  140. 140
  141. 141 第2个参数SOCK_STREAM:表示数据流通信类型,即使用的TCP。
  142. 142
  143. 143 第3个参数0 :配置为0的话,自动跟第2个参数进行协议匹配,这里就是TCP协议。
  144. 144
  145. 145 */
  146. 146
  147. 147 sock = socket (AF_INET, SOCK_STREAM, 0);
  148. 148
  149. 149
  150. 150
  151. 151 /* 端口号设置为1001 */
  152. 152
  153. 153 addr.sin_port = htons(LocalPort_NUM);
  154. 154
  155. 155
  156. 156
  157. 157 /* 与函数socket中的AF_INET作用一样 */
  158. 158
  159. 159 addr.sin_family = PF_INET;
  160. 160
  161. 161 /*
  162. 162
  163. 163 INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或所有地址,
  164. 164
  165. 165 任意地址。用在这里的话就表示监控端口号为ddr.sin_port的所有IP地址消息。一般主要用
  166. 166
  167. 167 于有多个网卡或者IP地址的情况。开发板只用了DM9161的网口,就是监听这个网口的IP地址。
  168. 168
  169. 169 */
  170. 170
  171. 171 addr.sin_addr.s_addr = INADDR_ANY;
  172. 172
  173. 173
  174. 174
  175. 175 /* 给socket绑定IP和端口号 */
  176. 176
  177. 177 bind (sock, (SOCKADDR *)&addr, sizeof(addr));
  178. 178
  179. 179
  180. 180
  181. 181 /* 设置监听,最大监听1个连接 */
  182. 182
  183. 183 listen (sock, 1);
  184. 184
  185. 185
  186. 186
  187. 187 /*
  188. 188
  189. 189 等待soket连接请求,有的话,自动创建1个新的socket进行连接通信,没有的话,等待连接。
  190. 190
  191. 191 注意,能够accept的个数受到listen函数的限制,而listen函数又受到Net_Config.c中宏定义
  192. 192
  193. 193 BSD_NUMSOCKS 的限制。
  194. 194
  195. 195 */
  196. 196
  197. 197 len = sizeof(ReAddr);
  198. 198
  199. 199 sd = accept (sock, (SOCKADDR *)&ReAddr, &len);
  200. 200
  201. 201 printf_debug ("远程客户端请求连接IP: %d.%d.%d.%d\n", ReAddr.sin_addr.s_b1,
  202. 202
  203. 203 ReAddr.sin_addr.s_b2,
  204. 204
  205. 205 ReAddr.sin_addr.s_b3,
  206. 206
  207. 207 ReAddr.sin_addr.s_b4);
  208. 208
  209. 209 printf_debug ("远程客户端端口号: %d\n", ntohs(ReAddr.sin_port));
  210. 210
  211. 211
  212. 212
  213. 213 /* 关闭监听socket,这个监听socket是调用函数socket后自动创建的 */
  214. 214
  215. 215 closesocket (sock);
  216. 216
  217. 217 sock = sd;
  218. 218
  219. 219
  220. 220
  221. 221
  222. 222
  223. 223 while (1)
  224. 224
  225. 225 {
  226. 226
  227. 227 /*
  228. 228
  229. 229 socket数据接收函数,如果recv工作在阻塞模式,使用这个函数注意以下事项:
  230. 230
  231. 231 1. 此函数的溢出时间受到Net_Config.c中宏定义 BSD_RCVTOUT 的限制。溢出时间到会自动退出。
  232. 232
  233. 233 2. 这个函数接收到一次数据包就会返回,大于或者小于设置的缓冲区大小都没有关系,如果数据量
  234. 234
  235. 235 大于接收缓冲区大小,用户只需多次调用函数recv进行接收即可。
  236. 236
  237. 237 3. 实际接收到数据大小通过判断此函数的返回值即可。
  238. 238
  239. 239 */
  240. 240
  241. 241 res = recv (sock, dbuf, sizeof(dbuf), 0);
  242. 242
  243. 243 if (res <= 0)
  244. 244
  245. 245 {
  246. 246
  247. 247 printf_debug("退出接收函数,重新开始监听%s\r\n", ReVal_Table[abs(res)]);
  248. 248
  249. 249 break;
  250. 250
  251. 251 }
  252. 252
  253. 253 else
  254. 254
  255. 255 {
  256. 256
  257. 257 printf_debug("Receive Data Length = %d\r\n", res);
  258. 258
  259. 259 switch(dbuf[0])
  260. 260
  261. 261 {
  262. 262
  263. 263 /* 字符命令 1 */
  264. 264
  265. 265 case '1':
  266. 266
  267. 267 sendbuf[0] = '1';
  268. 268
  269. 269 sendbuf[1] = '2';
  270. 270
  271. 271 sendbuf[2] = '3';
  272. 272
  273. 273 sendbuf[3] = '4';
  274. 274
  275. 275 sendbuf[4] = '5';
  276. 276
  277. 277 sendbuf[5] = '6';
  278. 278
  279. 279 sendbuf[6] = '7';
  280. 280
  281. 281 sendbuf[7] = '8';
  282. 282
  283. 283 sendbuf[8] = '\r';
  284. 284
  285. 285 sendbuf[9] = '\n';
  286. 286
  287. 287 res = send (sock, (char *)sendbuf, 10, 0);
  288. 288
  289. 289 if (res < 0)
  290. 290
  291. 291 {
  292. 292
  293. 293 printf_debug("函数send发送数据失败\r\n");
  294. 294
  295. 295 }
  296. 296
  297. 297 else
  298. 298
  299. 299 {
  300. 300
  301. 301 printf_debug("函数send发送数据成功\r\n");
  302. 302
  303. 303 }
  304. 304
  305. 305 break;
  306. 306
  307. 307
  308. 308
  309. 309 /* 字符命令 2 */
  310. 310
  311. 311 case '2':
  312. 312
  313. 313 /* 将数据缓冲区清成字符0,方便网络调试助手查看数据 */
  314. 314
  315. 315 len = sizeof(sendbuf);
  316. 316
  317. 317 memset(sendbuf, 48, len);
  318. 318
  319. 319
  320. 320
  321. 321 /* 这里仅初始化了数据包的前4个字节和最后4个字节 */
  322. 322
  323. 323 sendbuf[0] = 'a';
  324. 324
  325. 325 sendbuf[1] = 'b';
  326. 326
  327. 327 sendbuf[2] = 'c';
  328. 328
  329. 329 sendbuf[3] = 'd';
  330. 330
  331. 331 sendbuf[len - 4] = 'e';
  332. 332
  333. 333 sendbuf[len - 3] = 'f';
  334. 334
  335. 335 sendbuf[len - 2] = 'g';
  336. 336
  337. 337 sendbuf[len - 1] = 'h';
  338. 338
  339. 339 res = send (sock, (char *)sendbuf, len, 0);
  340. 340
  341. 341 if (res < 0)
  342. 342
  343. 343 {
  344. 344
  345. 345 printf_debug("函数send发送数据失败%s\r\n", ReVal_Table[abs(res)]);
  346. 346
  347. 347 }
  348. 348
  349. 349 else
  350. 350
  351. 351 {
  352. 352
  353. 353 printf_debug("函数send成功发送数据 = %d字节\r\n", res);
  354. 354
  355. 355 }
  356. 356
  357. 357 break;
  358. 358
  359. 359
  360. 360
  361. 361 /* 其它数值不做处理 */
  362. 362
  363. 363 default:
  364. 364
  365. 365 break;
  366. 366
  367. 367 }
  368. 368
  369. 369 }
  370. 370
  371. 371
  372. 372
  373. 373 }
  374. 374
  375. 375
  376. 376
  377. 377 /*
  378. 378
  379. 379 溢出时间到,远程设备断开连接等,程序都会执行到这里,我们在这里关闭socket,
  380. 380
  381. 381 程序返回到第一个大while循环的开头重新创建socket并监听。
  382. 382
  383. 383 */
  384. 384
  385. 385 closesocket (sock);
  386. 386
  387. 387 }
  388. 388
  389. 389 }

26.8 总结

本章节就为大家讲解这么多,内容相对比较简单,希望大家熟练掌握。

【RL-TCPnet网络教程】第26章 RL-TCPnet之DHCP应用的更多相关文章

  1. 【安富莱TCPnet网络教程】HTTP通信实例

    第41章      HTTP超文本传输协议基础知识 本章节为大家讲解HTTP(HyperText Transfer Protocol,超文本传输协议),从本章节开始,正式进入嵌入式Web的设计和学习. ...

  2. 【RL-TCPnet网络教程】第32章 RL-TCPnet之Telnet服务器

    第32章      RL-TCPnet之Telnet服务器 本章节为大家讲解RL-TCPnet的Telnet应用,学习本章节前,务必要优先学习第31章的Telnet基础知识.有了这些基础知识之后,再搞 ...

  3. 【RL-TCPnet网络教程】第30章 RL-TCPnet之SNTP网络时间获取

    第30章      RL-TCPnet之SNTP网络时间获取 本章节为大家讲解RL-TCPnet的SNTP应用,学习本章节前,务必要优先学习第29章的NTP基础知识.有了这些基础知识之后,再搞本章节会 ...

  4. 【RL-TCPnet网络教程】第28章 RL-TCPnet之DNS应用

    第28章      RL-TCPnet之DNS应用 本章节为大家讲解RL-TCPnet的DNS应用,学习本章节前,务必要优先学习第27章的DNS基础知识.有了这些基础知识之后,再搞本章节会有事半功倍的 ...

  5. 【RL-TCPnet网络教程】第20章 RL-TCPnet之BSD Socket客户端

    第20章      RL-TCPnet之BSD Socket客户端 本章节为大家讲解RL-TCPnet的BSD Socket,学习本章节前,务必要优先学习第18章的Socket基础知识.有了这些基础知 ...

  6. 【RL-TCPnet网络教程】第19章 RL-TCPnet之BSD Socket服务器

    第19章      RL-TCPnet之BSD Socket服务器 本章节为大家讲解RL-TCPnet的BSD Socket,学习本章节前,务必要优先学习第18章的Socket基础知识.有了这些基础知 ...

  7. 【RL-TCPnet网络教程】第17章 RL-TCPnet之UDP通信

    第17章      RL-TCPnet之UDP通信 本章节为大家讲解RL-TCPnet的UDP通信实现,学习本章节前,务必要优先学习第16章UDP用户数据报协议基础知识.有了这些基础知识之后,再搞本章 ...

  8. 【RL-TCPnet网络教程】第14章 RL-TCPnet之TCP客户端

    第14章      RL-TCPnet之TCP客户端 本章节为大家讲解RL-TCPnet的TCP客户端实现,学习本章节前,务必要优先学习第12章TCP传输控制协议基础知识.有了这些基础知识之后,再搞本 ...

  9. 【RL-TCPnet网络教程】第13章 RL-TCPnet之TCP服务器

    第13章      RL-TCPnet之TCP服务器 本章节为大家讲解RL-TCPnet的TCP服务器实现,学习本章节前,务必要优先学习第12章TCP传输控制协议基础知识.有了这些基础知识之后,再搞本 ...

随机推荐

  1. 不使用synchronized和lock 锁实现线程安全单例

    单例实现方式一,锁机制 public class Singleton { private static Singleton singleton=null; public Singleton() { } ...

  2. HBuilderx中编译sass文件

    安装scss/sass编译插件 工具 -> 插件安装 -> scss/sass编译插件 将sass编译成css 新建scss文件,编写完成后,(右键scss文件 -> 外部命令/插件 ...

  3. Chrome浏览器自动填充<input>标签的密码

    问题:登录页面登录时,Chrome浏览器保存了用户名和密码,在其他页面管理其他的账户和密码时,密码框先是显示正确的密码,然后一闪而过被覆盖. 原因:问了技术主管才得知,Chrome浏览器中的,保存用户 ...

  4. JAVA取数两个数组交集,考虑重复和不重复元素

    1.考虑不重复元素,重复元素不添加 import java.awt.List; import java.util.ArrayList; import java.util.TreeSet; public ...

  5. percona-toolkit安装

    https://www.percona.com/downloads/percona-toolkit/LATEST/ #下载wget https://www.percona.com/downloads/ ...

  6. C#学习-查询表达式

    查询表达式必须以from子句开头,并且必须以select或group子句结尾 在第一个from子句和最后一个select或group子句之间,可以包含一个或多个where子句.orderby.join ...

  7. 从Jensen不等式到Minkowski不等式

    整理即证 参考资料: [1].琴生不等式及其加权形式的证明.Balbooa.https://blog.csdn.net/balbooa/article/details/79357839.2018.2 ...

  8. 使用With递归查询 树

    UNION ALL -- 递归成员 SELECT a.* FROM tree a JOIN CTE c ON a.pid = c.id ) SELECT * from CTE   --1.将 CTE  ...

  9. 杂记:Python 两坑

    近日写代码又遇到两个 Python 的坑,觉得值得记录. 递归传参问题 Python 里传参的实现是 assignment,但由于 Python 里都是对象,除了几个基本类型,assignment 基 ...

  10. log4j警告:WARN Please initialize the log4j system properly 的解决方法

    出现这个问题的原因则是因为没有为log4j建立配置文件导致的.所以解决问题的方法很简单,只要在 src文件目录下建立配置文件即可: 右键点击src  -> New  ->  File 文件 ...