第20章 嵌入式Linux的网络编程_第1页
第20章 嵌入式Linux的网络编程_第2页
第20章 嵌入式Linux的网络编程_第3页
第20章 嵌入式Linux的网络编程_第4页
第20章 嵌入式Linux的网络编程_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第20章嵌入式Linux的网络编程 本章将介绍嵌入式Linux网络编程的基础知识 由于网络在嵌入式系统中的应用日益广泛 很多的应用中都会或多或少的涉及到网络应用 因此 掌握这方面的内容也是非常重要的 20 1TCP IP协议 通信协议用于协调不同网络设备之间的信息交换 它们建立了设备之间互相识别的信息机制 当今在通信界有许多可采用的协议 如NetBios IPX SPX TCP IP等 这些协议具有处理各种不同数据通信类型类型的几种基本结构 TCP IP许多年来一直被人们所采用 而且越来越成熟 大多数类型的计算机环境都有TCP IP产品 它提供了文件传输 电子邮件 终端仿真 传输服务和网络管理等功能 20 2TCP协议 TCP协议处于传输层 实现了从一个应用程序到另一个应用程序的数据传递 应用程序通过目的地址和端口号来区分接受数据的不同应用程序 TCP协议通过三次握手来初始化 目的是使数据段的发送和接受同步 告述其他主机其一次可接收的数据量 并建立连接 20 2 1TCP连接建立的过程 TCP连接的建立需耍连接的双方发送自己的同步SYN信息给对方 在SYN中包含了末端初始的数据序号 并且需要收到对方对白身发出SYN的确认 一个典型的TCP连接建立的过程如下 1 A B 2 A B 3 A B 20 2 2TCP连接的标示 TCP是实现两主机间进程的通信 所以只有两个主机的IP地址是不能标识条连接的 在TCP中 使用两个socket来标识一条连接 Socket由本地的IP地址和进程使用的端口号组成 这样对于一条TI P连接 就可以使用两个一元组来唯确定 或者使用四元组来表示 20 2 3关闭TCP连接 关闭一条TCP连接有3种可能的情况 发起连接的一方 主机A 请求关闭TCP连接 主机B主动请求关闭TCP连接 主机A和主机B同时发起断开连接的请求 其过程与上述两种情况大体相同 就不再详细介绍了 20 3UDP协议 UDP协议是一种无连接的协议 因此不需要像TCP那样通过三次握手来建立一个连接 同时 一个UDP应用可同时作为应用的客户或服务器方 由于UDP协议并不需要建立一个明确的连接 因此建立UDP应用要比建立TCP应用简单得多 使用UDP协议工作的服务器 通常是非面向连接的 因而服务器进程不需要像TCP协议服务器那徉建立连接 UDP服务器只需要在绑定的端口上等待客户机发送来的UDP数据报 并对其进行处理和响应 20 4socket简介 Socket接口是TCP IP网络的API Socket接口定义了许多函数或例程 程序员可以用它们来开发 TCP IP网络上的应用程序 要学Internet上的TCP IP网络编程 必须理解Socket接口 20 4 1socket的定义 在LINUX系统中 所有的I O操作都是通过读写文件描述符而产生的 socket 套接字 是一种特殊的文件描述符 当得到了一个socket之后 就可以使用send 和recv 系统调用与其他的程序通信 当然也可以使用read 和write 等系统操作调用而与其他的程序进行通信 但send 和recv 调用可以提供一种更好的数据通信的控制手段 20 4 2socket的类型 常见的socket有3种类型 流式socket数据报socket原始socket 20 5TCPServer程序设计 前面我们简单介绍了TCP IP协议 事实上该协议是十分复杂的 要编写一个优秀的网络程序也是十分困难的 笔者将尽最大可能简化相关细节的讨论 以便是读者能通过本章的学习 对网络程序的编写有一个概貌性的理解 而不是拘泥在各种细节之中 20 5 1TCP的通信过程 以最常用的TCP协议为例 一个典型的通信过程如图20 2所示 20 5 2TCPServer程序 为了介绍基于socket编程的基本流程和所用到的API函数 我们将通过一个实际的例子来学习 这个例子包含两个部分 服务器端程序和客户端程序 首先列出服务器端的程序的代码 稍后再介绍客户端程序 20 5 3网络地址的表示 在引入了众多头文件之后 源代码第12 13行定义了两个sockaddr in数据类型的变量 它们分别代表了服务器和客户端的网络地址 网络地址的表示主要通过两个重要的数据类型 sockaddr和sockaddr in 20 5 4建立socket 第17行到第26行为从命令行获得服务器的监听端口 第28行通过socket 系统调用建立了一个套接字socket 该系统调用的函数原型为 include includeintsocket intfamily inttype intprotocol 20 5 5绑定本地地址 先跳过第34 37行 在第39行 有一个很重要的函数bind 该函数可以帮助指定一个套接字使用的地址和端口 bind 的系统调用的函数原型如下 include includeintbind intsockfd structsockaddr sa intaddrlen 20 5 6字节顺序转换 如果你想将一个短型数据从主机字节顺序转换到网络字节顺序的话 有这样一个函数 它是以 h 开头的 代表 主机 紧跟着它的是 to 代表 转换到 然后是 n 代表 网络 最后是 s 代表 短型数据 H to n s 就是htons 函数 可以使用HosttoNetworkShort来助记 下面给出套接字字节转换程序的列表 htons htonl ntohs ntohl 20 5 7IP地址转换 为了绑定一个指定的IP地址 我们给出了一端代码 其中有一个陌生的函数 inet addr includein addr tinet addr constchar strptr 20 5 8Listen 函数 当调用bind 函数 将一个套接字绑定到某个端口上之后 就可以通过调用Listen 函数来准备接受客户端提请的连接请求了 listen 函数调用是非常简单的 该函数的函数原型如下 includeintlisten intsockfd intbacklog 20 5 9等待连接 请读者找到第55行 即 55if new fd accept sockfd structsockaddr 20 5 10数据通信 一旦成功建立起TCP连接 得到了一个socket 剩下要做的就是数据通信了 由于socket的本质就是文件描述符 因此 凡是基于文件描述符的I O函数几乎都可以用于数据通信 如read write put get 等 在本节的例程中我们就是用write 调用将消息 Hello 发给了客户端 1 send recv 函数 这两个函数是最基本的 通过连接的套接字流进行通讯的函数 与write 和read 函数的功能很相似 只是对了参数以用来对套接字进行读写操作控制 2 sendto 和recvfrom 函数 这两个函数是进行无连接的UDP通讯时使用的 使用这两个函数 则数据会在没有建立过任何连接的网络上传输 下面是sendto 函数和recvfrom 函数的声明 include includeintsendto intsockfd constvoid msg intlen unsignedintflags conststructsockaddr to inttolen intrecvfrom intsockfd void buf intlen unsignedintflagsstructsockaddr from int fromlen 20 5 11关闭套接字 当程序进行网络传输完毕后 就应该关闭这个套接字描述符所表示的连接 实现这个非常简单 只需要使用标准的关闭文件的函数 close 20 6TCPClient程序设计 客户端主要需要完成与服务器建立连接 请求数据 应答数据等工作 从代码上看 客户端程序有很多代码与服务器端程序都是相同的 所以我们在本节中主要关注那些与服务器端程序不同的实现 20 6 1DNS操作 DNS是 DomainNameService 域名服务 的缩写 有了它就可以通过一个可读性非常强的因特网名字得到这个名字所代表的IP地址 转换为IP地址后 就可以使用标准的套接字函数 bind connect sendto 或是其他任何需要使用的函数 例如 如果使用命令 ping可以知道它要访问的服务器IP地址是220 181 37 55 这就是通过DNS来实现的 20 6 2连接服务器 当客户端完成创建socket 填充服务器信息结构等工作后 就可以连接服务器了 如 43if connect sockfd structsockaddr server addr 44sizeof structsockaddr 44 1 这段代码中有一个在客户端程序中起着非常重要作用的函数 connect 函数 20 6 3测试实例 我们分别将服务器端程序编译为tcpserver 在PC机上运行 客户端程序一份交叉编译为tcpclient arm 在开发板上运行 一份编译为tcpclient pc 在PC机上运行 其中开发板的IP地址为192 168 1 20 开发板的IP地址为192 168 1 254 进行这个测试 读者需要打开3个终端 20 7UDP通信的程序设计 前面我们介绍了基于TCP的通信程序的设计 TCP协议实现了连接的 可靠的 传输数据流的传输控制协议 而UDP是非连接的 不可靠的 传递数据报的传输协议 由于UDP不提供可靠性保证 使得它具有较少的传输时延 因而UDP协议常常用在一些对速度要求较高的场合 20 7 1UDP的通信过程 UDP通信的基本过程如下 在服务器端 服务器首先创建一个UDP数据报类型的套接字 该socket的类型为SOCK DGRAM 代码如下 sockfd socket AF INET SOCK DGRAM 0 20 7 2UDP通信服务器端 下面我们通过一个例子 实际的看一看UDP通信是如何实现的 这个例程同样分为服务器端和客户端两个例程 20 7 3UDP通信客户端 客户端主要需要完成与服务器请求数据 应答数据等工作 与TCP通信的客户端不同的是 UDP通信的客户端不需要与服务器端建立连接 只要将数据包准备好 通过线路发出即可 因此UDP通信的客户端是不知道服务端是否正确的收到了发出的数据 除非程序员自己定义的应用层的通信协议 让服务器端反馈应答信息 这样才能保证通信的可靠性 20 8多线程文件服务器 整个服务器端程序由四个文件构成 分别为 fileserver c fileclient c rw h和rw c 其中fileserver c为多线程服务器的主程序 fileclient c是测试用的客户端程序 rw h和rw c主要提供了大数据量收发的功能函数 20 8 1文件服务器主程序 在多任务处理一章 我们曾讨论过多线程程序设计的问题 而且还与多进程的程序做过对比 得出在嵌入式系统中 应该优先考虑使用多线程来实现多任务处理 虽然采取创建子进程的方式来实现服务器同时对多个客户端服务的做法是最为常见的 但考虑嵌入式系统的实际 我们为读者提 硕嘞叱痰氖迪职咐 涫祷 镜乃枷攵 是一样的 就是为每个与客户端的连接创建一个处理子程序 20 8 2动态分配监听端口 出于某种目的的需要 服务器的监听端口需要动态的分配 如何实现这个功能呢 这需要补充一个函数的介绍 即getsockname 函数 getsockname 函数的作用是获得指定套接字的本地地址 其函数原型为 includeintgetsockname intsockfd structsockaddr addr int addrlen 20 8 3多线程服务器的实现 现在我们具体来阅读这段代码 实际上大部分的代码都与前面的例程是相似的 一直到for循环的代码才有了比较明显的区别 所以我们主要分析for循环和线程处理函数的内容 为了便于叙述 这里将for循环单独列出 并标上行号 20 8 4大数据量的读写函数 这里所指的大数据量是指超过read 或write 一次操作所能承载的数据量 我们知道read 函数和write 函数都有一个特点 若指定的数据量较大时 往往不能通过一次读写操作就完成所有的数据I O工作 往往需要根据它们返回的实际读取或写入的数据量 再进行若干此的读写操作 在rw c文件中提供了readall 和writeall 两个函数 解决了这个问题 20 8 5客户端测试例程 有了上面的三个文件 就可以构造出这个多线程的文件服务器了 同时 为了对这个服务器的功能进行测试 还需要编写一个合适的客户端程序 这样就有了下面的这个测试用的客户端程序 这个客户端程序是通过TCP协议与服务器端进行通信的 鉴于前面对TCPclient已做了详细的分析 这里就只列出该测试程序的代码 相信读者已经可以读懂这段代码了 20 8 6编译和测试 为了方便编译这些文件 我们还专门编写了Makefile文件 该文件的内容如下 CC gccall fileserverfileclientrw o rw c CC crw c orw ofileserver fileserver crw o CC fileserver crw o ofileserver lpthreadfileclient fileclient crw o CC fileclient crw o ofileclientclean rmfileserverfileclientrw o把这五个文件放在一个目录中 执行make命令就可以分别得到服务器程序fileserver和客户端程序fileclient 20 9PROXY源代码分析 初学编程最好的学习方法就是阅读高手所写的代码 Linux下有大量的优秀代码可供我们学习 笔者选择了一段Proxy 代理服务器 的源代码 尝试通过剖析这段代码 为读者深入揭示在网络编程中的常用知识和常见问题 这段代码的原作者是CarlHarris 虽然只是描述了最简单的proxy操作 但它不仅清晰地描述了客户机 服务器系统的概念 而且几乎包括了Linux网络编程的方方面面 非常适合Linux网络编程的初学者学习 20 9 1主函数main 一般从main 函数开始阅读和分析程序的代码 这个程序的整体框架十分清晰 是一段典型的服务器程序 网络通讯最重要的就是套接字的使用 在程序的一开始就对套接字描述符sockfd和newsockfd进行了定义 接下来定义客户机 服务器的套接字地址结构cliaddr和servaddr 存储客户机 服务器的有关通信信息 然后调用parse args argc argv 函数处理命令参数 20 9 2参数处理parse args 此函数的作用的处理命令行参数 这个函数的作用是传递命令行参数 参数的传递是通过两个全局变量来实现的 这两个变量是proxy port和hostaddr 分别用于传递等待连接请求的proxy端口和被绑定的主机地址信息 函数首先要检测命令行参数是否符合程序的要求 即在命令后紧跟代理服务器端口 远程主机名和服务端口号 如果不满足上述要求 则代理服务器程序终止 如果满足上述要求 则将命令行的这三个参数存储进自定义的pargs结构之中 注意pargs结构的三个成员都是以字符形式存放命令行参数信息的 后面我们需要调用函数将这些参数信息都转换成为数字形

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论