基于以太网跨平台双机会话Word文件下载.docx
《基于以太网跨平台双机会话Word文件下载.docx》由会员分享,可在线阅读,更多相关《基于以太网跨平台双机会话Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
关于这方面的知识参见〈嵌入式系统原理与接口技术实验指导书〉以及第1章相关部分。
2、uClinux的socket编程知识
socket是网络通信中应用进程和网络协议之间的一种网络编程接口,它是对通信端点的一种抽象,提供了一种发送和接受数据的机制。
再Linux系统中,socket属于文件系统的一部分,网络通信可以被看作是对文件的读取。
〈1〉socket编程常用函数
uClinux具有优秀的网络功能,提供和linux一样的socket系统调用函数。
下面是编制程序常用的系统调用函数:
①.socket():
分配socket
应用程序在使用socket之前,首先必须拥有一个socket。
socket()向应用程序提供创建socket的手段。
socket()函数原形如下:
int
socket(intdomain,inttype,intprotocol);
参数说明:
domain:
说明网络程序所在的主机采用的通信协议(AF_UNIX和AF_INET等)。
AF_INET是针对Internet的,允许在远程主机之间通信。
Type:
网络程序所采用的通信协议(SOCK_STREAM,SOCK_DGRAM等)。
其中SOCK_STREAM表明用的是TCP协议。
Protocol:
由于指定了type,所以一般用0来代替。
②.bind():
绑定本地地址
bind()函数给已经打开的socket指定本地地址。
函数原形如下:
intbind(intsockfd,structsockaddr*my-addr,intaddrlen);
sockfd:
是由socket()调用返回的文件描述符。
Addrlen:
是sockaddr结构的长度。
my-addr:
是一个指向sockaddr的指针。
③.listen():
准备接受连接请求
在用bind()给一个socket设定本地地址之后,就可以将这个socket用于接受连接请求,即listen()。
intlisten(intsockfd,intbacklog);
是调用过bind()后的文件描述符。
Backlog:
设置请求排队的最大长度。
④.accept():
接受指定socket上的连接请求
在系统调用listen()之后,系统就在socket的连接请求暂存队列里存放每一个向该socket建立的连接请求,accept()的作用是从该暂存队列中取出一个连接请求,用该socket的数据,创建一个新的socket。
intaccept(intsockfd,void*addr,int*addrlen);
是listen后的文件描述符。
addr、addrlen:
这两个参数将会被客户端的程序填写,服务器端只要传递指针就可以了,它用来描述连接进来的客户端的信息。
⑤.connect():
建立连接
bind(),listen()和accept()都是用于被动地等待对方建立连接时需要使用的,connect()函数是在主动地向对方建立连接时使用的。
intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen);
socket返回的文件描述符。
serv_addr:
存储了服务器端的连接信息。
serv_addr的长度,可以使用sizeof(structsockaddr)获得。
⑥.send(),recv():
用于socket的发送和接收数据
在连接建立完成后,通信双方就可以使用以上这些函数来进行数据的发送和接收操作。
send(),recv()函数原形如下:
intsend(intsockfd,constvoid*msg,intlen,unsignedintflags);
intrecv(intsockfd,void*buf,intlen,unsignedintflags);
希望进行数据传递的套接口的文件描述符。
asg:
指向希望发送的数据的指针。
len:
对于发送来说,它是希望发送的数据的字节长度。
若是recv(),则它表示接收缓冲的最大长度。
flags:
这个参数可以是0或者是下表中的各项的组合。
Flags参数选项
宏定义
含义
MSG_DONTROUTE
不查找路由表
MSG_OOB
接收或者发送带外数据
MSG_WAITALL
等待所有数据
MSG_PEEK
查看数据,并不从系统缓冲区移走数据
●MSG_DONTROUTE:
是send()函数使用的标志,这个标志告诉IP协议目的主机再本地网络上面,没有必要查找路由表。
●MSG_OOB:
表示可以接收和发送带外的数据。
●MSG_WAITALL:
是recv()函数的使用标志,表示等到所有的信息到达时才返回。
●MSG_PEEK:
是recv()函数的使用标志,表示只是从系统缓冲区中读取内容,而不改变系统缓冲区中的内容。
⑦.Sendto():
指定目的地址
因为数据报套接口是无连接,它并不连接到远程的主机上,所以再发送数据包之前,必须首先给出目的地址。
函数原型如下:
intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen);
除了最后两个参数以外,其他的参数含义与系统调用send()时相同。
其中,参数to是指向包含目的IP地址和端口号的数据结构sockaddr的指针。
参数tolen可以设置为sizeof(structsockaddr)。
⑧.close():
关闭socket
socket和文件描述符的关闭操作都使用这个函数。
intclose(sockfd);
调用这个函数以后,就不能再对此套接口进行任何的读写操作了。
〈2〉.数据流和数据报通信
网络通信最常用的Internet套接字分为三种类型:
数据流套接字、数据报套接字及原始套接字。
数据流套接字定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输;
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错;
原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。
数据报套接字使用UDP来传送数据包,所以数据报的顺序是没有保障的。
数据报是按一种应答的方式进行数据传输的。
下面对数据流通信和数据报通信的方式分别加以说明。
1.数据流通信
数据流套接字是基于TCP的,与网络通信协议相符合,它是面向连接的,能提供一种可靠的服务。
整个面向连接的数据流通信的socket编程过程可用图2-1来表示:
图2-1数据流通信过程
使用socket的数据流进行通信的过程如下:
首先启动服务器,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度,当远程的客户机试图使用connect()连接listen()正在监听的端口时,连接将会在队列中等待,直到调用accept()来处理它。
在accept()处理了连接请求后,将会生成一个新的描述这个连接端口的套接字,利用这个套接字就可以发送和接收数据了。
如果listen()一直没有侦听到连接请求,那么服务器任务就会在accept()处阻塞(在阻塞模式下),一直到有连接请求到来。
对于客户机任务来说,它也需要先用socket()建立一个通信端口,但是它不必用bind()把一个本地地址绑定到这个端口上,而是直接使用connect()向指定的服务器发送连接请求,如果请求被接收,下一步就可以进行数据流通信了。
②.数据报通信
对于数据报通信的服务器端来说,它不必再在一个端口上侦听,以等待建立连接,而只需生成一个端口描述符,并且把这个端口描述符绑定到本地地址上就可以了。
对于客户端也是一样。
这样整个通信过程就简洁的多。
需要说明的是,UDP的客户端可以使用connect(),但是这时使用connect()并不真正产生连接,而只是填写对端套接字的有关信息。
使用connect()的好处是,随后的程序通信中不必每次指定地址,即可以使用recv()、send()等进行通信。
否则,就应该使用recvfrom()、sendto()等实现函数通信,而每次都指定对端地址信息。
数据报通信的通信过程见图5-3所示。
图2-2数据报通信过程
socket编程高级特性
在socket应用编程中,还有许多高级应用特性,如获取服务器和客户机主机信息、进行阻塞处理、设置服务器工作模式、使用原始套接字等,下面对这些特性加以介绍。
1.获取服务器和客户机主机信息
(1)IP地址和域名的转换
在网络上标识一台机器时即可采用IP或者也可采用域名,那么怎样实现两者的转换呢?
可以使用如下函数:
structhostent*gethostbyname(constchar*hostname)
structhostent*gethostbyaddr(constchar*addr,intlen,inttype)
至于返回的数据结构structhostent,在<
/linux/linux-2.4.x/include/netdb.h>
中有它的定义:
structhostent{
charh_name;
/*主机的正式名称*/
charh_aliases;
/*主机的别名*/
inth_addrtype;
/*主机的地址类型AF_INET*/
inth_length;
/*主机的地址长度,对于IP4是4个字节32位*/
char**h_addr_list;
/*主机的IP地址列表*/
}
#defineh_addrh_addr_list[0]/*主机的第一IP地址*/
gthostbyname()可以将机器名(如)转换为一个hostent结构指针,在这个结构里面储存了域名的地址信息。
Gethostbyaddr()可以将一个32位的IP地址(C0A80001)转换为结构指针,在这个结构里面储存了域名的地址信息。
这两个函数调用失败时返回NULL,且设置h_errno错误变量。