一、 套接字简介
Windows Sockets规范定义并记录了如何使用API与Internet协议族(IPS,通常是指TCP/IP)连接,尤其要指出的是,所有的Windows Sockets实现都支持流套接接口和数据报套接接口,应用程序调用Windows Sockets的API实现相互之间的通信。Windows Sockets又利用下层的网络通信协议功能和操作系统调用实现实际的通信工作。它们之间的关系如下图所示。
套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。套接字存在于通信域中,Windows Sockets只支持一个通信域:网际域(AF-INET),这个域被使用网际协议族通信的进程所使用。 套接字有两种不同的类型:流套接字和数据报套接字。
TCP/IP的Socket则提供3种类型的套接字。
1.流式套接字(SOCK_STREAM)
提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传输协议(FTP)即使用流式套接字。
2.数据报式套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立包形式发送,不提供无差错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。
3.原始套接字(SOCK_RAW)
该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。
二、 套接字编程原理
1.C/S编程模式
服务器端程序执行步骤如下。
(1)打开一个通信通道并告知本地主机,它愿意在某一地址和端口上接收客户请求。
(2)等待客户请求到达该端口。
(3)接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,激活一个新的进程(或线程)来处理这个客户请求。新进程(或线程)处理此客户请求,并不需要对其他请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4)返回第二步,等待另一客户请求。
(5)关闭服务器。
与服务器端相对应,客户机执行的计算通常被称为前端处理。客户机端软件一般由网络接口软件、支持用户需求的应用程序以及实现某些网络功能的实用程序(如电子邮件等)组成。应用程序软件执行具体的任务,如字处理,电子表格和数据库查询等。实用程序软件通常执行几乎所有网络用户都要求的标准任务。网络接口软件提供各种数据传输服务,其执行步骤如下。
(1)打开一个通信通道,并连接到服务器所在主机的特定端口。
(2)向服务器发服务请求报文,等待并接收应答;继续提出请求。
(3)请求结束后关闭通信通道并终止。
2.Socket编程的通信方式
在利用Socket进行编程时要先了解以下几个概念,同步(Synchronous)、异步(Asynchronous)、阻塞(Block)和非阻塞(Unblock)。其中,同步、异步是属于通信模式的概念,而阻塞、非阻塞则属于套接字模式的概念。
(1)同步方式
通信的同步,指客户端在发送请求后,必须在服务端有回应后才能发送下一个请求。所以这个时候的所有请求将会在服务端得到同步。
(2)异步方式
通信的异步,指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求,这样对于所有的请求动作来说将会在服务端得到异步,这条请求的链路就像是一个请求队列,所有的动作在这里不会得到同步。
(3)阻塞方式
阻塞套接字是指执行此套接字的网络调用时,所调用的函数只有在得到结果之后才会返回,在调用结果返回之前,当前线程会被挂起,即此套接字一直阻塞在网络调用上。(4)非阻塞方式
非阻塞套接字是指在执行此套接字的网络调用时,即使不能立刻得到结果,该函数也不会阻塞当前线程,而会立刻返回。
3.套接字工作原理
套接字可以像Stream流一样被视为一个数据通道,这个通道架设在客户端应用程序和服务器端程序之间,数据的读取(接收)和写入(发送)均针对这个通道来进行。因此要通过网络进行通信,就至少需要一对套接字,其中一个运行于客户端,称之为客户端套接字(ClientSocket),另一个运行于服务器端,称之为服务器端套接字(ServerSocket)。当创建了这两个套接字对象之后,将这两个套接字连接起来就可以实现数据传送了。
根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
(1)服务器监听
服务器监听时服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求
客户端请求是指由客户端的套接字发出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后再向服务器端套接字提出连接请求。
(3)连接确认
连接确认是指当服务器端套接字监听到(或接收到)客户端套接字的连接请求时,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。 在TCP/IP网络中,IP网络交互分为两大类:面向连接的交互和无连接的交互。下面给出这两种交互的套接字编程流程。 三、 .NET中的Socket类
1.Socket类的构造函数
Socket类的构造函数原型如下:
public Socket(
AddressFamily addressFamily,
SocketType socketType,
ProtocolType protocolType
);
构造函数使用3个参数来定义创建的Socket实例。AddressFamily用来指定网络类型;SocketType用来指定套接字类型(即数据连接方式);ProtocolType用来指定网络协议。3个参数均是在命名空间System.Net.Sockets中定义的枚举类型。但它们并不能任意组合,不当的组合反而会导致无效套接字。IP套接字定义组合
SocketType值
|
ProtocolType值
|
描 述
|
Stream
|
Tcp
|
面向连接套接字
|
Dgram
|
Udp
|
无连接套接字
|
Raw
|
Icmp
|
网际消息控制协议套接字
|
Raw
|
Raw
|
基础传输协议套接字
|
Socket类的公共属性
属 性 名
|
描 述
|
AddressFamily
|
获取Socket的地址族
|
Available
|
获取已经从网络接收且可供读取的数据量
|
Blocking
|
获取或设置一个值,该值指示Socket是否处于阻塞模式
|
Connected
|
获取一个值,该值指示Socket是否已连接到远程主机
|
Handle
|
获取Socket的操作系统句柄
|
LocalEndPoint
|
获取本地终结点EndPoint
|
RemoteEndPoint
|
获取远程终结点EndPoint
|
ProtocolType
|
获取Socket的协议类型
|
SocketType
|
获取Socket的类型
|
2.Socket类的常用方法
(1)Bind(EndPoint address)
在服务器端,当一个套接字被创建后,需要将它绑定到系统的一个特定地址。可以使用Bind( )方法来完成,其参数为一个IPEndPoint实例(包含IP地址和端口信息)。
(2)Listen(int con_num)
服务器端的套接字完成了与地址的绑定后,就使用Listen( )方法监听客户发送的连接请求。其参数con_num为一整型值,该值表示服务器可以接受的最大连接数目。超过这个数目的连接都会被拒绝。con_num数值的设定会影响到服务器的运行,因为每个接受的连接都要使用TCP缓冲区,如果连接的数目过大,收发数据的缓存将减少。
(3)Accept( )
在服务器进入监听状态时,如有从客户端发来的连接请求,服务器将使用Accept( )方法来接受连接请求。Accept( )返回一个新的套接字,该套接字包含所建立的连接的信息并负责处理本连接的所有通信。而服务器刚开始创建的套接字仍然负责监听,并在需要时调用Accept( )接受新的连接请求。
(4)Send( )
当服务器接受了来自客户端的连接请求后,服务器和客户端双方就可以利用Send( )方法来发送数据。
(5)Receive( )
当服务器接受了来自客户端的连接请求后,服务器和客户端双方就可以利用Receive( )方法来接受数据。Receive( )有四种重载方法如表5.11所示。
(6)Connect(EndPoint remoteEP)
同服务器端一样,客户端的套接字建立后也必须与一个地址绑定。在客户端使用Connect( )方法实现绑定,remoteEP参数为所要连接的服务器端的IPEndPoint实例。调用Connect( )方法后,它将一直阻塞到连接建立,如果连接不成功,将返回一个异常。
(7)Shutdown(SocketShutdown how)
当客户端和服务器端的通信结束时,必须关闭相应的套接字实例。可以使用Shutdown( )方法来禁止该套接字上的发送和接收,Shutdown( )方法有一个枚举类型的参数,如SocketShutdown.Send表示禁用发送套接字,SocketShutdown.Receive表示禁用接收套接字,SocketShutdown.Both表示禁用发送和接收的套接字。图5.9 获取套接字属性运行结果
(8)Close( )
禁止套接字上的发送和接收之后,使用Close( )方法关闭套接字连接并释放所有相关资源。这样套接字会在系统内部缓冲区处理完毕后关闭套接字并释放资源。