以文本方式查看主题

-  曙海教育集团论坛  (http://sun4.cn/bbs/index.asp)
--  Linux应用开发  (http://sun4.cn/bbs/list.asp?boardid=32)
----  Linux Socket编程及其在无线网关中的应用  (http://sun4.cn/bbs/dispbbs.asp?boardid=32&id=1681)

--  作者:wangxinxin
--  发布时间:2010-11-23 13:22:06
--  Linux Socket编程及其在无线网关中的应用

l  引言

Linux具有丰富的网络功能,完善的内置网络是Linux的一大特点。嵌入式Linux专用于微控制器,同样具有优秀的网络功能。Linux是一种可移植的操作系统,能够在从微型计算机到大型计算机的任何环境中和任何平台上运行。可移植性为运行Linux的不同计算机平台与其他任何机器进行准确而有效的通讯提供了手段,不需要另外增加特殊的,昂贵的通讯接口。

该文在构建基于嵌入式Linux和MPC852T无线网关平台的基础上,编程实现了无线网关平台与无线终端之间的无线通信,并给出了无线网关平台与无线终端之间通信的测试结果。

2  Linux下的socket编程

2.1 Socket编程

socket有3种类型:流式套接字、数据报套接字及原始套接字。流式套接字定义了一种可靠的面向连接的服务,实现了无差错的数据传输。数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠。原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。

无连接服务器一般都是面向事务处理的,一个请求和一个应答就完成客户程序与服务程序之间的相互作用。

面向连接服务器处理的请求比较复杂,往往是并发服务器。工作过程如下:服务进程首先调用socket( )创建一个字节流套接字,并调用bind( )将服务器地址捆扎在该套接字上,接着调用listen( )监听连接请求,随后调用accept( )做好与客户进程建立连接的准备,无连接请求时,服务进程被阻塞。当连接请求到来后,服务器进程被唤醒,建立一个新的Socket,并用新套接字同客户进程的套接字建立连接,而服务进程最早生成的套接字则继续用于监听网络上的服务请求。客户进程调用socket( )创建字节流套接字,然后调用connect( )向服务进程发出连接请求。服务进程和客户进程通过调用read( )/recv( )和Write( )/send( )交换数据。

2.2 Linux下的socket函数库

socket是面向用户的,针对客户和服务器程序提供不同的socket系统调用。客户随机申请一个socket,系统为之分配一个socket号,服务器拥有全局公认的socket,任何客户都可以向它发出一个连接请求和信息请求。无论socket的内部机制如何,它提供给程序员的最终是一组系统调用,即socket的库函数。Linux这些库函数同样适用于嵌入式linux。下面是编制程序常用的库函数:

1) socket( ):建立Socket,此函数用来建立Socket描述字,并为此Socket建立资源(为一个Socket数据结构分配存储空间)。应用程序在使用socket之前,首先必须拥有一个socket。socket( )向应用程序提供创建socket的手段。socket( )函数原形为int socket(int domain,int type,int protoco1);函数中的domain是参数指定通信中使用的协议簇,也就是网络的类型,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型:SOCK_STREAM或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol是参数指定通信中使用的协议。

函数在正常时返回socket描述符;否则返回l,错误状态在全局变量error里。

2) bind( ):绑定本地地址,即将一个本地地址与一个SOCKET描述字连接在一起。此函数在服务程序上使用,是调用监听函数listen()必须要调用的函数。

Bind函数原型为:

int bind(int sockfd, struct sockaddr *my_addr, int addrlen)。bind()函数给已经打开的socket指定本地地址。函数中的sockfd是调用socket函数返回的socket描述符;addrlen是my-addr结构的长度,常被设置为sizeof(struct sockaddr);my-addr是用于侦听连接请求的本地地址。

函数在正常时返回0,否则返回l,同时error是系统错误码。

3) listen( ):准备接收连接请求。在用bind()给一个socket设定本地地址之后,就可以将这个socket用于接受连接请求,即listen()。函数原形为int listen(int s,int backlog);函数中的s是socket描述符;backlong是连接请求暂存队列长度。

函数正常时返回0,否则返回1,同时error是系统错误码。

4) accept( ):服务端应用程序调用此函数来接受客户端socket连接请求。在系统调用listen( )之后,系统就在socket的连接请求暂存队列里存放每一个向该socket建立的连接请求,accept()的作用是从该暂存队列中取出一个连接请求,用该socket的数据,创建一个新的socket用来在服务端和客户端之间传递接收信息,而原来socket仍然可以接收其他客户端的连接要求。

函数正常创建了一个新的连接,那么返回非负的整数,即新连接的socket描述符,否则返回l,error是系统错误码。

5) connect( ):建立连接。bind( ),listen( )和accept( )都是用于被动地等待对方建立连接时需要使用的,connect( )函数是在主动地向对方建立连接时使用的。函数原形为int connect(int sockfd,struct sockaddr*srvaddr,int addrlen);函数中的sockfd是socket描述符;srvaddr是通信目的方地址;addrlen是目的地址长度。

函数在正常建立连接时返回0,否则返回l,系统错误码在error中。

6) close( ):此函数是用来关闭某一socket。socket和文件描述符的关闭操作都使用这个函数。函数原形为int close(int fd);参数fd是socket描述符。函数在正常时返回0,返回1表示出错。

7) send( )/recv( ):用于socket的发送和接收数据。在连接建立完成后,通信双方就可以使用以上这些函数来进行数据的发送和接收操作。

3 无线网关平台的构建

为了将无线终端设备接入控制网络实现远程监控,根据条件构建了基于MPC852T和嵌入式Linux的无线网关平台。MPC852T是Motorola推出的面向低端的一款通信处理器,具有通信和网络处理能力强、可靠性高、功耗低、功能集成度高等优点,并且有众多的操作系统支持,这使得它在各种嵌入式系统,尤其是在网络通信以及数据采集和传输等系统中的应用较为广泛。

无线网关的硬件设计方案采用中心控制方案,中央处理器选用MPC852T,在MPC852T外围配置一个RS-232串口、一个10M以太网口、一个100M以太网接口、SDRAM同步动态随机存储器等构成无线网关的硬件平台,无线网关的硬件系统结构图如图1所示。

无线网关与无线终端通信的实现

嵌入式Linux具有完善的TCP/IP协议栈,为满足工业控制过程中传输数据量小、可靠性高、速度快等要求,这里使用socket编程来实现网络通信。无线终端通过无线网卡与无线网关自动建立链接,无线终端完成数据的采集,并将采集的数据以无线的方式发送给网关,无线网关把收到的数据上传给上位机进行分析、处理,最后计算出数据发送的速率。

图片点击可在新窗口打开查看

将编写好的服务器端和终端程序进行交叉编译,将编译得到的二进制可执行文件添加到RAMDISK中,压缩新生成的ramdisk.image文件系统映像文件,重新编译Linux内核,生成Linux内核映像文件,然后将内核映像文件烧写到无线网关平台的FLASH中。无线网关平台(服务器端)的主程序代码如下:

#define PORT 3000       /*设定服务器监听端口*/

………………

int main(int argc,char* argv[ ])

{

int second;

int sockfd,new_fd;           /* sockfd为监听用描述符*/

struct sockaddr_in srvaddr;    /*定义服务器sock地址*/

struct sockaddr_in cliaddr;    /*定义客户的sock地址*/

………………

if(bind(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1)    /*绑定*/

………………

if(listen(sockfd, QUEUE_SIZE) == -1)        /*监听端口是否有请求*/

………………

for(;;){          /*开始服务器循环*/

/*等待连接*/

sin_size=sizeof(struct sockaddr_in);

new_fd=accept(sockfd,(struct sockaddr*) &cliaddr,&sin_size);      /*接收连接请求*/

printf("Server:Got connection from %s \\n",

inet_ntoa(cliaddr.sin_addr));

if(read(new_fd,&second,4)==-1)      /*接收连接请求*/

………………

close(new_fd);        /*父进程不再需要该socket*/

………………;       

close(sockfd);

return 0;

}

}

测试结果

在上位机开启通信终端,设置好串口参数,进入超级终端。无线网关平台上运行服务器端程序,同时在终端上运行客户端程序,即可进行测试,测试结果如图2所示。

图片点击可在新窗口打开查看

图2  无线网关与无线终端测试结果图

6  

目前基于TCP/IP协议的工业以太网的在组网时仍需要布线,但在工业现场,布线时常会受到限制,电缆的连接也限制了现场设备的移动和网络结构的重组,还有一些高速旋转设备根本无法通过电缆来传输数据。将802.11b无线通信技术应用于工业控制网络,工控网络就兼有了无线通信的优点:现场设备无需电缆即可与控制网络连接,实现现场数据的无线采集和传输,对于在一些不可预知的环境,尤其是不适于布线的强腐蚀恶劣环境。本文作者创新点:通过Linux下的socket编程实现了无线网关与无线终端的通信,可以使用无线通信来完成对现场设备的控制。