服务器概览

本文详细解析了服务器与客户端的区别,特别是在网络通信中的角色。客户端发起连接,服务器等待连接,服务器通过监听套接字接受连接后创建新的套接字副本用于通信。在连接过程中,服务器使用特定端口号,通过IP地址、客户端端口号和服务器端口号来唯一标识套接字。此外,描述符被用来在应用程序和协议栈之间标识套接字。
摘要由CSDN通过智能技术生成

客户端与服务器的区别

**首先,服务器和客户端有什么区别呢?**根据用途,服务器可以分为很多种类,其硬件和操作系统与客户端是有所不同的。但是,网络相关的部分,如网卡、协议栈、Socket库等功能和客户端却并无二致。无论硬件和OS如何变化,TCP和IP的功能都是一样的,或者说这些功能规格都是统一的。

不过,它们的功能相同,不代表用法也相同。在连接过程中,客户端发起连接操作,而服务器则是等待连接操作,因此在Socket库的用法上还是有一些区别的,即应用程序调用的Socket库的程序组件不同。

此外,服务器的程序可以同时和多台客户端计算机进行通信,这也是一点区别。因此,服务器程序和客户端程序在结构上是不同的。

服务器程序的结构

服务器需要同时和多个客户端通信,但一个程序来处理多个客户端的请求是很难的,因为服务器必须把握每一个客户端的操作状态。因此一般的做法是,每有一个客户端连接进来,就启动一个新的服务器程序,确保服务器程序和客户端是一对一的状态

具体来说,服务器程序的结构如图6.1所示。首先,我们将程序分成两个模块,

等待连接模块(图6.1(a))
负责与客户端通信的模块(图6.1(b))。

当服务器程序启动并读取配置文件完成初始化操作后,就会运行等待连接模块(a)。这个模块会创建套接字,然后进入等待连接的暂停状态。接下来,当客户端连发起连接时,这个模块会恢复运行并接受连接,然后启动客户端通信模块(b),并移交完成连接的套接字。接下来,客户端通信模块(b)就会使用已连接的套接字与客户端进行通信,通信结束后,这个模块就退出了。

在这里插入图片描述
每次有新的客户端发起连接,都会启动一个新的客户端通信模块(b),因此(b)与客户端是一对一的关系。这样,(b)在工作时就不必考虑其他客户端的连接情况,只要关心自己对应的客户端就可以了。通过这样的方式,可以降低程序编写的难度。服务器操作系统具有多任务、多线程功能,可以同时运行多个程序,服务器程序的设计正是利用了这一功能

当然,这种方法在每次客户端发起连接时都需要启动新的程序,这个过程比较耗时,响应时间也会相应增加。因此,还有一种方法是事先启动几个客户端通信模块,当客户端发起连接时,从空闲的模块中挑选一个出来将套接字移交给它来处理

服务器端的套接字和端口号

刚才我们介绍了服务器程序的大体结构,但如果不深入挖掘调用Socket库的具体过程,我们还是无法理解服务器是如何使用套接字来完成通信的。因此,下面就来看一看服务器程序是如何调用Socket库的

首先,我们再来回忆一下客户端与服务器的区别。从数据收发的角度来看,区分“客户端”和“服务器”这两个固定的角色似乎不是一个好办法。现在大多数应用都是由客户端去访问服务器,但其实应用的形态不止这一种。为了能够支持各种形态的应用,最好是在数据收发层面不需要区分客户端和服务器,而是能够以左右对称的方式自由发送数据。TCP也正是在这样的背景下设计出来的。

不过,这其中还是存在一个无法做到左右对称的部分,那就是连接操作。连接这个操作是在有一方等待连接的情况下,另一方才能发起连接,如果双方同时发起连接是不行的,因为在对方没有等待连接的状态下,无法单方面进行连接。因此,只有这个部分必须区分发起连接和等待连接这两个不同的角色。从数据收发的角度来看,这就是客户端与服务器的区别,也就是说,发起连接的一方是客户端,等待连接的一方是服务器

这个区别体现在如何调用Socket库上。首先,客户端的数据收发需要经过下面4个阶段。

1)创建套接字(创建套接字阶段)
(2)用管道连接服务器端的套接字(连接阶段)
(3)收发数据(收发阶段)
(4)断开管道并删除套接字(断开阶段)

相对地,服务器是将阶段(2)改成了等待连接,具体如下。

1)创建套接字(创建套接字阶段)
(2-1)将套接字设置为等待连接状态(等待连接阶段)
(2-2)接受连接(接受连接阶段)
(3)收发数据(收发阶段)
(4)断开管道并删除套接字(断开阶段)

下面我们像前面介绍客户端时一样,用伪代码来表示这个过程,如图6.2所示。我们一边看图,一边介绍一下服务器端的具体工作过程。
在这里插入图片描述
接下来调用bind将端口号写入套接字中(图6.2(2-1))。在客户端发起连接的操作中,需要指定服务器端的端口号,这个端口号也就是在这一步设置的。具体的编号是根据服务器程序的种类,按照规则来确定的,例如Web服务器使用80号端口

设置好端口号之后,协议栈会调用listen向套接字写入等待连接状态这一控制信息(图6.2(2-1))。这样一来,套接字就会开始等待来自客户端的连接网络包。

然后,协议栈会调用accept来接受连接(图6.2(2-2))。由于等待连接的模块在服务器程序启动时就已经在运行了,所以在刚启动时,应该还没有客户端的连接包到达。可是,包都没来就调用accept接受连接,可能大家会感到有点奇怪,不过没关系,因为如果包没有到达,就会转为等待包到达的状态,并在包到达的时候继续执行接受连接操作。因此,在执行accept的时候,一般来说服务器端都是处于等待包到达的状态,这时应用程序会暂停运行。在这个状态下,一旦客户端的包到达,就会返回响应包并开始接受连接操作。接下来,协议栈会给等待连接的套接字复制一个副本,然后将连接对象等控制信息写入新的套接字中(图6.3)。刚才我们介绍了调用accept时的工作过程,到这里,我们就创建了一个新的套接字,并和客户端套接字连接在一起了。
在这里插入图片描述

当accept结束之后,等待连接的过程也就结束了,这时等待连接模块会启动客户端通信模块,然后将连接好的新套接字转交给客户端通信模块,由这个模块来负责执行与客户端之间的通信操作。之后的数据收发操作和刚才说的一样,与客户端的工作过程是相同的。

其实在这一系列操作中,还有一部分没有讲到,那就是在复制出一个新的套接字之后,原来那个处于等待连接状态的套接字会怎么样呢?其实它还会以等待连接的状态继续存在,当再次调用accept,客户端连接包到达时,它又可以再次执行接受连接操作。接受新的连接之后,和刚才一样,协议栈会为这个等待连接的套接字复制一个新的副本,然后让客户端连接到这个新的副本套接字上。像这样每次为新的连接创建新的套接字就是这一步操作的一个关键点。如果不创建新副本,而是直接让客户端连接到等待连接的套接字上,那么就没有套接字在等待连接了,这时如果有其他客户端发起连接就会遇到问题。为了避免出现这样的情况,协议栈采用了这种创建套接字的新副本,并让客户端连接到这个新副本上的方法。

此外,创建新套接字时端口号也是一个关键点。端口号是用来识别套接字的,因此我们以前说不同的套接字应该对应不同的端口号,但如果这样做,这里就会出现问题。因为在接受连接的时候,新创建的套接字副本就必须和原来的等待连接的套接字具有不同的端口号才行。这样一来,比如客户端本来想要连接80端口上的套接字,结果从另一个端口号返回了包,这样一来客户端就无法判断这个包到底是要连接的那个对象返回的,还是其他程序返回的。因此,新创建的套接字副本必须和原来的等待连接的套接字具有相同的端口号。

但是这样一来又会引发另一个问题。端口号是用来识别套接字的,如果一个端口号对应多个套接字,就无法通过端口号来定位到某一个套接字了。当客户端的包到达时,如果协议栈只看TCP头部中的接收方端口号,是无法判断这个包到底应该交给哪个套接字的。

这个问题可以用下面的方法来解决,即要确定某个套接字时,不仅使用服务器端套接字对应的端口号,还同时使用客户端的端口号再加上IP地址,总共使用下面4种信息来进行判断(图6.4)。

· 客户端IP地址
· 客户端端口号

在这里插入图片描述

· 服务器IP地址
· 服务器端口号

服务器上可能存在多个端口号相同的套接字,但客户端的套接字都是对应不同端口号的,因此我们可以通过客户端的端口号来确定服务器上的某个套接字。不过,使用不同端口号的规则仅限一台客户端的内部,当有多个客户端进行连接时,它们之间的端口号是可以重复的。因此,我们还必须加上客户端的IP地址才能进行判断。例如,IP地址为198.18.203.154的客户端的1025端口,就和IP地址为198.18.142.86的客户端的1025端口对应不同的套接字。如果能够理解上面这些内容,那么关于套接字和端口号的知识就已经掌握得差不多了。

说句题外话,既然通过客户端IP地址、客户端端口号、服务器IP地址、服务器端口号这4种信息可以确定某个套接字,那么要指代某个套接字时用这4种信息就好了,为什么还要使用描述符呢?这个问题很好,不过我们无法用上面4种信息来代替描述符。原因是,在套接字刚刚创建好,还没有建立连接的状态下,这4种信息是不全的。此外,为了指代一个套接字,使用一种信息(描述符)比使用4种信息要简单。出于上面两个原因,应用程序和协议栈之间是使用描述符来指代套接字的。
使用描述符来指代套接字的原因如下。
(1)等待连接的套接字中没有客户端IP地址和端口号
(2)使用描述符这一种信息比较简单

问题

- 什么是描述符?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值