函数netconn_new用来创建一个新的连接结构。连接结构的类型可以选择为TCP或UDP等。函数结构原型如下所示,参数type描述了连接的类型,可以为NETCONN_TCP或NETCONN_UDP等,这里都以TCP作为讨论的对象。

struct netconn* netconn_new(enum

netconn_type type)

该函数首先调用netconn_alloc函数分配并初始化一个netconn结构。初始化的过程包括设置netconn结构类型字段,同时为该结构的op_completed创建一个信号量、recvmbox字段创建一个接收邮箱。奇怪的是netconn_alloc函数并不是在文件api_lib.c文件中,而是在api_msg.c中,凌乱!接下来函数netconn_new会构建一个api_msg消息,该消息要求内核执行函数do_newconn,最后函数tcpip_apimsg用来将消息包装成tcpip_msg结构并发送出去。tcpip_thread函数解析该消息并调用函数do_newconn,do_newconn根据参数的类型最终调用函数tcp_new创建一个TCP控制块。tcpip_apimsg会阻塞在一个信号量上,直至do_newconn释放该信号量。

函数netconn_delete用来删除一个连接结构netconn。与前面的流程相同,它通过消息告诉内核执行do_delconn,调用tcp_close函数关闭TCP连接。而后netconn_delete调用netconn_free函数释放netconn结构的空间。注意这里的netconn_free函数netconn_alloc函数一样,也不是在文件api_lib.c文件中,而是在api_msg.c中,尽管他们都是netconn_xxx结构。

netconn_bind用于将一个IP地址及端口号与结构netconn绑定。事实上,内核是通过函数do_bind调用tcp_bind完成相应TCP控制块得绑定工作的。

netconn_connect函数一般在客户端调用,用以将服务器端的IP地址和端口号与本地的netconn结构绑定。该函数与内核tcp_connect函数对应。

netconn_listen函数一般在服务器端调用,用于将某个TCP控制块置为LISTEN状态。类似的函数do_listen会被调用,该函数有两个重要的工作:为结构netconn字段acceptmbox创建邮箱,该邮箱用于接受外部连接;向相应TCP的PCB控制块中accept字段注册一个回调函数accept_function,当该PCB上有新连接出现时,回调函数会被调用,以向上面的acceptmbox邮箱中发送消息,告诉应用程序有新的连接到来,新连接的信息以netconn结构形式被保存在了邮箱中。

netconn_accept函数在服务器上使用,用于接收远端的连接,该函数主要在阻塞在上面所述的acceptmbox邮箱上,当接收到新的连接后,在该邮箱上取下连接的netconn结构并返回。

netconn_recv函数用于接收数据,接收到得数据被封装为netbuf结构。这里内核函数tcp_recved会被协议栈调用,以通知内核数据被正常接收,内核因此调整发送窗结构,返回ACK确认等。

函数netconn_write用于向相应的TCP连接上发送数据,主要这个函数只用于发送TCP数据,用于发送UDP数据的函数叫netconn_send,这里先不讨论。netconn_write函数原型如下,它用于将dataptr指向的size个数据放到连接conn的发送队列上,apiflags用于描述

err_t netconn_write(struct netconn

*conn, const void *dataptr, int size, u8_t apiflags)

对该数据的操作,包括是否拷贝,是否立即发送两种选择。最后netconn_close函数用于主动关闭连接。

API函数就说这么一点点了。下面我们用这些API函数构造一个服务器程序。这个服务器程序很简单,它能响应一个客户端的连接和数据请求,并向客户端发送一个固定字符串。任务代码如下:

const uint8 data[]= "hello

world!"; // 待发送字符串

void mytcp_thread(void *arg)

{

struct netconn * conn,

*newconn; // API描述的连接结构

struct netbuf *

buf; // API数据缓冲

conn = netconn_new(NETCONN_TCP); //

创建新的TCP连接结构

netconn_bind(conn, NULL,

7); //

该连接与端口7绑定

netconn_listen(conn); //

将结构置为侦听状态

newconn =

netconn_accept(conn); // 接收到一个新的连接

while(1)

{

buf =

netconn_recv(newconn); // 在新连接上接收到一个数据

netbuf_delete(buf); // 删除接收到的数据

netconn_write(newconn,data,sizeof(data), NETCONN_COPY); //

将字符串发送的客户端

}

}

服务器程序之所以要这样设计是为了测试的方便,因为手上恰好有个小程序可以用来测试这个服务器程序以及我们的LwIP协议栈运转是否正常。这个小程序是当年参加中兴编程大赛的时候写的,名字叫报文监视器。它能接收某个TCP连接上的数据并能按照用户要求对这些数据进行过滤,去除用户不关心的数据。大嘴东哥和寝室的鹏鹏。。O(∩_∩)O~看到这个程序就想到了你们,大功臣啊。。。测试结果如下:

过滤表达式编辑框内的内容是用户输入的过滤条件,当接收的数据串满足过滤条件时,该字符串不会在接收结果中显示出来。过滤条件是一系列的引号括起来的字符串,它们可以用or,and,not,括号等连接起来,组成很复杂的过滤条件。。不讲了。

首先,将过滤条件置为空,此时显示了从服务器接收到得所有数据“hello

word!”,如图下方所示。然后将过滤条件设置为“he”or

“ww”..即字符串中含有“he”或者“ww”字样的数据串将被滤除掉不以显示。。这正如接收结果中的前两行所示。OK…测试结果一切正常,我们的LwIP稳定的跑起来了!不过,这里还可以用其他的测试方法,更常用的方法是构建一个http服务器,然后用我们的浏览器来连接服务器,这些在LwIP移植手册中有了很多例程以及详细的说明,不罗嗦了。

可见,使用LwIP

API已经可以轻松完成所有TCP通信的相关任务了。除此之外,LwIP还用自身的API函数实现了BSD Socket

API函数。因为很多的软件编写是基于BSD套接字的,BSD套接字更简单易懂,使用广泛,可见实现Socket

API还是有必要的。但是LwIP说明文档中这样写道:

这一节提供使用LwIP API对BSD Socket

API的一个简单实现。这个实现只能作为一个参考,不能用于实际编程中,因为它并不完善,比如它没有容错机制等。同时,这个简单实现也不支持BSD

Socket API中的select()与poll()函数,因为LwIP

API没有任何函数可以用于这两个函数的实现。要实现这两个函数,BSD

socket实现需要直接与LwIP协议栈通讯,而不是使用其API。

所以这里不对BSD Socket API做详细讨论了,使用LwIP

API完全可以完成相关的工作,且编程工作也很简单。

到这里,我们已经从头到尾的将LwIP协议走完了一遍,从网络接口层到ARP层,再到IP层,然后到TCP层,最后到API层。通常实际应用中,TCP数据包也是按照这个次序依次被处理的。LwIP还有很多其他内容还没有讨论到,首先是UDP,接下来是PPP,SILP,DNS,IGMP,DHCP,SNMP,IPV6等等。这些都是在某些特殊的场合才会使用到的,不具有什么共性,所以这里先不涉及这些了。

全剧终。。。

lwip协议栈实现服务器端主动发送,API函数及编程实例《LwIP协议栈源码详解—TCP/IP协议的实现》...相关推荐

  1. lwip路由实现_TCP超时与重传《LwIP协议栈源码详解——TCP/IP协议的实现》

    在TCP两端交互过程中,数据和确认都有可能丢失.TCP通过在发送时设置一个定时器来解决这种问题.如果当定时器溢出时还没有收到确认,它就重传该数据.对任何TCP协议实现而言,怎样决定超时间隔和如何确定重 ...

  2. 详解TCP/IP协议栈面临的五大网络安全问题

    文章来源:企鹅号 - 疯猫网络科技 1. IP欺骗 IP Spoof即IP 电子欺骗,可以理解为一台主机设备冒充另外一台主机的IP地址与其他设备通信,从而达到某种目的技术.早在1985年,贝尔实验室的 ...

  3. 源码公开的TCP/IP协议栈在远程监测中的应用

    目前,随着互联网的发展,越来越多的工业测控设备已经将网络接入功能作为其默认配置,以实现设备的远程监控和信息分布式处理.笔者曾参与某发电机射频监测仪的开发,该设备主要用于诊断和预警发电机早期故障,并通过 ...

  4. STM32 USART串口DMA 接收和发送的源码详解!

    硬件平台:STM32F103ZET6: 开发环境:KEIL 4: 先说说应用通讯模式,串口终端的工作方式和迪文屏差不多,终端被动接受MCU发的指令,终端会偶尔主动发送一些数据给MCU(像迪文屏的触摸信 ...

  5. LwIP源码详解 - UDP

    目录 1. UDP说明 1.1 协议简介 1.2 UDP特点 1.3 报文格式 2. UDP在LWIP上的实现 2.1. 数据结构 2.1.1 UDP控制块 2.1.2 UDP首部 2.2 接口函数 ...

  6. node源码详解(四) —— js代码如何调用C++的函数

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4  本博客同步在https://cnodejs. ...

  7. VC++ 功能强大的API函数FindFirstFile使用介绍(附源码)

    VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从 ...

  8. C语言 printf源码详解,从头一起学c语言(六)————printf函数的详解

    这段时间很忙,更新的晚了,见谅.当然同样有今天我们的主角十分复杂,之前介绍了这个手记并非是面对新手的,而是我的复习手记.所以我们会讲头文件,或许有错误,如果有大手子看到,希望能够提出我的错误. pri ...

  9. 单片机tcp ip协议c语言,单片机TCP IP协议栈实现的原理

    对已TCP IP协议栈,我们已经说了很多关于它的原理相关的知识了.但是只有原理是不够的,在这方面我们将要举出一个实际操作实例为大家讲解,那么首先我们来看一下有关于单片机TCP/IP就是在单片机上运行的 ...

  10. 计算机网络基础(三次握手|TCP/IP协议|五层协议栈|网络安全)

    目录 一.三次握手 1.1 三次握手过程 1.2 为什么不两次握手 1.3 四次握手 1.4 常见问题 1.5 TCP的有限状态机 二.TCP与UDP 2.1 TCP/IP协议簇 2.2 TCP与UD ...

最新文章

  1. mysql1045错误如何解决,Java面试真题精选
  2. SM02 发送系统消息给所有Client用户
  3. STRUTS2 标签调用静态方法
  4. JS让本地图片预览不再难-jquery插件
  5. 热聘:英特尔音频Firmware-Linux内核驱动
  6. tika获取压缩文件内容
  7. python win32api win32gui win32con PyUserInput实现自动化脚本
  8. 交换机配置常用的命令
  9. 计算机设备管理器没有WDS,hp 1136 电脑重启后 自动脱机 ,打印机服务也开起来,要把驱动删除掉,重新安装驱动才可以...
  10. ios 裁剪框大小_ios – 如何将视频裁剪为特定大小?
  11. 第二次作业-时事点评
  12. html画布动画,画布动画(Canvas Animation)
  13. stm32使用XR20M1172详细攻略·SPI转UART串口
  14. 微信小程序隐藏分享按钮
  15. mysql(数据库)初级操作
  16. 学计算机画素描吗,用电脑制作一张素描画
  17. ln的c语言表达式,c程序中语句中如何表示ln函数?
  18. 面试平安科技--二面
  19. html 页面 title keyworld 的 SEO优化的 基本设置格式
  20. 计算机系统结构第二版习题答案,计算机系统结构课后习题答案(第2版).docx

热门文章

  1. PDF虚拟打印机(virtual printer)软件汇总
  2. 数据库mysql报2005错_sql2005还原数据库错误的问题解决方法
  3. 处女座与cf 模拟
  4. 单片机c语言 arduino,单片机C语言程序设计实训100例——基于Arduino+Proteus仿真
  5. 单片机C语言程序设计实训100例大集合
  6. 表白代码,浪漫网页-JavaScript的应用
  7. mmap 文件不能为空
  8. revit2016注册表删除_Revit怎么卸载,如何把revit彻底卸载删除干净重新安装的方法?【转载】...
  9. 熊猫烧香delphi编写免费源代码
  10. python播放音频文件