基于嵌入式的socket编程及其应用
2015-11-10任安虎李鹏飞
任安虎 李鹏飞
摘 要:socket套接字可提供一种在不同计算机,不同系统间通信的解决方案,是在实际网络编程中使用的重要手段,并且在不同的平台拥有完善的API接口函数和实现方法。TCP/IP协议是目前使用最广泛的Internet网络服务协议,该协议免费、稳定、通用性强,是轻量级数据传输的最主流解决方案。文中提供了在TCP/IP协议下的socket编程方法,并建立了一个基于Linux操作系统和S3C2440的ARM嵌入式平台。使用此方法可实现基于Linux操作系统的ARM平台与Windows系统的PC间通信。
关键词:socket编程;TCP/IP协议;嵌入式;ARM微处理器;Linux操作系统;应用程序编程接口
中图分类号:TP393.03 文献标识码:B 文章编号:2095-1302(2015)10-00-03
0 引 言
近年来,随着智慧城市等概念的兴起,嵌入式系统在很多领域得到了空前发展。而嵌入式设备与计算机间的数据通信技术是该系统重要的支撑技术[1],以此入手,提供一种基于TCP/IP协议的socket编程实现ARM平台与PC间的数据通信解决方案,其设计思路与源码,可供读者参考借鉴。
使用搭载ARM9架构的S3C2440微处理器和DM9000系列网卡的TX2440A开发板,并在其上移植Linux系统,该系统具有优秀的网络功能,被广泛应用于嵌入式领域[2]。将ARM开发板作为客户端,PC作为服务器,通过socket编程使ARM平台与PC端建立通信,关键源码及详细解释将在最后给出。
1 Socket编程原理及API函数简介
Socket最早出现于UNIX系统中,是TCP/IP协议栈向应用程序提供的API接口,用于在两个基于TCP/IP协议的应用程序间相互通信。但设计人员也考虑了socket的扩展,使之可以适用于其他网络协议,具有良好的通用性[3]。
常见的socket类型分为三种:流模式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAM)。实现作为客户端的ARM平台与服务器端的PC间的通信,即实现Linux系统与Windows系统间的通信,因此对应的socket接口函数也有两套:分别为Linux系统的socket函数和Windows系统的socket函数,socket主要包括用于连接的connect函数,用于接受连接的accept函数,用于发送数据的send函数,用于接收数据的recv函数等。以上函数分别为Linux操作系统的客户端和Windows操作系统的服务器端socket编程主要使用的函数,只有基于对这些函数的了解和认识,才能更好地理解跨平台网络通信的原理和方法。
2 客户端在ARM上的移植
搭载S3C2440微处理器的TX2440A开发板,在其上移植2.6.32内核版本的Linux系统。通过Linux系统的arm-linux-gcc交叉编译工具将客户端源码进行交叉编译,生成二进制可执行文件,将该文件拷贝至开发板运行,即可打开客户端应用程序。
客户端应用程序的主要源代码如下:
……
int port = atoi(args[2]);
int st = socket(AF_INET, SOCK_STREAM, 0); //初始化socket,
struct sockaddr_in addr; //定义一个IP地址的结构
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; //设置结构地址类型为TCP/IP地址
addr.sin_port = htons(port); //端口号:htons:将short类型从host字节类型到 net字节 类型转化
addr.sin_addr.s_addr = inet_addr(args[1]);//将字符串类型的IP地址转化为int,赋给addr结构成员.
//调用connect连接到结构addr指定的IP地址和端口号
if (connect(st, (struct sockaddr *) &addr, sizeof(addr)) == -1)
……
while (1)
{
……
read(STDIN_FILENO, s, sizeof(s)); //从键盘读取用户输入
if (send(st, s, strlen(s), 0) == -1) //发送buf的数据
……
if (recv(st, s, sizeof(s), 0) > 0) //如果接收数据失败,循环break
printf("recv %s\n", s);
……
}
close(st); //关闭socket
……
由程序可以看出,客户端首先创建一个套接字和一个结构体sockaddr保存服务器网络信息,然后调用connect函数将套接字连接到该结构体指定的IP地址和端口号,连接成功后建立一个字符串s,以死循环的模式读取键盘输入写入s,并调用send函数将s发送出去,然后调用recv函数从服务器端接收消息。如果接收数据失败,则退出循环,关闭套接字。
3 服务器端在PC上的建立
使用Microsoft visual stdio 2013作为开发编译环境,界面友善,功能强大。
服务器端应用程序主要源代码如下:
……
//加载socket库函数
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
……
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return 0;
}
printf(“load socket function success!\n”);
……
//将IP与server程序绑定
if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1)
……
//server端开始listen,
if (listen(st, 20) == -1)
……
int client_st = 0;//client端socket
struct sockaddr_in client_addr; //表示client端的IP地址
int len = sizeof(client_addr);
……
//accept会阻塞,直到有客户端连接过来,accept返回client的socket描述符
client_st = accept(st, (struct sockaddr *)&client_addr, &len);
……
while (1)
{
……
int rc = recv(client_st, s, sizeof(s), 0); //recv是阻塞调用,
if (rc > 0) //接收来自client的消息
{
……
fgets( s, sizeof(s), stdin);
send(client_st, s, strlen(s), 0);
}
else
{
……
}
}
close(client_st); //关闭client端socket
close(st); //关闭server端listen的socket
……
由程序可以看出,服务器端首先调用WSAStartup函数加载Windows socket库函数,创建一个套接字和一个结构体sockaddr保存本地网络信息,调用bind函数将套接字与本地网络信息绑定并调用listen函数开始侦听。然后创建一个客户端套接字描述符client_st和一个sockaddr_in格式的结构体用于存储客户端网络信息。当有客户端发起connect请求时,程序调用accept函数与客户端建立连接,连接成功后建立一个字符串s,以死循环的模式接收来自客户端的数据写入s并打印在屏幕上,并读取键盘输入写入s,并调用send函数将s发送出去,如果接收失败则退出循环,释放客户端和服务器端套接字的资源。
4 嵌入式设备与计算机的网络连接
上面章节对客户端和服务器端的源码和原理分别做出介绍,读者也许不能从整体上很好地理解,图1展示了TCP/IP的客户端/服务器程序模型,帮助读者能更直观的理解TCP/IP网络连接的原理和流程[4]。
相信结合程序模型图,以及上面章节对原理和源码的介绍,读者很容易的理解网络中客户端和服务器收发数据的原理和流程。下面给出客户端和服务器端应用程序实际在两个平台上运行的结果演示。
首先,在VS2013中打开服务器源码srv.c,编译运行,服务器阻塞等待客户端连接请求。其打开图如图2所示。
其次,使用交叉编译工具arm-linuc-gcc编译客户端源码,生成二进制可执行文件clt,将其拷贝至开发板,配置开发板网络环境,打开客户端应用程序,通过超级终端查看开发板的运行情况,具体如图3所示。
图1 TCP/IP程序模型图
图2 服务器打开
图3 客户端连接服务器
可以看到服务器已经接受了客户端的连接请求,此时服务器已经可以和客户端进行通信,图4所示是服务器语客户端进行通信的操作图形。
图4 服务器与客户端通信
5 结 语
伴随微型专用计算机的发展,嵌入式设备将用于生活的方方面面,嵌入式设备与计算机的通信需求也随之增长。本文介绍了socket编程机制及跨平台实现了一组套接字程序,可以看出socket描述网络程序直观、实用性强、框架清晰。该系统目前基本实现了即时通信的功能,但尚有一些不完善的地方,如未能实现服务器处理并发客户端连接请求,下一步我们将对该系统进行改进和完善。
参考文献
[1]詹文元,金花,程永谊. 基于嵌入式网关的socket编程及通信协议[J].可编程控制器与工厂自动化,2005(1):117-122.
[2]林伟,黄康.基于S3C44B0X的嵌入式网络通信研究[J].微计算机信息,2007,23(8):36-39.
[3]王堃,于悦,张玉华,等. 面向物联网应用平台的Socket设计与优化[J].吉林大学学报(工学版),2012,42(S1):290-294.
[4]邓全良.Winsock网络程序设计[M].北京:中国铁道出版社,2002:36-38.
[5]吴佩贤.Linux环境下基于TCP的Socket编程浅析[J].现代电子技术,2005,28(16):53-56.
[6]郭东升,田秀华.Linux环境下基于Socket的网络通信[J].软件导刊,2009,8(1):116-118.
[7]王晓鹏.TCP/IP下的Socket及Winsock通信机制[J].航空计算技术,2004,34(2):126-129.
[8]刘赟. Winsock技术在网络通信系统中的应用[J].西南科技大学学报,2013,28(2):88-92.