二、嵌入式操作系统uClinux下的网络socket编程
网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用;Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket:SOCK_STREAM和数据报式Socket:SOCK_DGRAM。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
1 uCLinux中socket编程中用到的函数
(1)socket函数:int socket(int domain, int type, int protocol);
为了执行I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型(使用IPv4的TCP、使用IPv6的UDP、Unix域字节流协议等)。
(2)connect函数: int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);TCP客户用connect函数来建立一个与TCP服务器的连接。
(3)bind函数:int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
函数bind给套接口分配一个本地协议地址。对于网际协议,协议地址是非颠倒2位IPv4地址16位的TCP或UDP端口号的组合。
(4)listen函数: int listen(int sockfd, int backlog);
函数listen仅被TCP服务器调用。它做两件事件事情,当函数socket创建一个套接口时,被假设为一个主动套接口。也就是说,它是一个将调用connect发起连接的客户套接口,函数listen将未连接的套接口转换成被动套接口,指示内核应接受指向此套接口的连接请求。根据TCP状态转换调用函数listen导致套接口从CLOSED状态转换到LISEN状态。一般来说,此函数应在调用函数socket和bind之后,调用函数accept之前调用。
(5)accept函数: int accept(int sockfd, void *addr, int *addrlen);
accept函数由TCP服务器调用,从已完成连接队列头返回下一个已完成连接。若已完成连接队列为空,则进程睡眠。(假定套接口是缺省的阻塞方式)
(6)send() and recv()函数:
int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, unsigned int flags);
这两个函数用于流式套接字或者数据报套接字的通讯,使用无连接的数据报套接字,应该使用于sendto() 和 recvfrom()函数
2 uClinux中网络通信编程的实现
TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:
1)、非对等作用;
2)、通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务:(过程如下)
1.打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求;
2.等待客户请求到达该端口;
3.接收到重复服务请求,处理该请求并发送应答信号;
4.返回第二步,等待另一客户请求;
5.关闭服务器;
客户方:
1.打开一通信通道,并连接到服务器所在主机的特定端口;
2.向服务器发送服务请求报文,等待并接收应答;继续提出请求……;
3.请求结束后关闭通信通道并终止;
根据上面介绍的socket函数我们可以画出面向连接的套接字的系统调用时序图:
在这里要说明的是计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换。
应该说uClinux同标准Linux的最大区别就在于内存管理,同时也由于uClinux的内存管理引发了一些标准Linux所不会出现的问题。uClinux对内存的管理减少同时就给开发人员提出了更高的要求。由于应用程序加载时必须分配连续的地址空间,而针对不同硬件平台的可一次成块(连续地址)分配内存大小限制是不同,所以开发人员在开发应用程序时必须考虑内存的分配情况并关注应用程序需要运行空间的大小。另外由于采用实存储器管理策略,用户程序同内核以及其它用户程序在一个地址空间,程序开发时要保证不侵犯其它程序的地址空间,以使得程序不至于破坏系统的正常工作,或导致其它程序的运行异常。从内存的访问角度来看,开发人员的权利增大了(开发人员在编程时可以访问任意的地址空间),但与此同时系统的安全性也大为下降。