分类: 系统运维
2011-10-19 19:41:02
UNIX网络编程入门
Unix是计算机使用的主流操作系统之一,TCP/IP是广为应用的互连网协议,Unix为TCP/I P网络编程提供了一种网络进程通信机制:套接字接口(Sockets Interface)。本文将介绍Un ix环境下套接字的基本概念及编程技术,并结合实例说明在Unix下如何用套接字实现客户机/服务器方式的进程通信。
一、套接字简介
套接字(Socket)是网络通信的基本操作单元,它提供了不同主机间进程双向通信的端点,这些进程在通信前各自建立一个Socket,并通过对Socket的读/写操作实现网络通信功能。
套接字分为以下3种类型。
1.字节流套接字
这是最常用的套接字类型,TCP/IP协议簇中的TCP(Transport Control Protocol)协议使用此类接口,它提供面向连接的(建立虚电路)、无差错的、发送先后顺序一致的、包长度不限和非重复的网络信包传输。
2.数据报套接字
TCP/IP协议族中的UDP(User Datagram Protocol)协议使用此类接口,它是无连接的服务,以独立的信包进行网络传输,信包最大长度为32KB,传输不保证顺序性、可靠性和无重复性,它通常用于单个报文传输或可靠性不重要的场合。
3.原始数据报套接字
提供对网络下层通讯协议(如IP协议)的直接访问,它一般不是提供给普通用户的,主要用于开发新的协议或用于提取协议较隐蔽的功能。
二、套接字系统调用
附表是Unix中套接字系统调用的简单说明。
附表
三、套接字编程方法
这里将分别介绍面向连接协议的字节流套接字与非连接协议的数据报套接字的编程方法,因原始数据报套接字在实际工作中使用较少,在此不作讨论。
不论何种套接字编程均采用客户机/服务器的协作模式,即由客户进程向服务器进程发出请求,服务器进程执行被请求的任务并将结果返回给客户进程。
字节流套接字的服务进程和客户进程在通信前必须建立连接。建立连接及通信的步骤见图1。
1.服务进程首先调用Socket()创建一个字节流套接字,并调用bind()将服务器地址捆扎在该套接字上,接着调用listen()监听连接请求,随后调用accept()做好与客户进程建立连接的准备,无连接请求时,服务进程被阻塞;
2.客户进程调用Socket()创建字节流套接字,然后调用connect()向服务进程发出连接请求;
3.当连接请求到来后,服务进程被唤醒,生成一个新的字节流套接字,并用新套接字同客户进程的套接字建立连接,而服务进程最早生成的套接字则继续用于监听网络上的服务请求
4.服务进程和客户进程通过调用read()和write()交换数据;
5.服务进程和客户进程通过调用close()撤消套接字并中断连接。
图1 面向连接协议的字节流套接字系统调用
图2 非连接协议的报套接字系统调用
数据套接字的服务进程客户进程通信前不必建立连接, 通信的步骤见图2。
1.服务进程首先调用Socket()创建一个数据套接字,并调用bind()将服务器地址捆扎在该套接字上,然后调用recvfrom()等待客户进程发来的请求;
2.客户进程在调用Socket()创建一个数据报套接字后,调用bind()将客户机地址捆扎在此套接字上,接着调用sendto()向服务进程发送请求,然后调用recvfrom()等待服务进程返回该请求的处理结果;
3.服务进程在执行客户进程所请求的任务后,调用sendto()将处理结果返回给客户进程
4.服务进程和客户进程通过调用close()撤消套接字。
四、套接字编程示例
下面给出一个运用字节流套接字在TCP/IP网络上实现客户机/服务器方式进程通信的实例。
在此例中,服务进程先于客户进程运行,当双方建立连接后,服务进程通过该连接向客户进程不断发送一个连续增长的序列数,客户进程每接收到50个序列数就在屏幕上显示一个‘.',显示至20个点后换行,直至任意一方进程被中断为止。
/******server.c******/
# include
# include
# include
# include
# include
main()
{
int sock,namelen,seq,netint;
struct sockaddr-in server;
//存服务器的internet地址
char msgsock;
char buf[1024];
//创建internet域的TCP协议的字节流套接字
sock=socket(AF-INET,SOCK-STREAM,IPPROTO-TCP);
if(sock<0){
perror("socket");
exit(1);
}
//将本地主机(服务器)的地址捆扎到创建的套接字上
server.sinfamily=AF-INET;
//internet域
sevrer.sinaddr.s-addr=INADDR-ANY; //使用任意合法地址
sevrer.sinport=htons(1032);
//公认的服务端口号
if(bind(sock,&server,sizeof(server))<0){
perror("bind");
exit(2);
}
//建立长度为5的监听队列,从套接字上收听连接请求
if(listen(sock,5)<0){
perror("listen");
exit(3)
}
//阻塞至客户方有连接请求到来,建立一新套接字用于通信
namelen=sizeof(server);
if((msgsock=accept(sock,&server,&namelen))<0){
perror("accept");
exit(4);
}
//此时连接已建立,可以进行通信
seq=0;
for(;;){
netint=htonl(seq);
//主机字节顺序转为网络字节顺序
write(msgsock,&netint,4);
//向客户方写序列数
seq++;
}
}
/******client.c******/
# include
# include
# include
# include
# include
main(argc,argv)
int argc;
char *argv[];
{
int sock,myseq,recvseq;
struct sockaddr-in server;//存服务器的internet地址
struct hostcnt *h;//存主机信息
//命令行必须跟参数:服务器的主机名,该主机
//必须在/etc/hosts文件中定义,例如:
// 192.7.100.31 hp486
if(argc!=2){
printf("Usage:%s servername\n",argv[0];
exit(1);
}
//创建internet域TCP协议的字节流套接字
sock=socket(AF-INET,SOCK-STREAM,IPPROTO-TCP);
if(sock<0){
perror("socket");
exit(2);
}
//根据命令行参数提供的服务器主机名,取得服务器的地址
if(!(h=gethostbyname(argv[1]))){
perror(argv[1];
exit(3);
}
bzero(&server,sizeof(server)); //先将服务器地址清0
server.sinfamily=AF-INET;
//internet域
//将取到的主机地址填入服务器的地址
bcopy(h->h-addr,&server.sinaddr,h->length);
server.sinport=htons(1032); //填入公认的服务端口号与服
务进程建立连接
if(connect(sock,&server,sizeof(server))<0){
perror("connect");
exit(4);
}
//此时,连接已建立,可通过对套接字的读/写实现通信
myseq=0;
while(read(sock,&recvseq,4)==4){//读序列数
recvseq=ntohl(recvseq);
//网络字节顺序转换为主机字节顺序
if(myseq!=recvseq){
printf("sented=%d wanted=%d\n",recvseq,myseq);
myseq=recvseq;
}
else
myseq++;
if(!(recvseq%50))
printf(".");
if(!(recvseq%1000))
printf("\n");
}
}
五、结束语
虽然Sockets最早是作为BSD规范提出来的,并已成为Unix操作系统下TCP/IP网络编程标准,但是,随着网络技术的不断进步,Sockets的应用范围已不再局限于Unix操作系统和TCP/I P网络。目前,Windows、Windows NT、Windows 95、OS/2、Sun OS、Netware等诸多的操作系统都开始提供套接字接口,它们在兼容4.3BSD Unix Sockets的基础上附加了一些适应自身操作系统特性的扩充内容,这些新版的Sockets以操作系统内置或外挂的形式提供给程序员。W insock (Windows Sockets)便是一个用于Windows系列操作系统的Sockets版本。同时,套接字所支持的网络协议种类也不断增加,例如,Winsock不仅支持TCP/UDP协议,而且支持IPX/SP X、AppleTalk、Decnet、NetBEUI等网络协议,Netware的套接字支持TCP/UDP及IPX/SPX协议。另外,套接字还增加了非C语言支持:如C++、BASIC、Pascal等。
由此可见,Sockets的开放性能正逐步完善,可以说已经成为网络编程的通用接口,有了这个强有力的工具,我们可以构造任意跨操作系统、跨网络协议的分布式处理系统。
池中龙 制作/维护