摘 要 该文在介绍Windows Sockets背景知识的基础上,结合在Win
dows环境中建立So ckets的过程,重点介绍了Windows Sockets的特点
,及其基本的结构体和函数;继而结合开发Windows Sockets应用程序
的经验,介绍了Windows Sockets对系统硬软件环境的要求、调试方法
及其在Internet互联联网上的应用。
关键词 Sockets Internet TCP/IPSocket指一个通信端点,用
户的应用程序可以籍助它通过网络与其他Socdets应用程序相互通信
。Windows 系统中的Socket则是该环境中的一个通信端点。
近年来,鉴于PC机上Windows系统的流行,以及Internet互联网在
全球范围内的广泛使用,很多用户需要在Windows环境中开发可通过互
联网进行通信的应用软件。笔者所在课题组在用Wavelet小波方法对
图像进行实时压缩与传输应用程序的开发中曾采用Windows Socdets
进行数据文件与实时图像经由Internet互联网的传输。本文将根据笔
者的实践对有关内容进行介绍。
一、背景知识
众所周知,ISO颁布的OSI开放式网络系统互连标准由7层组成,其
中第1~4层用于保证不同格式数据的传输,而第5~7层则用于保证通
信双方相互间的正确理解。附图给出了Window sSockets的网络层次,
通过与OSI标准对照,可以看出Windows Sockets是处在第4层与第5层
的位置上。
Internet互联网采用TCP/IP(Transmission Control Protocol/I
nternet Protocol)协议。从附图可以看出:Windows Sockets正好在
该协议的上面一层。
由Microsoft公司开发的Windows Socdets API建立了Windows环
境与网络之间的编程界面,它以伯克利大学的BSD Sockets的编程模块
为基础,同时含有BSD式的函数(共30个左右,其函数名只采用小写英文
字母)和专门为Windows视窗系统扩展的函数(近20个,其函数名采用大
、小写英文字母混用)。
Windows Sockets API有适于Windows 3.x和适于Windows NT的两
种版本。两者均含有上述两类函数,并均通过Windows系统中的Messag
e消息予以驱动。两者不同之处在于:前者是1 6位,单进程;而后者是3
2位,可在多线程视窗(Multithreaded Windows)中使用。
根据所传输数据类型的不同,Windows Sockets又可分为Stream S
ockets和Datagram So ckets两种类型。前者对应不按记录定界的数
据字节流,使用TCP对应的Internet互联网地址,双方互相连接,因而它
可保证按正确的顺序,单一和可靠地传输数据;后者对应记录型数据流
,使用UDP对应的Internet互联网地址,双方不需直连,按固定的最大长
度进行传输,它不能保证按顺序传输数据,并可能出现数据的重复,或
者丢失。附图 Windows Sockets与OSI标准网络层次结构
二、建立与运作过程
在实际应用中我们至少要涉及两个应用程序的Socket(一般各自
位于连在Internet互联网上的两台微机上,分别起Server服务器和Cli
ent客户机的作用,本文分别简称为"服务器So cket/和"客户机Socket
")相互交换信息与传输数据,因此需要在服务器与客户机的应用程序
中分别建立Socket,然后建立相互之间的连接和通信。实际上是同一
程序在服务器和客户机双方分别执行。
1.Windows Socdet的初始化
在Windows环境中建立Socket的第一步是初始化应用程序中的Soc
ket,即按给定的Socke t版本,用WSAData结构体变量中各成员的值来
初始化Socket.
WSAData结构体含有包括Socket版本号、系统状态等信息在内的7
个成员,Windows Sock ets的初始化信息就存储在其对应的变量中。
一般可通过调用WSAStartup()函数(含Socket版本号和该结构体变量
地址两个参数)来完成对Socket的初始化。
如上所述,我们必须对服务器Socket和客户机Socket分别进行初
始化。用户在实际编程中常采用的对Socket的初始化方法有两种:对
于就用单一固定在Socket上的程序可采用在打开应用程序窗口后即自
动驱动message消息的方法;对于具有多个应用模块的应用程序最好采
用菜单命令驱动message消息的方法。笔者采用后者。
2.Socket的生成
在应用程序完成对Socdet的初始化后,即可调用Socket()函数(含
有网络地址类型、传输数据类型和网络协议3个参数)生成Socket,该
函数返回所生成Socket的句柄。
在该函数的3个参数中:
(1)网络地址类型可以取AF-INET(Address Family InterNET的缩
写)和AF-UNSPEC(Addr ess Family-UNSPECified的缩写)。
(2)传输数据类型如前所述分别为SOCK-STREAM和SOCK-DGRAM(Dat
aGRAM的缩写),为保证数据可靠的传送,笔者采用的前一种;
(3)缺省的协议就是TCP/IP;对应参量值取0;如果网络地址类型取
AF-UNSPEC,则此处必须指明相应的协议。
3.将服务器地址赋予服务器Socket,然后使之进入Listen等待连
接的监听状态……
在应用程序完成对服务器Socket的初始化和生成Socket后,一般
需要用服务器的地址先对SOCKADDR-IN结构体变量赋值,然后调用bind
()函数将服务器地址赋予服务器Socket(将SO CKADDR-IN结构体变量
值转给SOCKADDR结构体变量),再调用Listen()函数让服务器Socket进
入Listen"等待连接"的监听状态……。
(1)对服务器Socket的SOCKADDR-IN结构体变量赋值
SOCKADDR-IN(SOCKet ADDRess-InterNet的缩写)只适用于Intern
et地址类型,是一种特殊的Socket地址结构体,它含有Internet Socke
t地址类型、IP端口号、IP地址、填补字节( 以保证与SOCKADDR结构
体总长度相同)4个成员,它用于还没有被赋予相应主机地址的Socket
;由于它与下面要介绍的SOCKADDR结构体具有相同的总长度,因此SOCK
ADDR-IN结构体变量的值可通过bind()、connect()或accept()函数直
接转给对应Socket的SOCKADDR结构体变量。
SOCKADDR-IN结构体变量的第一个参量对于Internet互联网可取
定为AF-INET;第二个参量可由SocKet的最终用户通过对话框输入,例
如12;第三个参量对于Server服务器一方可取一待定值INADDR-ANY;第
四个参量无需赋值。
(2)将服务器地址赋予服务器Socket。
调到bind()函数(含服务器Socket句柄、服务器的SOCKADDR结构
体变量及其长度第三个参量)将服务器对应的SOCKADDR-IN结构体变量
值直接转给服务器的SOCKADDR结构体变量,从而将服务器地址赋予其S
ocket.
SOCKADDR结构体是Socket的一般地址结构,它用于存储参与Windo
ws Sockets通信的计算机的IP地址,它含有Socket采用的地址类型和
具体地址两个成员。如上所述,它与SOCKADDR- IN结构体具有相同的
总长度,SOCKADDR-IN结构体变量的地址值可由bind()、connect()或a
c cept()函数直接转给对应Socket和SOCKADDR结构体变量,从而实现
将地址赋予Socket.
(3)服务器Socket进入Listen"等待连接"的监听状态
调用Lister()函数(含服务器Socket句柄和最大监听态值两个参
量),让服务器Socket进入"等待连接"的监听状态:等待来自客户机Soc
ket的connect"要求连接"信号。
(4)服务器Socket在收到客户机Socket发来的connect"要求连接"
信号后,发回accept"接受连接"信号。
处于监听状态的服务器Socket一旦收到客户机Socket发来的conn
ect"要求连接"信号后,立即调用accept()函数(含处于监听态的服务
器Socket句柄、发出conncet"要求连接"信号的客户机的SOCKADDR结
构体变量地址及其长度等3个参量)将客户机对应的SOCKADDR-IN结构
体变量值转给服务器的SOCKADDR结构体变量,该函数返回一个新的Soc
ket句柄,从而在服务器应用程序中产生一个新的被赋予已连客户机地
址的Socket,同时发回accept"接受连接"的信号。
(5)连接实现
一旦客户机Socket收到服务器Socket发来的accept"接受连接"信
号后,连接实现。
4.将服务器地址赋予客户机Socket,然后使之发出connect"要求
连接"信号,在接到服务器Socket的accept"接受连接"的信号后,连接
实现。在应用程序完成对客户机Socket的初始化和生成客户机Socket
后,一般则需要用欲连服务器的地址先对SOCKADDR-IN结构体变量赋值
,然后调用connect()函数将服务器地址赋于客户机Socket(将SOCKADD
R-IN结构体变量转给S OCKADDR结构体变量),之后由客户机Socket向
服务器Socket发出connect"要求连接"信号,在客户机Socket接到由服
务器Socket发回的accept"接受连接"的信号后,即双方实现连接。
(1)对客户机Socket的SOCKADDR-IN结构体变量赋值
SOCKADDR-IN结构体变量的第一个参量对于Internet互联网仍可
取定为AF-INET;第二个参量仍由Socket的最终用户通过对话框输入(
应同于服务器Socket,例如12);第三个参量则先由Socket的最终用户
通过对话框输欲连服务器的名字或地址(显然名字较为方便)然后利用
g ethostbyname()或gethostbyaddr()函然将名字或地址转换为指向h
ostent结构体变量的指针(hostent结构体含有主机名、替换名、地址
类型、地址长度、地址5个成员),再将hostent结构体变量的地址成员
值复制到SOCKADDR-IN结构体变量上;第四个参量仍无需赋值。
(2)将服务器地址赋予客户机Socket,然后使之发出connect"要求
连接"信号
调用connect()函数(含申请连接的客户机Socket句柄、欲连服务
器的SOCKADDR结构体变量地址及其长度等3个参量)将服务器对应的SO
CKADDR-IN结构体变量值转给客户机的SOCKAD DR结构体变量,从而将
服务器地址赋予客户机Socket;之后由客户机Socket向服务器Socket
发出connect"要求连接"信号。
(3)实现连接
一旦客户机Socket收到来自服务器Socket发回的accept"接受连
接"的信号,则表示服务器与客户机双方的Sockets已经通过Internet
互联网实现连接。
5.已连通双方Sockets之间的数据通信
当服务器与客户机双方的Sockets通过Internet网实现连接后,任
一方均可通过互联网向对方发送,也可以接收对方发来的数据。
(1)数据的发送
相互连接的Sockets任一方均可调用send()函数(含发送目标方的
Socket句柄、要传输数据所在缓冲区地址、数据长度、调用标志等4
个参量)向对方发送各种类型的数据,发送成功后返回所发送的字符数
。
(2)数据的接收
相互连接的Sockets双方均应可调用WSASSyncSelect()函数等待
来自网络的FD-READ事件通知,然后驱动message消息接收对方Socket
发来的数据。
(1)调用WSASSyncSelect()函数(含应收到事件通知的Socket句柄
、应收到message自己的窗口句柄、应收到的message消息名、事件通
知类型等4个参量)等待来自网络的FD-READ事件通知,驱动相应的mesa
age消息。
(2)在被驱动的message消息中调用recv()函数(含接收方的Socke
t句柄、放置所接收数据的缓冲区地址、数据长度、调用标志等4个参
量)接收对方Socket传来的数据。
6.Socket的关闭
相互连接的Sockets任一方均可调用WSASSyncSelect()函数(将后
两个参量置0)来中止S ocket等待网络事件通知,再调用无参WSACIean
up()函数关闭Socket.而相互连接的Sockets任一方关闭的Socket时,
均会向对方发出FD-CLOSE事件通知,并驱动message消息通知用户。
三、编程特点
1.message消息驱动
Windows视窗系统采用meassge消息驱动的工作方式,Windows Soc
kets除了采用命令菜单驱动message消息外,还需采用专门用于接收网
络事件通知与驱动message消息的函数WSASSy ncSelect()。
上述Windows Sockets的建立、互连与数据发送过程均可按模块
进行组合,然后分别放在相应的命令菜单驱动的message消息中,而互
连后接收数据的过程则应放在由WSASSyncSelec t()函数驱动的messa
ge消息中。一般在WM-COMMAND所属的菜单驱动的message中至少应含
有IDM-LTSTEN(等待连接)、IDM-CONNECT(要求连接)、IDM-SEND(发送
数据)、IDM-CLOSE(关闭Socket)这几个基本消息;而WSASSyncSelect(
)函数驱动的message中至少应含有WM-READ(接收数据)消息。这些消
息的名字可由用户自己确定。
上述互连过程采用的是Blocking模式,即服务器在调用Listen()
函数后陷入"死等"来自客户机Socket的connect"请求连接"信号的Blo
king状态(此时用户不能激活相应应用程序窗口的命令菜单)。
鉴于WSASSyncSelect()函数可以接收除FD-READ和FD-CLOSE以外
的其它事件通知,如:FD -ACCEPT("要求连接"的事件通知)、FD-CONNE
CT("接受连接"的事件通知)等,因此我们也可以在服务器Socket和客
户机Socket的互连过程中,在服务器一方进入监听状态后,调用该函数
来等待FD-ACCEPT"要求连接"的事件通知,并驱动WM-ACCEPT"接受连接
,准备通信……"的消息; 同样,我们也可以客户机一方在发出connect
"要求连接"信号后,调用此函数来等待FD-CONNE CT"接受连接"的事件
通知,并驱动WM-CONNECTED"连接成功,准备通信……"的消息。
在服务器与客户机的Sockets互连过程中调用WSASSyncSelect()
函数还可以避免服务器在调用Listen()函数后的Bloking状态转为Non
-Blocking状态,而让用户可以在相应窗口中进行其它操作;但它将增
加程序中的message消息数量,不利于独立的模块化DLL动态连接库的
建立。
2.DLL动态连接库文件的建立与应用
考虑到Socket经常是作为Windows视窗应用程序中的一个功能模
块,因此应尽可能将上述Socket的建立与运作过程函数化,并作为主程
序文件的DDL动态连接库予以使用。
在DLL动态连接库文件的生成过程中,首先应正确处理主程序与DL
L、DLL内部各函数之间的参数传递;其次是应将命令菜单、人机对话
框等资源放在主程序中;由函数WSASSyncSelec t()驱动的message消
息不能放到DLL中,而应放到主程序中(但可将该消息的具体内容函数
化,放到DLL中)。
3.多线程视窗(Multithreaded Windows Processes)
在Windows NT视窗系统中可以实现多线程,例如,我们可以在服
务器一方进入监听状态后,通过调用beginthread()函数来生成新的线
程,在此线程中调用指定的自定义函数,而在该函数中调用accept()和
recv()函数分别实现接收来自客户机Socket的connect"要求连接"信
号,发回accept"接受连接"信号,和接收客户机发来的数据。
四、对环境的要求与调试
1.对运行环境的要求
Windows Sockets对运行环境的要求不是很高,一般宜采用Pentiu
m微机、Windows NT视窗系统,此外系统还应装有下列软硬件。
(1)Windows Socket
Windows NT视窗系统已含有Windows Sockets软件系统,无须再进
行安装;对于Windows 3.X版则需要单独进行安装。
(2)网卡
由于TCP/IP可以工作在任何网络上,而Windows Sockets是在TCP/
IP的上层,因此它也可以用在各种不同的网络上,即它对具体采用哪一
种网卡没有特殊的要求,当然在可能的条件下应在同一网络中采用传
输速率较高的网卡。
笔者采用了使用PCI局域总线的CWL9510 PCI Ethernet网卡,其速
率为20/10Mbps.在安装网卡前应从网络管理员处取得分配给该微机的
名字、IP地址、Subnet mask、Gateway、Dom ain Suffix等参数。在
主板上插入网卡后即可启动视窗,依次揿击Main、Control Panel、N
etwork图标打开Network安装窗口,再揿击Add Adapter按钮添入所用
的网卡,再调用随卡带来的安装程序进行安装。安装过程中按屏幕提
示在对话框中正确填入上述参数即可。
(3)HOSTS文件
为了帮助用户记住在Windows Sockets正常工作时所需要的主机
名与IP地址,用户可以在硬盘C的指定目录中装入供TCP/TP使用的文件
名为HOSTS的文本文件。笔者采用了Windows N T(V3.51)系统,该文件
放于C:/WINNT35/SYSTEM32/DRIVERS/ETC子目录中。文件的每一行由
用空格分开的3列栏目组成,依次给出Windows Sockets可能涉及的主
机IP地址、主机名和由符号#引导的注释。
一个典型的例子如下:
127.0.0.1
Localhost#Local host
128.146.155.114 robin.eng.ohio-state.edu#Server host
128.146.155.112 gull.eng.ohio-state.edu#Client host
2.调试
笔者在MS Visual C++V4.0的 MS Developer Studio环境中对Win
dows Sockets DLL及应用主程序进行编辑和Build装配(含编译和联接
)。
在应用程序Sockets的调试与实际应用过程中,均可根据需要在程
序中添加必要的人机交互对话框或信息框,以直观得到Sockets运行过
程中各阶段的结果。
在对DLL进行Build前,应在缺省的库文件基础上增加wsock32.lib
、libcmtd.lib和libc d.lib三个库文件模块;而在对主程序进行Buil
d时,还应增加所生成的相应DLL的*.obj目标文件模块,以及设备相应
模块文件的搜索路径。
在Windows Sockets的调试阶段,可在一台计算机上同时打开两个
Windows Socket应用程序窗口进行试运行,待正常后再在两台不同机
器上进行实验。即使计算机没有入网,也可以采用localhost的名字和
127.0.0.1的IP地址进行应用程序Sockets的单机试调。
五、在Internet网络中的实际应用
虽然目前已有WWW浏览器、FTP等Internet互联网的应用工具,可
以下装网上的信息,或实现网上工作站间的数据与文件传输,但是Wind
ows Sockets则可方便地在用户自己设计的Win dwos视窗应用程序中
通过Internet互联网传输数据,由于互联网的传输速度可以高达数十
兆到数百兆bps,因此除了可以传递一般的文字、图形、声音等数据文
件外,还可以用来传递实时的图像数据。
send()函数可由用户给定所发送数据祯(Frame)的长度,如果数据
祯较长(数KB以上),在实际传输前,Socket要先将数据祯重新分成若干
个数据包(Packets),再分别顺序传输,也就是说只要该祯数据没有接
收完,接收一方Socket将不断驱动WM-READ消息直到接收完该祯数据。
因此,应根据这一特点对所接收的数据进行相应处理。在实时传输时,
还应由接收一方对传输过程控制……。
附:作者简介
裴纯礼,北京师范大学计算中心副主任、副教授,同时兼任国家教
委高教司"全国普通高校文科专业计算机基础教育指导组"副组长、国
家教委师范司"全国高等师范学校计算机教育指导组"委员、北京市教
委大学处"北京地区普通高校计算机基础教育评价与指导委员会"委员
等职,多年从事计算机基础教学工作,已出版有关计算机基础教材、著
作200余万字,正式发表十余篇论文。1996年5月赴美进修,从事计算机
网络通信与Wavelet的研究工作,现为美国俄亥俄州立大学电气工程系
高级访问学者。热点技术