基于MicroC/OSII 的TCP/IP Socket Server

  整理一下这几天学习的一些知识,就当是一些知识概念的整理,免得以后忘记了。

一、内容  

  在NiosII IDE建立基于uC/OS操作系统的TCP/IP Socket Server工程,该应用工程能够初始化LwIP(Light weight IP)stack,运行简单的TCP Server。PC机可以通过Ethernet与开发板通信。硬件系统要求有lan91c111 Ethernet MAC。软件有MicroC/OS-II和LwIP。把配置有Ethernet控制器的硬件系统配置到FPGA中,然后编译运行应用程序。PC机通过Ethernet访问开发板进行通信。

  这里所用的平台是:博创UP-AR2000    Quartus II 7.2    Nios II 7.2


二、uC/OS II

  uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。

  Altera的uCOS2本质上是Nios II HAL的一个超集,是uCOS2任务调度器和相关API函数在HAL环境上的扩展。在uCOS2 Project中,所有Nios II本身的HAL API都可以被调用。


   

三、LwIP协议栈 和 NicheStack TCP/IP协议栈

3.1 LwIP协议栈

  LWIP是TCP/IP协议栈的一种实现。主要目的是减少存储器利用量和代码尺寸,几十K字节的程序空间和几十K字节的数据RAM空间就可以实现。很适合应用于小的、资源有限的处理器如嵌入式系统。可以移植到操作系统上,也可以在无操作系统的情况下独立运行。

  要实现嵌入式TCP/IP协议栈,最关键的一个问题就是,如何结合系统资源有限的嵌入式系统软硬件环境以及具体的嵌入式Internet应用对标准的TCP/IP协议栈进行简化, 从而实现一种“轻量级”的TCP/IP协议栈。这就是所谓的Light-weight IP。由瑞典计算机科学院的Adam Dunkels创建。

  LwIP提供了完成的TCP/IP协议功能,支持IP,ICMP,UDP,TCP,DHCP,ARP。

  Altera在Nios II上的LwIP移植基于uCOS2的多任务环境,在Nios IDE中开发LwIP应用程序需要工程首先配置为支持uCOS2。

  Nios II上LwIP支持的网络芯片为SMSC的LAN91C111。

3.2 LwIP的进程模型

  协议实现的进程模型以把系统划分成为不同的进程的方法进行描述。先看下普通的TCP/IP协议的模型。

  这种方法有其诸多优势,如协议能在运行时被增加,代码一般容易理解和调试。但也有不利因素,严格的分层并不总是实现协议的最好方法。

  数据跨层传递时将不得不产生进程切换(context switch)。对于接收一个TCP段来说,将会引起三次进程切换,从网络设备驱动层进程到IP进程,从IP进程到TCP进程,最终到应用层进程。对于大部分操作系统来说,进程切换的代价可是相当昂贵的。

  

  lwIP所使用的进程模型是:把所有协议封装到一个单一的进程中,从而与操作系统内核分开。

  应用程序可能也驻留在lwIP处理过程中,或者在单独的过程中。

  TCP/IP栈和应用程序之间的通信可以通过函数调用实现,也可以通过更为抽象的API。

  有些学者把这种方法称为零拷贝技术。所谓“零拷贝”,是指TCP/IP协议栈没有用于各层数据传输的缓冲区,协议栈各层之间传递的都是数据指针。

  只有当数据最终要被驱动程序发送出去或者是被应用程序取走时,才进行真正的数据搬移。这样就大大减少了系统开销,从而提高系统性能。

3.3 NicheStack与LwIP一脉相承,技术上并无本质区别,在作产品时可能有区别。前者需要授权,后者则不需要。


四、代码中的一些分析

(1)网络接口的初始化

在启动OSStart()函数进入多任务状态之前,调用如下两个函数完成网络接口的初始化:

  1)lwip_stack_init()

函数原型为:void lwip_stack_init(int thread_prio, void (* init_done_func)(void *), void *arg)
thread_prio:主TCP/IP线程的优先级
init_done_func():lwip_stack_init函数执行完成后就转向执行这个指针指向的函数
arg:传递给init_done_func的参数,视init_done_func()而定,通常置为0
功能:创建一个TCPIP协议栈主线程,完成TCP/IP协议栈的初始化并转向init_done_func

  2)lwip_devices_init()

函数原型为:int lwip_devices_init(int rx_thread_prio)
Lwip_devices_init从system.h中遍历所有安装的网络设备驱动并注册。成功后返回一个非零值,此时如果TCPIP栈准备就绪,就可以为应用程序创建任务。
此函数创建了一个接收线程,其优先级由参数rx_thread_prio给定
此函数会调用get_mac_addr和get_ip_addr二函数,这两个函数必须由用户编写。

(2)get_mac_addr和get_ip_addr

  LwIP系统代码必须根据此二函数设置网络设备的MAC和IP地址。

  通过写这两个函数,系统可以灵活地将MAC和IP地址存放在任意位置,而不是设备驱动的某个固定位置。如可以存放在FLASH中,也可存放在片内RAM中。

  两个函数都使用了LwIP内部使用的结构体。用户无需知道结构体的细节,只需知道如何填充MAC和IP地址。

(3)应用程序创建四个任务

  1)SSSInitialTask()

  SSSInitialTask创建了两个软件组件层任务:
     NicheStack TCP/IP Stack main task:在netmain()中创建
     time-keeping task:在netmain()中创建

  SSSInitialTask在创建两个任务后删除本任务。

 1 alt_iniche_init(); //执行NicheStack网络栈的预初始化
2 netmain(); //初始化并开始NicheStack网络栈
3 //iniche_net_ready标明TCP/IP栈准备好,IP地址已获取
4 while (!iniche_net_ready) TK_SLEEP(1);
5 //协议栈已开始运行,应用程序初始化, 开始应用相关的任务加载代码块
6 printf("\nSimple Socket Server starting up\n");
7 TK_NEWTASK(&ssstask); //创建simple socket server任务
8 SSSCreateOSDataStructs();//创建OS数据结构:队列信号量等
9 SSSCreateTasks(); //创建其它任务
10 error_code = OSTaskDel(OS_PRIO_SELF);

  2)SSSSimpleSocketServerTask()

  其完成的功能为:

    创建一个socket实现TCP/IP连接,绑定到socket上,侦听客户端的TCP/IP连接请求。

    到来TCP/IP连接时,调用sss_handle_accept()。

    调用sss_handle_receive()处理TCP/IP连接。如果需要多个TCP/IP连接,需要创建更多任务。

    调用sss_reset_connection(), sss_send_menu()和sss_exec_command()。

    当收到数据包后,LED命令被提取并通过SSSLEDCommandQ队列送到LEDManagementTask()。

  3)LEDManagementTask()

  响应SSSLEDCommandQ队列中的命令。如果命令给7段数码管的则更改SSSLEDLightshowSem信号量。如果命令给LED灯,则修改SSSLEDEventFlag值,从而控制不同的LED灯显
示。

  4)LED7SegLightshowTask()

  根据SSSLEDLightshowSem的值,在7段LED上闪烁随机图案或停止闪烁。


 五、实验过程与结果

  实验中自己修改的内容不算多,只要设置好MAC地址和IP地址。IP地址是要和PC机的IP地址在一个局域网中,然后用交叉线连接。需要注意的是:有的电脑上有2个网口,当需要做实验时,需要将另外一个网口关闭,否则远程控制会无效。关键还是要理解其中运行的机理。主要实现的是从PC机上远程控制开发板上的操作。

  当.sof文件下载后,运行软件,可以在输出窗口看到自己所设置的IP地址。

  从“开始”中打开“运行”。

 输入命令和IP、端口号“telnet 192.168.0.250 30”。

 只要能连接上,就能远程控制LED灯与数码管了。

原文地址:https://www.cnblogs.com/kongtiao/p/2319678.html