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 <sys/types.h># include <sys/socket.h># include <netinet/in.h># include <netdb.h># include <stdio.h>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 <sys/types.h># include <sys/socket.h># include <netinet/in.h># include <netdb.h># include <stdio.h>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 hp486if(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)); //先將服務器地址清0server.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;}elsemyseq++;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的開放性能正逐步完善,可以說已經成為網絡編程的通用接口,有了這個強有力的工具,我們可以構造任意跨操作系統、跨網絡協議的分布式處理系統。