Linux是一种很受欢迎的操作系统,与UNIX系统兼容,开放源代码。它原来被设计为桌面系统,现在广泛运用于嵌入式设备。uCLinux正是在这种氛围下产生的。在uCLinux这个英文单词中,u表示Micro,是“小”的意思;C表示Control,是“掌握”的意思,以是uCLinux便是Micro-Control-Linux,字面上的理解便是“针对微掌握领域而设计的Linux系统”。它也是针对无MMU(内存管理单元模块)的微处理器设计的操作系统。S3C4510B便是属于该类的微处理器。
Samsung公司的S3C4510B是基于以太网运用系统高性价比16/32位RISC微掌握器,内含一个由ARM公司设计16/32位ARM7TDMI RISC处理器核。ARM7TDMI为低功耗、高性能的16/32核,最适宜用于对价格及功耗敏感的运用处所。除了ARM7TDMI核以外,S3C4510B还有许多主要的片内外围功能模块,个中就有1个以太网掌握器,用于S3C4510B系统与其它设备的网络通信工程。在S3C4510B的网络掌握平台上移植了uCLinux操作系统,并在这个嵌入式平台上实现网络掌握的各项功能。本文的阐述的网络通信工程便是个中最紧张的功能。

1 基于S3C4510B以太网电路的设计思路与实现

作为一款精良的网络掌握器,基于S3C4510B的系统若没有以太网接口,其运用代价就会大打折扣,因此,就全体系统而言,以太网接口电路应是必不可少的,但同时也是相对较繁芜的。从硬件的角度看,以太网接口电路紧张由MAC掌握器和物理层接口(Physical Layer,PHY)两大部分构成。
S3C4510B内嵌一个以太网掌握器,支持媒体独立接口(Media Independent Interface,MII)和带缓冲DMA接口(Buffered DMA Interface,BDI),可在半双工或全双工模式下供应情报0M/100Mbps的以太网接入。在半双工模式下,掌握器支持CSMA/CD协议,在全双工模式下支持IEEE802.3MAC掌握层协议。因此,S3C4510B内部实际上已包含了以太网MAC掌握,但并未供应物理层接口,故需外接一片物理层芯片,以供应以太网的接入通道。
常用的单口10M/100Mbps高速以太网物理层接口器件紧张有RTL8201、DM9161等,均供应MII接口和传统7线制网络接口,可方便地与S3C4510B接口。以太网物理层接口器件紧张功能一样平常包括:物理编码子层、物理媒体附件、双绞线物理媒体子层、10BASE-TX编码/解码器和双绞线媒体访问单元等。
在该设计中,利用DP9161作为以太网的物理层接口。DM9161是一款低功耗、高性能的CMOS芯片,支持10M和100M的以太网传输,它起编码、译码输入和输出数据的浸染。它与S3C4510B的引脚连线如图图1所示。
由于S3C4510B片内已民用有带MII接口的MAC掌握器,而DM9161也供应了MII接口,各种旗子暗记的定义也很明确,因此DM9161与S3C4510B的连接时序衔接,可以达到很好的网络旗子暗记通报的目的。图2为DM9161在本系统中的实际运用电路(图中右下方的1、2、3以及14、15、16分别与网络隔离变压器相应引脚相连)。
S3C4510B的MAC掌握器可通过MDC/MDIO管理接口掌握多达斡尔1个DM9161,每个DM9161应有不同的PHY地址(可从00001B~11111B)。当系统复位时,DM9161锁存引脚9、10、12、13、15的初始状态作为与S3C4510B管理接口通信工程的PHY地址;但该地址不能设为00000B,否则DM9161进入掉电模式。
旗子暗记的发送和吸收端应通过网络隔离变压器和RJ45接口接入传输媒体,实际运用电路如图书室所示。
图2
2 Linux下的网络编程协议剖析
Linux下的TCP/IP网络协议栈的各层之间是通过一系列相互连接层的软件来实现Internet地址族的,构造层次如图4所示。
个中BSD socket层由专门用来处理BSD socket的通用套接字管理软件来处理,它由INET socket层来支持。INET socket为基于IP的协议TCP和UDP管理传输端点。UDP(用户数据报协议)是一个无连接协议,而TCP(传输掌握协议)是一个可靠的端对端协议。传输UDP包的时候,Linux不知道也不关心它们是否安全到达了目的地。TCP则不同。在TCP连接的两端都须要加上一个编号,以担保传输的数据被精确吸收。在IP层,实现了Internet协议代码,这些代码要给传输的数据加上一个IP头,并且知道如何把传入的IP包送给TCP或者UDP协议。在IP层以下,便是网络设备来支持所有的Linux网络事情,如PLIP、SLIP和以太网。
3 uClinux环境下的socket编程
网络的socket数据b传输是一种分外的I/O,socket也是一种文件描述符,也具有一个类似文件的函数调用socket。该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过该socket函数实现的。常用的socket类型有两种:流式socket和数据报式socket。两者的差异在于:前者对应于TCP做事,后者对应于UDP做事。
3.1 uCLinux中socket编程中用到的函数
(1) socket函数
为了实行I/O,一个进程必须做的第一件事情便是调用socket函数,指定期望的通信协议类型(利用IPv4的TCP、利用IPv6的UDP、Unix域字节流协议等),其函数构造如下:int socket(int family,int type,int protocol);
/返回:非负描述字—成功,-1—出错/
代码中的family指明协议族。套接口的类型type是某个常值。一样平常来说,函数socket的参数protocol主设置为0,socket函数成功时返回一个小的非负整数值。为了得到这个数值,我们指定协议族(IPv4IP、v6或Unix)和套接口类型(字节流、数据报或原始套接口)。
(2)connect函数
TCP客户用connect函数来建立一个与TCP做事器的连接。
Int connect(int sockfd,const struct sockaddr servaddr,socklen_t addrlen);/返回:0—成功,-1—出错/
Sockfd由socket函数返回数值,第二、第三个参数分别是一个批晌套接口地址构造的指针和该构造的大小。套接口叶址构造必须含有做事器的IP地址和端口号。
(3)bind函数
函数bind给套接口分配一个本地协议地址。对付网际协议,协议地址是非颠倒2位IPv4地址16位的TCP或UDP端口号的组合。
Int bind(int sockfd,const struct sockaddr myaddr,socklen_t addrlen);/返回:0—成功,-1—出错/
第二个参数量个指向特定于协议地址构造的指针,第三个参数是该地址构造的长度。对付TCP,调用函数bind可以指定一个端口,指定一个IP地址。可以两者都指定,也可以一个也不指定。
(4)listen函数
函数listen仅被除数TCP做事器调用。它做两件事宜事情,当函数socket创建一个套接口时,被假设为一个主动套接口。也便是说,它是一个将调用connect发起连接的客户套接口,函数listen将未连接的套接口转换成被动套接口,指示内核应接管指向此套接口的连接要求。根据TCP状态转换调用函数listen导致套接口从CLOSED状态转换到LISEN状态。函数的第二个参数规定了内核为此套接口排队的最大连接个数。
Int listen(int sockfd,int backlog);
/返回:0—成功,-1—出错/
一样平常来说,此函数应在调用函数socket和bind之后,调用函数accept之前调用。
(5)accept函数
accept函数由TCP做事器调用,从已完成连接行列步队头返回下一个已完成连接。若已完成连接行列步队为空,则进程就寝。(假定套接口噗缺省的壅塞办法)
int accept(int sockfd,struct sockaddrcliaddr,socklen_taddrlen);/返回非负数值—OK,-1—出错/
参数cliaddr和addrlen用来返回连接对方进程(客户)的协议地址。Addrlen是结果参数,调用前,将由addrlen所指示的整数值置为由cliaddr所旨的套接口地址构造的长度,返回时,此整数值即为由内核存在此套接口地址构造内的准确字节数。
3.2 uClinux中网络通信编程的实现
在uCLinux中进行socket编程,一样平常按照图书资料所示流程编写网络运用程序。
除了熟习前文提出的函数外,还应知道两个主要的数据构造。由于在打算机中,数据存储有两种字节优先顺序:高位字节优先和低位字节优先。在互联网上,数据因此高位字节优先顺序传输的,以是对付在内部以低位字节优先办法存储的数据,须要进行转换才能在互联网上传输。
struct sockaddr:用来保存socket信息
struct sockaddr{unsigned short sa_family;/地址族,AF_xxx/
char sa_data[14]; /14字节的协议地址/};
struct sockaddr_in;和来进行数据类型的转换
struct sockaddr_in{
short int sin_family; /地址族/
unsigned short int sin_port; /端口号/
sruct in_addr sin_addr; /IP地址/
unsigned cha sin_zero[8]; /添补0,以保持与struct sockaddr同样大小/};
至此,可经编出uCLinux的网络通信工程程序。在此给出部分uCLinux下实现网络通信源代码及其Makefile文件的编写实例。
main函数中部分代码如下:
int sockfd;
unsigned int uiip;
char szsendbuf[1024];
char head[8];
intphead=head+4,nsize=1024,allsize=0;
struct sockaddr_in servaddr;
sockfd=socket(AF_INET,SOCK_STREAM,0);/创建socket/
bzero(&servaddr,sizeof(struct sockaddr_in));
servaddr.sin_family=AF_INET;
servaddr.sin_port=8888;//htons(8888); /指定通信端口/将命令行输入的字符串IP转换为connect函数可识别的整数uiip。本来在Linux上开拓时可以利用C库函数inet_pton,但在uCLinux的库中不支持该函数,因此只好自己实现该函数的功能。
aiptoi如下所示:
aiptoi(argv[1],&uiip);
servaddr.sin_addr.s_addr=uiip; /指定连接的对端IP/
connect(sockfd,(struct sockaddr)&servaddr,sizeof(struct sockaddr));
/连接对端吸收代码/
fp=fopen(\公众kongzhi.htm\"大众,\公众r\公众); /打开掌握页面/
while(nsize==1024)
{bzero(szsendbuf,1024); /每次从文件中读取巧024个字节发送出去,若读出少于1024字节结束/
nsize=phead=fread(szsendbuf,1,1024,fp);/从文件中读取并填入发送BUFFER中/
write(sockfd,head,8);/发送协议头/
nsize=write(sockfd,szsendbuf,nsize);/发送/}
fclose(fp);
uCLinux中的Makefile需做的修正如下:
CC=gcc
COFF2FLAT=/uclinux/coff2flt-0.3/coff2flt
CFLAGS=-I/uclinux/uC-libc-pic/include
LDFLAGS=/uclinux/uC-libc-pic/libc.a
ethernet:Ethernet.o
$(CC)-o $@.coff ethernet.c $(CFLAGS)$(LDFLAGS)
$(COFF2FLAT)-o Ethernet ethernet.coff
cp Ethernet /Ethernet
clean:
rm -f Ethernet Ethernet.o
须要把稳的是:①uCLinux中不带有pthread库,在编写网络程序要牢记;②在uCLinux环境下,处理器(硬件)和内核黄素(软件)均不供应内存管理机制,以是程序的地址空间等同于内存的物理地址空间。在程序中可直接对I/O地址进行操作,而不须要申请和开释I/O空间,但须要用户自己来检讨所操作的I/O地址的占用情形。
结语
由于网络通信工程广泛运用在嵌入式设备中,以往的文章只是泛泛地阐述网络通信设计的某一个方面。本文结合实际工程项目,从硬件电路的搭建、运用软件的设计要点。这对付在嵌入式设备中,特殊是基于uCLinux的系统中运用网络通信有主要的参考意义。
AET会员年终大福利!









