第18章 网络编程基础.pdf

上传人:qwe****56 文档编号:70021079 上传时间:2023-01-14 格式:PDF 页数:21 大小:455.16KB
返回 下载 相关 举报
第18章 网络编程基础.pdf_第1页
第1页 / 共21页
第18章 网络编程基础.pdf_第2页
第2页 / 共21页
点击查看更多>>
资源描述

《第18章 网络编程基础.pdf》由会员分享,可在线阅读,更多相关《第18章 网络编程基础.pdf(21页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、 第 18 章 网络编程基础 237第 18 章 网络编程基础 计算机网络是通过通信线路互相连接的计算机的集合,它是由计算机及外围设备、数据通信和中断设备等构成的一个群体。TCP/IP 协议是 Internet 上使用的协议,而 Internet是世界上最大的计算机网络。国际标准化组织 ISO 对网络标准提出了 OSI 参考模型,该模型进一步规范了计算机网络的设计并解决了 TCP/IP 协议没有涉及的底层实现问题。Linux系统的一个主要特点是它的网络功能非常强大。随着网络的日益普及,基于网络的应用也将越来越多。本章将讲解计算机网络的基本概念,以及基础的网络编程方法。18.1 计算机网络组成

2、在学习网络编程前,首先需要了解的是计算机网络的组成,只有这样才能知道如何设计程序在其间进行通信,以及网络编程所面对的问题。物理层面上,计算机网络由计算机设备、网络连接设备、传输介质这 3 个部分组成;逻辑层面上,计算机网络由网络协议、网络应用软件、数据这 3 个部分组成。计算机网络根据其组成的形式又可分为多种结构,有的结构适用于某种环境,但更多情况是将多种网络结构复合使用组成实际的网络。为了规范不同的计算机和计算机网络进行通信,通常用网络模型来描述需要解决问题的层次,并以网络模型为基础编制出了多种网络传输协议。18.1.1 网络结构 大多数的计算机网络是局域网,整个网络位于一幢建筑物或一个房间

3、内。局域网用于在多台计算机之间共享资源。例如,连接两台计算机和一台打印机的局域网允许任何一台计算机访问打印机,如图 18.1 所示。图 18.1 简单的局域网 第 4 篇 Linux 网络编程与数据库编程 238根据局域网的组成形式,可以将局域网分为星型网络、环状网络和总线网络 3 种基本网络结构。计算机都连在一个中心站点上,那么该网络即是星型网络。星型网络像车轮的轮辐,所以星型网络的中心通常被称为集线器或交换机。典型的集线器或交换机包括了这样一种电子装置,它从发送计算机接收数据并把数据传输到合适的目的地,如图 18.2 所示。图 18.2 星型网络 环状网络将计算机连接成一个封闭的圆环,一根

4、电缆连接第一台计算机与第二台计算机,另一根电缆连接第二台计算机与第三台,依次类推,直到一根电缆连接最后一台计算机与第一台计算机,如图 18.3 所示。图 18.3 环状网络 总线网络通常有一根连接计算机的长电缆,任何连接在总线上的计算机都能通过总线发送信号,并且所有计算机也都能接收信号。由于所有连接在电缆上的计算机都能检测到电子信号,因此任何计算机都能向其他计算机发送数据,如图 18.4 所示。第 18 章 网络编程基础 239 图 18.4 总线网络 每种网络结构都有优点与缺点。环状网络使计算机容易协调使用以及容易检测网络是否正确运行。然而,如果其中两根电缆断掉,整个环状网络都要失效。星型网

5、络能保护网络不受某一根电缆损坏的影响,因为每根电缆只连接一台机器。总线网络所需的布线比星型网络少,但是有和环状网络一样的缺点。所以,对于某一个小的区间来说,网络的实现可能是以上任何一种,但对于大型网络来说,通常是由这 3 种网络组成的复合结构。18.1.2 OSI 参考模型 国际标准化组织开发了开放式系统互联参考模型,以促进计算机系统的开放互联。开放式互联特点是支持不同系统环境互联。该模型为计算机间开放式通信所需要定义的功能层次建立了全球标准。该模型的层次依次为:?物理层:物理层并非是指网络硬件或传输媒介,它只存在与抽象结构中,是负责数据流传输的最底层功能模块。物理层从第二层数据链路层(DDL

6、)接收数据帧,然后以串行方式发送数据帧,每次只发送一个字节。另外,它也负责接收数据流,然后组合成数据帧传送给数据链路层。?数据链路层:数据链路层的作用是将数据流打包成数据帧,然后将数据帧交给物理层进行传递。也从物理层接收数据帧,并通过循环校验来检测数据传输的可靠性。?网络层:网络层用于设备间建立路由,处理数据帧中的地址信息。但是,网络层不检验数据的完整性,而是交由数据链路层完成。?传输层:传输层是以数据包和网段为对象的数据处理层,它是高度抽象化的数据链路层服务。传输层对数据的完整性负责,如果某一数据包丢失,它将要求对方重新发送该数据包。?会话层:会话层用于建立两个网络终端间的联系,与传输层关系

7、极为密切,用于决定通信的模式是单工还是双工,以及基本的握手协议。?表示层:表示层用于处理不同计算机的数据编码方式,负责对数据编码进行转换。不同计算机的数据编码系统可能有差别,例如 IBM 和 APPLE 系统之间的差别。?应用层:应用层不包括任何应用,只是为 OSI 参考模型提供接口。通常,网络协议被应用程序调用的是应用层。第 4 篇 Linux 网络编程与数据库编程 240为了更清晰地展现 OSI 参考模型每一层的功能,以及两个网络终端以 OSI 参考模型进行通信的原理,可以用垂直方向图表示该模型,如图 18.5 所示。OSI 参考模型在两个网络终端中层层对应,因此每一层都具备输入和输出的功

8、能。18.1.3 TCP/IP 参考模型 OSI 参考模型并非实际应用中的标准,而只是一种抽象化表示方法。目前真正被广泛使用的是 TCP/IP 参考模型,它是以 OSI 参考模型作为基础设计的。Internet 的高速发展使TCP/IP 参考模型被所有计算机所使用。TCP/IP 协议是一个协议集,其核心为 TCP 协议与 IP 协议。TCP/IP 参考模型也是一个开放模型,能适用互联网等各种网络的需要,它具有如下 4 个特点。图 18.5 OSI 模型垂直方向的结构层次?TCP/IP 是一种标准化的高级协议,同时提供了多种网络服务协议。?完善的网络地址分配方法,网络中每个点都具备独立的地址。?

9、非专利技术,与操作系统及硬件结构无关。?与网络硬件无关,适合于各种网络结构。TCP/IP 参考模型有 4 个层次。其中应用层与 OSI 中的应用层对应,传输层与 OSI 中的传输层对应,网络层与 OSI 中的网络层对应,物理链路层与 OSI 中的物理层和数据链路层对应。TCP/IP 中没有 OSI 中的表示层和会话层,如图 18.6 所示。4 个层次分别是:第 18 章 网络编程基础 241 图 18.6 TCP/IP 模型与 OSI 模型比较 1应用层 应用层是 TCP/IP 参考模型的最高层,它向用户提供一些常用应用程序,如电子邮件等。应用层包括了所有的高层协议,并且总是不断有新的协议加入

10、。应用层协议主要有:网络终端协议 TELNET,用于实现互联网中的远程登录功能;文件传输协议 FTP,用于实现互联网中交互式文件传输功能;简单电子邮件协议 SMTP,实现互联网中电子邮件发送功能;域名服务 DNS,用于实现网络设备名字到 IP 地址映射的网络服务;网络文件系统NFS,用于网络中不同主机间的文件系统共享。2传输层 传输层也称为 TCP 层,主要功能是负责应用进程之间的端端通信。传输层定义了两种协议:传输控制协议 TCP 与用户数据包协议 UDP。TCP 协议是一种可靠的面向连接的协议,主要功能是保证信息无差错地传输到目的主机。UDP 协议是一种不可靠的无连接协议,它与 TCP 协

11、议不同的是它不进行分组顺序的检查和差错控制,而是把这些工作交给上一级应用层完成。3网络层 网络层又称为 IP 层,负责处理互联网中计算机之间的通信,向传输层提供统一的数据包。它的主要功能有以下 3 个方面:处理来自传输层的分组发送请求;处理接收的数据包;处理互联的路径。4物理链路层 物理链路层主要功能是接收 IP 层的 IP 数据包,通过网络向外发送,或接收处理从网络上来的物理帧,抽出 IP 数据包,向 IP 层发送。该层是主机与网络的实际连接层。第 4 篇 Linux 网络编程与数据库编程 24218.2 TCP/IP 协议 TCP/IP 协议(Transmission Control Pr

12、otocol/Internet Protocol)是随着 Internet 而发展的网络协议,目前应用最为广泛。Internet 最初是因为美国国防需要而建立的,用于保证美国政府的计算机网络间能够互通,并保证遭受核打击时不至于瘫痪。TCP/IP 很好地解决了不同网络互访问性和网路的健全性,领导着 Internet 发展。几乎所有的操作系统都支持 TCP/IP协议,Linux 系统更是将 TCP/IP 协议作为重要标准,成为了世界上最流行的网络服务器操作系统。18.2.1 IP 协议与 Internet 计算机网络技术在近 50 年的发展路程中,产生过多种不同的网络结构和通信协议,很多至今还在使

13、用。让不同网络可相互访问的结局方案有两种:第一种是选择一种组网络结构为标准,使所有网络都按照同一方法来组建。这种方案显然没有可行性,因为不但网络重建的费用太高,而且没有一种网络结构能满足所有应用。因此,第二种方法被提出,该方法要求设计一种协议,能够让所有网络结构都能支持。TCP/IP 协议由此诞生,解决网络互通问题的是 IP 协议。IP 协议又称为网际协议,对应于 TCP/IP 参考模型的网络层,是 Internet 中最重要的协议。IP 协议规定数据包由数据包正文与报头两部分组成。数据包正文是要传递的数据,没有格式要求。报头包括发送主机的网络地址、接收主机的网络地址、数据包的报头校验和、数据

14、包的长度等信息。IP 协议的主要功能有数据包传输、数据包路由选择和拥塞控制。数据包采用“无连接”方式传递,即两台主机在通信之前不需要建立连接。网络主机间使用统一的 IP 数据包,这样能保持不同物理网络间能够传递和识别数据。如果目的地为同一网段的计算机,那么数据包将被直接传输过去。如果两台主机处于 Internet 上的不同子网中,IP 协议将通过路由器获得主机间的传输路径,通过交换机或服务器接力的方式,将数据包传递过去。路由器是网络中选择路径的专用计算机,它以图算法为核心,负责找到两点之间最短的距离。同时也会考虑网络的拥堵状况,找到实际最快的传输路径。一些比较大的数据被拆分为数据包后,很可能是

15、以不同的路径传递到目的地。18.2.2 IP 互联网协议地址 所有 Internet 上的计算机都必须有一个Internet上唯一的编号作为其在Internet的标识,这个编号称为 IP 地址。每个数据包中包含有发送方的 IP 地址和接收方的 IP 地址。IP 地址是一个 32 位二进制数,即 4 个字节,为方便起见,通常将其表示为 w.x.y.z 的形式。其中,w、x、y、z 分别为一个 0 至 255 的十进制整数,对应二进制表示法中的一个字节。这样的第 18 章 网络编程基础 243表示叫做点分十进制表示。IP 地址的取得方式,简单地说是大的组织先向 Internet 的 NIC(Net

16、work Information Center)申请若干 IP 地址,然后将其向下级组织分配,下级组织再向更下一级的组织分配IP 地址。各子网的网络管理员将取得的 IP 地址指定给子网中的各台计算机。IP 地址分为 3 类。1A类地址 A 类 IP 地址的最高位为 0,其前 8 位为网络地址,是在申请地址时由管理机构设定的,后 24 位为主机地址,可以由网络管理员分配给本机构子网的各主机。A 类地址的第一个十进制整数的值在 1 至 126 之间。一个 A 类地址最多可容纳 224(约 1600 万)台主机,最多可有 127 个 A 类地址。当然这是纯从数学上讲的,事实上不可能达到,因为一个网络

17、中有些地址另有特殊用途,不能分配给具体的主机和网络。下面在 B 类、C 类地址中的数字也是同样的。2B类地址 B 类 IP 地址的前 16 位为网络地址,后 16 位为主机地址,且第一位为 1,第二位为 0。B类地址的第一个十进制整数的值在128至191之间。一个B类网络最多可容纳216即65536台主机,最多可有 214 个 B 类地址。3C类地址 C 类 IP 地址的前 24 位为主机地址,最后 8 位为主机地址,且第一位、第二位为 1,第三位为 0。C 类地址的第一个整数值在 192 至 223 之间。一个 C 类网络最多可容纳 28即256 台主机,共有 221 个 C 类地址。有几个

18、特殊的 IP 地址,第一个是回送地址,该地址用于网络测试或本机进程间通信,十进制形式为 127.0.0.1。第二个是广播地址,用于呼叫整个网络内的计算机,子网中最后一个地址即被用作广播地址,例如 16.255.255.255 用于 A 类网络 16.0.0.0 中所有计算机的呼叫。第三个是子网地址,用于识别子网,子网中第一个地址即是子网地址,例如192.168.0.0。18.2.3 TCP 协议 原始的互联网使用的传输介质为电话线,计算机通过调制解调器将数值信号转为模拟信号,然后使用电流载波。因为电话线的噪声极大,很容易造成误码,因此 TCP 协议具有完善的循环校验机制。TCP 是重要的传输层

19、协议,必须保证数据传递的完整性。另外,数据包报文中有计算机端口号信息,可以用来区别同一计算机上不同应用程序的数据。数据包是很小的数据单位,而通过网络传递的连续数据往往是数据包长度的很多倍。因此,数据包报文中还有一个顺序编号,使接收的计算机能够更具编号重新按顺序还原数据。TCP 协议的另一个重要功能就是把大的数据切成较小的数据包,或者将接收到的数据第 4 篇 Linux 网络编程与数据库编程 244包按顺序还原为原始数据。如果发现某一个数据包丢失了,TCP 协议会向源计算机发送请求,要求重新传递丢失的数据包。这种处理能力,被称之为全双工。TCP 协议最小的处理单位为字节,因此 TCP 是面向字节

20、的顺序协议。数据包内的每个字节都会被分配一个顺序编号,以及为了验证数据真实性的奇偶校验位。虽然这种做法传递了过多的冗余数据,但根本原因是由早期网络极为不可靠造成的。为可靠的完成数据传输任务,TCP 将报文或数据分成可管理的长度并加上 TCP 头,并定义一些主要的字段,如图 18.7 所示。图 18.7 TCP 报文结构 TCP 报文中的字段定义如下。?源端口:源计算机指定的端口编号。?目的地端口:接收计算机的端口编号。?顺序号:分配给 TCP 包的编号。?应答号:接收计算机向源计算机发送的编号。?偏移位:指出 TCP 头的长度(即 TCP 头中的 32 位字的数)。它表明数据开始和TCP 头结

21、束。对于正常的 20 字节的头,这个字段设置成 0101。?保留位:为将来使用而保留。必须设置为 0。?控制位:用作个别控制位,如表 18.1 所示。?窗口号:窗口字段也称接收窗口大小,表示在 TCP 连接上准备由主机接收的 8 位字节的数目。?校验位:一个差错检验数,用于确定被接收的数据包文在传输期间是否被讹误。包括 TCP 头和所有数据。?紧急指针:它指出了紧接紧急数据的字节的顺序编号。?可选项:长度变量,它考虑到 TCP 使用的各种选项:选项表的结束、无操作、最大分段长度。表 18.1 TCP报头控制位指令 第 18 章 网络编程基础 245指 令 说 明 URG 紧急指示字段 ACK

22、如果设置,该包包含确认 PSH 启用推入功能 RST 恢复连接。用于一个功能不接收连接请求时 SYN 用于建立同步序号 FIN 数据不再从连接的发送点进入,结束总报文 TCP 提供的主要服务有:?建立、维持和终结两个进程之间的连接。?可靠的包传递(经过确认过程)。?编序包(可靠的数据传送)。?控制差错的机制。?通过使用端口,允许在个别的源和目的地主机内部实现和不同进程多重连接的 能力。?使用全双工操作的数据交换。18.2.4 UDP 协议 UDP 又称用户数据包文协议,也是 TCP/IP 的传输层协议,它是无连接的、不可靠的传输服务。当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序。

23、如果出现丢失包或重复包的情况,也不会向发送方发出差错报文,与 IP 协议非常类似。UDP 的主要作用是分配和管理端口编号,以正确无误的识别运行在网络站点上的个别应用程序。由于它执行功能时具有低的开销,因而执行速度比 TCP 快。它多半用于不需要可靠传输的应用程序,例如网络管理域、域名服务器等。UDP 协议的报文结构如图 18.8 所示。任何与 UDP 相配合作为传输层服务的应用程序必须提供确认和顺序系统,以确保数据包是以发送时的顺序到达。也就是说,使用 UDP 的应用程序必须提供这类服务。传输层具有独特的、与所有其他层不相关的帧头。UDP 报头及其数据被封装在 IP 报头内,由 IP 协议将这

24、个数据包文发送到数据链路层,依次下去,数据链路层又使用它的帧头包装这个报文,最后将数据送到物理层实际传输。当数据包被接时,数据链路层将把地址解释为它自己的,剥去它的帧头,将包传递给IP 层。IP 层将根据 IP 报头上的正确 IP 地址接受包。剥去它的报头,最后将数据包交给UDP 软件,UDP 软件接受包必须按 UDP 报头上的端口编号进行译码。第 4 篇 Linux 网络编程与数据库编程 246 图 18.8 UDP 报文结构 18.3 Socket 套接字 Socket 套接字由远景研究规划局(Advanced Research Projects Agency,ARPA)资助加里福尼亚大学

25、伯克利分校的一个研究组研发。其目的是将 TCP/IP 协议相关软件移植到UNIX 类系统中。设计者开发了一个接口,以便应用程序能简单地调用该接口通信。这个接口不断完善,最终形成了 Socket 套接字。Linux 系统采用了 Socket 套接字,因此,Socket接口就被广泛使用,到现在已经成为事实上的标准。与套接字相关的函数被包含在头文件sys/socket.h 中。18.3.1 Socket 套接字简介 Socket 的英文原意是“插座”,作为类 UNIX 系统的进程通信机制,它如同插座一样方便的帮助计算机接入互联网通信。任何用户在通信之前,首先要先申请一个 Socket 号,Socke

26、t 号相当于自己的电话号码。同时要知道对方的电话号码,相当于对方有一个 Socket。然后向对方拨号呼叫,相当于发出连接请求(假如对方不在同一区内,还要拨对方区号,相当于给出网络地址)。对方假如在场并空闲(相当于通信的另一主机开机且可以接受连接请求),拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是向电话机发出信号和从电话机接受信号的过程,相当于 Socket 发送数据和从 Socket 接受数据。通话结束后,一方挂起电话机,相当于关闭 Socket,撤销连接。由此可见,Socket 的通信机制与电话交换机制非常相似。Socket 实质上提供了进程通信的端点。进程通信之前,

27、双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。每一个 Socket 都用一个半相关描述。协议,本地地址,本地端口。第 18 章 网络编程基础 247一个完整的 Socket 则用一个相关描述:协议,本地地址,本地端口,远程地址,远程端口。每一个 Socket 有一个本地的唯一 Socket 号,由操作系统分配。套接字有 3 种类型:流式套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)和原始套接字。流式套接字可以提供可靠的、面向连接的通信流。如果通过流式套接字发送了顺序的数据:1、2。那么数据到达远程时候的顺序也是 1、2。流式套接字可用于 Telnet

28、 远程连接、WWW 服务等需要使数据顺序传递的应用,它使用 TCP 协议保证数据传输的可靠性。流式套接字的工作原理如图 18.9 所示,我们将网络中的两台主机分别作为服务器和客户机看待。数据包套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠性。数据包套接字使用者数据包协议 UDP,数据只是简单地传送到对方。数据包套接字的工作原理如图 18.10 所示。图 18.9 流式套接字的工作原理 图 18.10 数据套接字的工作原理 原始套接字允许对低层协议如 IP 或 ICMP 直接访问,主要用于新的网络协议实现的测试等。原始套接字主要用于一些协议的开发,可以进行

29、比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。18.3.2 创建套接字 套接字是通过标准的 UNIX 文件描述符和其他的程序通信的一个方法。套接字在使用第 4 篇 Linux 网络编程与数据库编程 248前必须先被建立,建立套接字的系统调用为 socket(),它的一般形式是:int socket(int domain,int type,int protocol);创建出来的套接字是一条通信线路的一个端点,domain 参数负责指定地址族,type 参数负责指定与这个套接字一起使用的通信类型,而 protocol 参数负责制定所使用的协议。d

30、omain 参数的取值范围如表 18.2 所示。表 18.2 domain参数的取值范围 参 数 说 明 AF_UNIX UNIX 内部(文件系统套接字)AF_INET ARPA 因特网协议(UNIX 网络套接字)AF_ISO ISO 标准协议 AF_NS 施乐网络系统协议 AF_IPX NOVELL IPX 协议 AF_APPLETALK Appletalk DDS 最常用的套接字域是 AF_UNIX 和 AF_INET,前者用于通过 UNIX 文件系统实现的本地套接字,后者用于 UNIX 网络套接字。AF_INET 套接字可以用在穿过包括 Internet 在内的各种 TCP/IP 网络而

31、进行通信的应用程序中。套接字参数 type 指定了与新套接字对应的通信特性。它的取值范围为枚举常量SOCK_STREAM 和 SOCK_DGRAM。SOCK_STREAM 是一个有序的、可靠的、基于连接的双向字节流。对于一个 AF_INET 域的套接字来说,如果在恋歌流式套接字的两端之间建立的是一个 TCP 连接,连接时默认值即为该特性。SOCK_DGRAM 是一个数据图服务,可以用来发送最大长度是一个固定值的消息,但消息是否会被送达或者消息的先后次序是否会在网络传输中被重新安排并没有保证。对于 AF_INET 域的套接字来说,这种类型的通信是由 UDP 提供的。通信所用的协议通常是由套接字的

32、类型和套接字的域来决定,如果还有其他的协议可以选择,那么就在 protocol 参数里设置。protocol 参数默认值为 0,表示使用默认的协议。socket 系统调用返回的是一个描述符,它与文件描述符非常相似。当这个套接字和通信线路另一端的套接字连接好以后,就可以进行数据的传输和接收操作了。18.3.3 套接字地址 每个套接字域都有独特的地址格式。对于一个 AF_UNIX 套接字来说,它的地址是由一个包含在 sys/un.h 头文件里的 sockaddr_un 结构描述的。该结构的定义为:struct sockaddr_un sa_family_t sun_family;/AF_UNIX

33、char sun_path;/路径;因为不同类型的地址都需要传递到对套接字进程处理的系统调用里去,所以定义各种第 18 章 网络编程基础 249地址格式时使用的结构也都很相似,每个结构的开始都是一个定义地址类型(即套接字域)的数据项。sun_family_t 是由 X/Open 技术规范定义的,在 Linux 系统上,它被声明为一个short 类型。sun_path 给出的路径长度是有限制的,Linux 规定其最长不能超过 108 个字符。因为地址结构在长度方面是不固定的,所以许多套接字调用都要用到或输出一个用来复制特定地址结构的长度值。AF_INET 域里的套接字地址是由一个定义在 neti

34、net/in.h 头文件里的 sockaddr_in 结构确定的。该结构的定义为:struct sockaddr_in short int sin_family;/AF_INET unsigned short int sin_port;/端口号 struct in_addr sin_addr;/Internet 地址;其中 Internet 地址是 netinet/in.h 头文件中定义的另一个结构体,该结构体的定义为:struct in_addr unsigned long int s_addr;一个 AF_INET 套接字完全可以由它的域、IP 地址和端口号确定下来。从应用程序的角度看,各

35、种套接字的行为就像是文件描述符,用一个独一无二的整数就可以把它们表示出来。18.3.4 套接字的名字 要使 socket()调用创建的套接字能够被其他进程使用,程序就必须给该套接字起个名字。AF_UNIX 套接字会关联到一个文件系统的路径名上去,AF_INET 套接字将关联到一个 IP 端口号上去。为套接字命名可使用 bind()系统调用,它的一般形式如下:int bind(int socket,const struct sockaddr*address,size_t address_len);bind()系统调用的作用是把参数 address 中给出的地址赋值给与文件描述符 socket 相

36、关联的未命名套接字。地址结构的长度是通过 address_len 参数传递的。地址的长度和类型取决于地址族。bind()调用需要用一个与之对应的地址结构指针指向真正的地址类型。该调用成功时将返回 0,否则返回1,并将 errno 变量设置为表 18.3 中的值。表 18.3 bind()系统调用返回的错误代码 代 码 说 明 EBADF 文件描述符无效 ENOTSOCK 该文件描述符代表的不是一个套接字 EINVAL 该文件描述符是一个已命名套接字 EADDRNOTAVAIL 地址不可用 EADDRINUSE 该地址已经绑定一个套接字 AF_UNIX 套接字对应的错误代码比上表要多出两个,分别

37、是 EACCESS,表示权限不第 4 篇 Linux 网络编程与数据库编程 250足,不能创建文件系统中使用的名字;ENOTDIR/ENAMETOOLONG,表示路径错误或路径名太长。18.3.5 创建套接字队列 为了能够在套接字上接受接入的连接,服务器程序必须创建一个队列来保存到达的请求。创建队列可使用系统调用 listen()完成,它的一般形式为:int listen(int socket,int backlog);Linux 系统可能会对队列里能够容纳的排队连接的最大个数有限制。在这个最大值的范围内,listen()将把队列长度设置为 backlog 个连接。在套接字上排队的接入连接个数

38、最多不能超过这个数字,再往后的连接将被拒绝,用户的连接请求将会失败。这是 listen()提供的一个机制,在服务器程序紧张地处理着上一个客户的时候,后来的连接将被放到队列里排队等号。backlog 常用的值是 5。listen()函数成功时会返回 0,否则返回1,它的错误代码包括 EBADF、EINVAL 和ENOTSOCK,含义同 bind()系统调用的错误代码相同。18.3.6 接受连接 服务器上的应用程序创建好命名套接字之后,就可以通过 accept()系统调用来等待客户端程序建立对该套接字的连接了。accept()的一般形式是:int accept(int socket,struct

39、sockaddr*address,size_t*address_len);accept()系统调用会等到有客户程序试图连接到由 socket 参数指定的套接字时才返回。该客户就是套接字队列里排在第一位的连接。accept()函数将创建出一个新的套接字来与该客户进行通信,返回的是与之对应的文件描述符。新套接字的类型与服务器监听套接字的类型相同。套接字必须是被 bind()调用命名过的,并且还要有一个由 listen()调用分配的连接队列。客户的地址将被放在 address 指向的 sockaddr 结构里。如果不关心客户的地址,可以在这里使用一个空指针。参数 address_len 给出了客户结

40、构的长度。如果客户地址的长度超过了这个值,就会被截短。在调用 accept()之前,必须把 address_len 设置为预期的地址长度。当这个调用返回时,address_len 将被设置为客户的地址结构的实际长度。如果套接字队列里没有排队等候的连接,accept 将阻塞程序,直到有客户建立连接为止。这个行为可以用 O_NONBLOCK 标志改变,方法是对这个套接字文件描述符调用 fcntl()函数。代码如下:int flags=fcntl(socket,F_GETFL,0);fcntl(socket,F_SETFL,O_NONBLOCK|flags);如果有排队等候的客户连接,accept(

41、)函数将返回一个新的套接字文件描述符,否则它第 18 章 网络编程基础 251将返回1。其错误原因除类似于 bind()调用和 listen()调用中的情况之外,还有一个EWOULDBLOCK,如果前面指定了 O_NONBLOCK 标志,但队列里没有排队的连接,就会出现这个错误。如果进程阻塞在 accept()调用里的时候执行被中断了,就会出现 EINTR错误。18.3.7 请求连接 当客户想要连接到服务器的时候,它会尝试在一个未命名套接字和服务器的监听套接字之间建立一个连接。它们用 connect()系统调用来完成这一工作,它的一般形式是:int connect(int socket,con

42、st struct sockaddr*address,size_t address_len);参数 socket 指定的套接字将连接到参数 address 指定的服务器套接字上去,服务器套接字的长度由参数 address_len 指定。套接字必须是通过 socket 调用获得的一个有效的文件描述符。如果操作成功,函数返回 0,否则返回1。该函数产生的错误代码如表 18.4 所示。表 18.4 connect()系统调用返回的错误代码 代 码 说 明 EBADF 文件描述符无效 EALREADY 套接字上已经有了一个正在使用的连接 ETIMEDOUT 连接超时 ECONNREFUSED 连接请求

43、被服务器拒绝 如果连接不能立刻建立起来,connect()会阻塞一段不确定的倒计时时间,这段倒计时时间结束后,这次连接就会失败。如果 connect()调用是被一个信号中断的,而这个信号又得到了处理,connect 还是会失败,但这次连接尝试是成功的,它会以异步方式继续尝试。类似于 accept()调用,connect()的阻塞特性可以用设置该文件描述符的 O_NONBLOCK标志的办法来改变。在这种情况下,如果连接不能立刻建立起来,connect()会失败并把 errno变量设置为 EINPROGRESS,而连接将以异步方式继续尝试。异步连接的处理是比较困难的,而我们可以在套接字文件描述符上

44、用一个 select()调用来表明该套接字已经处于写就绪状态。18.3.8 关闭连接 系统调用 close()函数可以结束服务器和客户上的套接字连接,就像对底层文件描述符进行操作一样。要想关闭套接字,就必须把服务器和客户两头都关掉才行。对服务器来说,应该在 read()返回 0 时进行该操作,但如果套接字是一个面向连接的类型并且设置了SOCK_LINGER 选项,close()调用会在该套接字尚有未传输数据时阻塞。第 4 篇 Linux 网络编程与数据库编程 25218.3.9 套接字通信 本节将设计两个例子演示套接字通信的过程,其中一个为服务器程序,另一个为客户程序。1服务器程序 服务器程序

45、的代码如下:#include#include /包含套接字函数库#include#include /包含 AF_INET 相关结构#include /包含AF_INET相关操作的函数#include int main()int server_sockfd,client_sockfd;/用于保存服务器和客户套接字标识符 int server_len,client_len;/用于保存服务器和客户消息长度 struct sockaddr_in server_address;/定义服务器套接字地址 struct sockaddr_in client_address;/定义客户套接字地址 server_

46、sockfd=socket(AF_INET,SOCK_STREAM,0);/定义套接字类型 server_address.sin_family=AF_INET;/定义套接字地址中的域 server_address.sin_addr.s_addr=inet_addr(127.0.0.1);/定义套接字地址 server_address.sin_port=9734;/定义套接字端口 server_len=sizeof(server_address);bind(server_sockfd,(struct sockaddr*)&server_address,server_len);/定义套接字名字 l

47、isten(server_sockfd,5);/创建套接字队列 while(1)char ch;printf(服务器等待消息n);client_len=sizeof(client_address);client_sockfd=accept(server_sockfd,/接收连接 (struct sockaddr*)&client_address,(socklen_t*_restrict)&client_len);read(client_sockfd,&ch,1);/读取客户消息 ch+;write(client_sockfd,&ch,1);/向客户传送消息 close(client_sockf

48、d);/关闭连接 该程序监听本地的 9734 端口,程序运行后等待客户通过该端口连接,从客户传送的消息里读取一个字符,然后对该字符进行加 1 操作后,再传送给客户,并关闭该连接。2客户程序 客户程序的源代码如下:第 18 章 网络编程基础 253#include#include /包含套接字函数库#include#include /包含 AF_INET 相关结构#include /包含 AF_INET 相关操作的函数#include int main()int sockfd;/用于保存客户套接字标识符 int len;/用于保存客户消息长度 struct sockaddr_in address

49、;/定义客户套接字地址 int result;char ch=A;/定义要传送的消息 sockfd=socket(AF_INET,SOCK_STREAM,0);/定义套接字类型 address.sin_family=AF_INET;/定义套接字地址中的域 address.sin_addr.s_addr=inet_addr(127.0.0.1);/定义套接字地址 address.sin_port=9734;/定义套接字端口 len=sizeof(address);result=connect(sockfd,(struct sockaddr*)&address,len);/请求连接 if(resu

50、lt=-1)perror(连接失败);return 1;write(sockfd,&ch,1);/向服务器传送消息 read(sockfd,&ch,1);/从服务器接收消息 printf(来自服务器的消息是%cn,ch);close(sockfd);/关闭连接 return 0;客户端程序向本地的 9734 端口请求连接,如果连接成功即发送一个字符 A 作为消息。然后从服务器传送的消息中读取一个字符,并将该字符输出,退出程序。将这两个程序分别编译,然后打开两个终端,第一个终端运行服务器程序,这时会出现提示符“服务器等待消息”。第二个终端运行客户程序,客户程序会将字符 A 作为消息传送给服务器程

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁