Visual C++ 2017网络编程实战
上QQ阅读APP看书,第一时间看更新

4.1 套接字基本概念

Socket的中文称呼叫套接字或套接口,是TCP/IP网络编程中的基本操作单元,可以看作是不同主机的进程之间相互通信的端点。套接字是应用层与TCP/IP协议簇通信的中间软件抽象层,一组接口,它把复杂的TCP/IP协议簇隐藏在套接字接口后面。某个主机上的某个进程通过该进程中定义的套接字可以与其他主机上同样定义了套接字的进程建立通信,传输数据。

Socket起源于UNIX。在UNIX一切皆文件的哲学思想下,Socket是一种“打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向自己的文件写入内容供对方读取或者读取对方内容,通信结束时关闭文件。当然,这只是一个大体路线,实际编程还有不少细节需要考虑。

无论在Windows平台还是Linux平台,都对套接字实现了自己的一套编程接口。Windows下的Socket实现叫Windows Socket。Linux下的实现有两套:一套是伯克利套接口(Berkeley sockets),起源于Berkeley UNIX,这套接口简单,得到了广泛应用,已经成为Linux网络编程事实上的标准;另一套实现是传输层接口(TLI ,Transport Layer Interface),是System V系统上的网络编程API,所以这套编程接口更多的是在UNIX上使用。

这里简单地说一下SystemV和BSD(Berkeley Software Distribution)。SystemV的鼻祖正是1969年AT&T开发的UNIX,随着1993年Novell收购AT&T后开放了UNIX的商标,SystemV的风格也逐渐成为UNIX厂商的标准。BSD的鼻祖是加州大学伯克利分校在1975年开发的BSDUnix,后被开源组织发展为现在众多的*BSD操作系统。这里需要说明的是:Linux不能称为“标准的UNIX”而只被称为“UNIX Like”的原因有一部分就是来自它的操作风格介乎两者之间(SystemV和BSD),而且不同的厂商为了照顾不同的用户,各Linux发行版本的操作风格之间也有不小的出入。本书讲述的Linux网络编程,都是基于Berkeley Sockets API。

Socket是在应用层和传输层之间的一个抽象层,把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中的通信。它在TCP/IP中的地位如图4-1所示。

图4-1

由图4-1可以看出,Socket编程接口其实就是用户进程(应用层)和传输层之间的编程接口。

4.1.1 网络程序的架构

网络程序通常有两种架构:

·一种是B/S架构(Browser/Server,浏览器/服务器),比如我们使用火狐浏览器浏览Web网站,火狐浏览器就是一个Browser,网站上运行的Web服务器就是一个服务器。这种架构的优点是用户只需要在自己电脑上安装一个网页浏览器就可以了,主要工作逻辑都在服务器上完成,减轻了用户端的升级和维护的工作量。

·另外一种架构是C/S架构(Client/Server,客户机/服务器),这种架构要在服务器端和客户机端分别安装不同的软件,并且针对不同的应用,客户机端也要安装不同的客户机软件,有时候客户机端的软件安装或升级还比较复杂,因此维护起来成本较大。此种架构的优点是可以较充分地利用两端的硬件能力,较为合理地分配任务。值得注意的是,客户机和服务器实际是指两个不同的进程,服务器是提供服务的进程,客户机是请求服务和接受服务的进程,它们通常位于不同的主机上(也可以是同一主机上的两个进程),这些主机有网络连接,服务器端提供服务并对来自客户端进程的请求做出响应。比如我们常用的QQ,我们自己电脑上的QQ程序就是一个客户端,而在腾讯公司内部还有服务器端程序。

在基于套接字的网络编程中,通常使用C/S架构。一个简单的客户机和服务器之间的通信过程如下:

(1)客户机向服务器提出一个请求。

(2)服务器收到客户机的请求,进行分析处理。

(3)服务器将处理的结果返回给客户机。

通常,一个服务器可以向多个客户机提供服务。因此,对服务器来说,还需要考虑如何有效地处理多个客户的请求。

4.1.2 套接字的类型

在Windows系统下有以下3种类型的套接字:

(1)流套接字(SOCK_STREAM)

流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP协议。

(2)数据报套接字(SOCK_DGRAM)

数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,因此对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

(3)原始套接字(SOCK_RAW)

原始套接字允许对较低层次的协议直接访问,比如 IP、 ICMP协议。它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Linux下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术经常会用到原始套接字。

原始套接字与标准套接字(标准套接字包括流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据报,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。