什么是TCP/IP------本课程的主要部分
TCP/IP如何工作-----TCP/IP软件结构与实现
如何用TCP/IP-------TCP/IP应用程序编程接口
前面说过,TCP/IP标准并不指定应用程序与TCP/IP协议软件的接口,但并不是说没有提供任何指导,首先,它指定了一些必须具有的操作。这包括:
–为通信指定本地资源
–指定本地和远程通信端点
–初始化连接(客户端)
–等待连接(服务器端)
–发送和接收数据
–生成紧急数据
–中断通信
–……
–在通信结束时释放本地资源
同时,TCP/IP标准还指定了一个概念层接口,它是作为一个阐述如何使用TCP/IP的例子,它包含了一系列过程和函数,标准建议了每个过程和函数所需要的参数及其所执行操作的语义,但没有进一步指定数据表示的细节。
仔细的接口通常由操作系统来定义,只要完成TCP/IP标准中的功能,可以有不同的细节选择。这样不同的操作系统的应用程序编程接口是各不同的。
–BerkeleySoftwareDistributionUNIX的Socket接口是广泛使用的
–Windows的接口定义Winsock接口
–SystemV的接口定义TLI接口
–……
操作系统提供的应用程序编程接口又分为两类:
–直接由操作系统内核提供的系统调用
BSDUNIX socket
–在操作系统外以库函数的方式提供的各种可调用函数
Windowssocket
一、系统调用
–当应用程序要进行系统调用,首先是把控制交到系统调用接口,接口再把控制转到操作系统,由操作系统调用相应的内部进程来执行请求的操作,内部进程完成后,操作系统再通过调用接口把控制权返回应用程序
在TCP/IP协议加入操作系统后,操作系统可以有两种方式来帮助应用程序访问内核的TCP/IP协议
–用一种新的系统调用
–用通常的I/O调用来访问TCP/IP
完全用第一种方案较少,因为这样要把所有的概念操作都重新设计
采用第二种方案:通过重载通常的I/O调用使得访问协议与通常的I/O一样。
较多采用混合方法:易重载的重载,不易重载的用新函数。
UNIX的基本的I/O函数(一般设备或文件的I/O操作)
–open:为I/O操作准备设备或文件
–close:终止使用前面打开的设备和文件
–read:从输入设备或文件获取数据
–write:向输出设备或文件传输数据
–lseek:移到设备或文件指定的位置
–ioctl:控制设备或访问它的软件
一旦打开某个设备或文件,就给它分配一个描述号,
–intdesc;
–desc=open(“filename”,O_RDWR,0)
在后面,应用程序将使用desc来对该文件进行标识并进行读写操作
–read(desc,buffer,)
完成相关操作后,关闭
–close(desc)
–在BSDUNIX中,使用重载上述的I/O调用来实现对协议的部分访问。同时又一些功能不能重载,需要设计一些新的函数
BSDUNIXSocket使用混合模式
BSDUNIXSocket在设计时还考虑到支持多种通信协议,因此,协议族名称往往是一些函数的参数。TCP/IP是一个单一的协议族
BSDUNIXSocket要求必须使用服务类型来指定操作而不是指定某个协。
以下为几个在完成socket进程通信机制中需要的系统调用(以下以BSDUNIX为例)
sockid=socket(family,type,protocol)//创建socket
–其中:family:地址族,即协议族
–Type:协议服务类型
–Protocol:具体协议
–sockid:UNIX用于标识该socket的整数,
bind(sockid,localaddr,addrlen)
//将本地socket地址(本地地址,本地端口)与所创建的scoket号联系起来,
–其中localaddr:指向socket地址结构的指针,TCP/IP的socket地址结构:
structsockadd_in{
u_shortsin_family;//指明协议族
u-shortsin_port;//端口号
structin_addrsin_addr;//IP地址
charsin_zero[8];//未用
}
–addrlen:地址结构的长度(以字节为单位)
connect(sockid,destaddr,paddrlen)
//用于建立socket连接
–sockid:欲建立连接的本地socket号
–destaddr:指向对方socket地址结构的指针
–paddrlen:对方socket地址长度
listen(sockid,quelen)
//服务器用于确认它愿意建立客户请求的连接
–sockid:本地socket号,服务器将从它上面接收客户请求
–quelen:请求队列的长度,
newsock=accept(sockid,clientaddr,paddrlen)
//用于面向连接的服务器建立socket连接
–sockid:欲建立连接的本地socket号
–clientaddr:指向客户socket地址结构的指针
–paddrlen:客户socket地址长度
–newsock:一个新的socket号
发送数据的系统调用(write)
–面向连接
write(sockid,buff,bufflen)//缓冲发送
writev(sockid,iovector,vectorlen)//集中发送
send(sockid,buff,bufflen,flags)//可控缓冲发送
–面向无连接
sendto(sockid,buff,bufflen,flags,dstadd,addrlen)//可控缓冲发送
sendmsg(sockid,message,flags)//可控缓冲发送
接收数据的系统调用(read)
–与发送的调用是一一对应的,有些参数所不同
其它与socket有关的系统调用
此外socket调用中还有一些给程序员用的实用函数,例如整数转换函数等等以实现不同体系结构的兼容性。因为BSDUNIXsocket调用是支持多协议族的。(这也是socket函数复杂、受到批评的一个原因)
调用的时序关系:
利用socket实现并发服务器的例子:
intinitsockid,newsockid;
if((initsockid=socket(…))0)
error(“cantcreatscoket”);
if(bind(initsockid,localaddr,addrlen)0
error(“binderror”);
if(listen(initsockid,5)0)
error(“listenerror”);
for(;;){
newsockid=accept(initsockid,…)
if(newsockit0)
error(“accepterror”);
if(fork()==0){
close(initsockid);
do(newsockid);
exit(o);
}
close(newsockid);
}
除了完成socket的系统功能调用,BSDUNIX还提供了一套预定义的符号常量和数据结构声明,应用程序可以用它们来声明数据、指定变量。例如:符号常量SOCK_DGRAM和SOCK_STREAM分别说明采用树举报服务还是流服务
这些声明定义在两个头文件中:
–#includesys/types.h
#includesys/socket.h
二、在操作系统外以库函数的方式提供可调用函数
WinsockAPI函数
–WSAStartup:初始化scoket库
–WSACleanup:终止使用scoket库
–scoket:创建
–connect:
–closesocket:
–bind
–listen
–accept
–……
其它