Linux高并发服务器开发---笔记4(网络编程)
时间:2022-09-07 04:30:00
0705
第4章 提高项目生产和技能
- 4.0 视频课链接
- 4.1 项目介绍与环境建设
- 4.2 Linux系统编程1、4.3 Linux系统编程2
- 4.4 多进程
-
- 1-9
- 10.进程间通信☆☆☆
- 4.5 多线程
- 4.6 网络编程1 & 4.7 网络编程2
-
- 参考计算机网络笔记,Linux简明教程笔记2
- 1.MAC地址
-
- 网卡
- MAC地址
- 2.IP地址
-
- IP协议 和 IP地址
- IP地址编码方式(A类、B类、C类IP地址)
- 子网掩码
- 局域网、广域网、内网、外网
- 3.端口port(网络通信)
-
- 端口类型
- 4.网络模型
-
- OSI 七层参考模型
- TCP/IP 四层模型
-
- 和 OSI 七层参考模型 的关系
- 四层介绍
- 5.协议(网络协议)
-
- 协议的概念和三要素
- 常见协议
- UDP协议的第一个格式
- TCP协议
- IP协议的第一个格式
- 以太网帧协议
- ARP协议(IP地址 --> MAC地址)
- 封装
- 分用(解封装)
- 发送前包装,接收后解封
- 6.网络通信过程
- 7.socket介绍(IP地址,端口号)
- 8.字节序
-
- 概念(大端字节序 和 小端字节序)
- 字节序举例
-
- 如何验证你的电脑是大端还是小端?
- 字节序转换函数(网络字节序-大,主机字节序-小。
-
- 示例:
- 9.socket地址
-
- 通用socket地址(结构体sockaddr)
- 专用socket地址(结构体sockaddr_in 和 结构体sockaddr_in6)
- 10.IP地址转换(字符串ip-整数 ,转换主机和网络字节序)
-
- 示例:
- 11-17 TCP
-
- TCP和UDP的区别
- TCP通信流程
- 套接字函数
-
- 头文件:
- socket()函数:
- bind()函数:
- listen()函数:
- accept()函数:(阻塞)
- connect()函数:
- write()函数、read()函数
- ☆示例
- ☆☆☆补充理解TCP通信
- TCP三次握手
-
- 三次握手的概念
- TCP首部格式:
- 三次握手示意图及过程
- 为什么是三次握手,而不是四次或者两次握手?
- TCP滑动窗口
- TCP四次挥手
- TCP状态转换
-
- TIME_WAIT为什么状态要持续? 2 * MSL 的时间?
- 半关闭状态 (函数shutdown() 和 close() 的区别)
- 18.端口复用 --- setsockopt()函数
-
- 第四次挥手后等待`2 * MSL`带来的问题
- 示例(将上述问题复现出来)
- 解决方案:端口重用
- 19.I/O多路复用(I/O多路转接)☆☆☆
4.0 视频课链接
4.1 项目介绍与环境建设
4.2 Linux系统编程1、4.3 Linux系统编程2
4.4 多进程
1-9
Linux高并发服务器开发-笔记1
10.进程间通信☆☆☆
见Linux高并发服务器开发-笔记2
4.5 多线程
见Linux高并发服务器开发-笔记3(多线程)
4.6 网络编程1 & 4.7 网络编程2
视频课链接:
4.6 网络编程1
4.6 网络编程2
参考计算机网络笔记,Linux简明教程笔记2
计算机网络笔记
②Linux简洁系统编程(嵌入式微信官方账号课)-总课时12h
1.MAC地址
网卡
网卡是一种计算机硬件,设计用于允许计算机在计算机网络上通信,也称为网络适配器或网络接口卡NIC。其拥有 MAC 地址,属于 OSI 模型的第 2 层,它让用户通过电缆
或无线
相互连接。(即网卡分为以太网卡和无线网卡)
每个网卡都有一个叫做 MAC 独一无二的地址 48 位串行号。
网卡的主要功能:
1.包装和解封数据
2.链路管理
3.数据编码和译码。
MAC地址
MAC 地址(Media Access Control Address),直译为媒体访问控制位置,又称以太网地址、物理地址或硬件地址,它是用来的确认网络设备的位置由网络设备制造商生产位置在网卡中烧录。 OSI 在模型中,第三层网络层负责 IP 第二层数据链路层负责地址 MAC位址 。
MAC 地址用于在网络中识别网卡和设备若有一张或多张网卡,则每个网卡都需要并且会有一个独特的 MAC 地址。
<>MAC 地址的长度为 48 位(6个字节),通常表示为 12 个 16 进制数,如:00-16-EA-AE-3C-40 就是一个MAC 地址,其中前 3 个字节,16 进制数 00-16-EA 代表网络硬件制造商的编号,它由IEEE(电气与电子工程师协会)分配,而后 3 个字节,16进制数 AE-3C-40 代表该制造商所制造的某个网络产品(如网卡)的系列号 。只要不更改自己的 MAC 地址,MAC 地址在世界是唯一的。形象地说,MAC 地址就如同身份证上的身份证号码,具有唯一性。
2.IP地址
IP协议 和 IP地址
IP 协议是为计算机网络相互连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守 IP 协议就可以与因特网互连互通。
各个厂家生产的网络系统和设备,如以太网、分组交换网等,它们相互之间不能互通,不能互通的主要原因是因为它们所传送数据的基本单元(技术上称之为“帧”)的格式不同。IP 协议实际上是一套由软件程序组成的协议软件,它把各种不同“帧”统一转换成“IP 数据报”格式,这种转换是因特网的一个最重要的特点,使所有各种计算机都能在因特网上实现互通,即具有“开放性”的特点。正是因为有了 IP 协议,因特网才得以迅速发展成为世界上最大的、开放的计算机通信网络。因此,IP 协议也可以叫做“因特网协议”。
IP 地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。IP 地址是 IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
IP 地址是一个 32 位的二进制数,通常被分割为 4 个“ 8 位二进制数”(也就是 4 个字节)。IP 地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是 0~255 之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是 32 位二进制数(01100100.00000100.00000101.00000110)。
IP地址编址方式(A类、B类、C类IP地址)
每个 IP 地址包括两个标识码(ID),即网络ID 和主机 ID。同一个物理网络上的所有主机都使用同一个网络 ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机 ID 与其对应。Internet 委员会定义了 5 种 IP 地址类型以适合不同容量
的网络,即 A 类~ E 类。
特殊的IP地址:
- 每一个字节都为 0 的地址( “0.0.0.0” )对应于当前主机(包括有线网卡和无线网卡);
- IP 地址中的每一个字节都为 1 的 IP 地址( “255.255.255.255” )是当前子网的广播地址;
- IP 地址中凡是以 “11110” 开头的 E 类 IP 地址都保留用于将来和实验使用;
- IP地址中不能以十进制 “127” 作为开头,该类地址中数字 127.0.0.1 到 127.255.255.255 用于回路测试,如:127.0.0.1可以代表本机IP地址。
子网掩码
子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个 IP 地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。
子网掩码不能单独存在,它必须结合 IP 地址一起使用。子网掩码只有一个作用,就是将某个 IP 地址划分成网络地址
和主机地址
两部分。
子网掩码是一个 32 位地址,用于屏蔽 IP 地址的一部分以区别网络标识和主机标识,只有网络标识相同的两台主机在无路由的情况下才能相互通信(在同一个子网中)。
子网掩码是一个 32 位的 2 进制数, 其对应网络地址的所有位都置为 1
,对应于主机地址的所有位置都为 0
。子网掩码告知路由器,地址的哪一部分是网络地址,哪一部分是主机地址,使路由器正确判断任意 IP 地址是否是本网段的,从而正确地进行路由。网络上,数据从一个地方传到另外一个地方,是依靠 IP 寻址。从逻辑上来讲,是两步的。第一步,从 IP 中找到所属的网络,好比是去找这个人是哪个小区的;第二步,再从 IP 中找到主机在这个网络中的位置,好比是在小区里面找到这个人。
局域网、广域网、内网、外网、互联网
- 广域网(Wide Area Network,缩写为 WAN),又称外网、公网,外网也叫互联网;
- 局域网是封闭型的,也叫内网,私有IP。
3.端口port(做网络通信)
端口分为虚拟端口和物理端口,其中
- 虚拟端口指计算机内部或交换机路由器内的端口,不可见,是特指TCP/IP协议中的端口,是逻辑意义上的端口。例如计算机中的
80 端口、21 端口、23 端口
等; - 物理端口又称为接口,是可见端口,计算机背板的
RJ45 网口
,交换机路由器集线器等 RJ45 端口。电话使用RJ11 插口
也属于物理端口的范畴。
如果把 IP 地址比作一间房子,端口就是出入这间房子的门。真正的房子只有几个门,但是一个 IP地址的端口可以有 65536(即:2^16)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从 0 到65535(2^16-1)。
端口类型
- 周知端口(Well Known Ports)
周知端口是众所周知的端口号,也叫知名端口、公认端口或者常用端口,范围从 0 到 1023,它们紧密绑定于一些特定的服务。例如 80 端口分配给 WWW 服务,21 端口分配给 FTP 服务,23 端口分配给Telnet服务等等。我们在 IE 的地址栏里输入一个网址的时候是不必指定端口号的,因为在默认情况下WWW 服务的端口是 “80”。网络服务是可以使用其他端口号的,如果不是默认的端口号则应该在地址栏上指定端口号,方法是在地址后面加上冒号“:”(半角),再加上端口号。比如使用 “8080” 作为 WWW服务的端口,则需要在地址栏里输入“网址:8080”。但是有些系统协议使用固定的端口号,它是不能被改变的,比如 139 端口专门用于NetBIOS 与 TCP/IP 之间的通信,不能手动改变。 - 注册端口(Registered Ports)
端口号从 1024 到 49151,它们松散地绑定于一些服务,分配给用户进程或应用程序,这些进程主要是用户选择安装的一些应用程序,而不是已经分配好了公认端口的常用程序。这些端口在没有被服务器资源占用的时候,可以用用户端动态选用为源端口。 - 动态端口 / 私有端口(Dynamic Ports / Private Ports)
动态端口的范围是从 49152 到 65535。之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。
4.网络模型
OSI 七层参考模型
- 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
- 数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能。定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。将比特组合成字节进而组合成帧,用MAC地址访问介质。
- 网络层:进行逻辑地址寻址,在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。
- 传输层:定义了一些传输数据的协议和端口号( WWW 端口 80 等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP 特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如 QQ 聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
- 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求。
- 表示层:数据的表示、安全、压缩。主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
- 应用层:网络服务与最终用户的一个接口。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
TCP/IP 四层模型
和 OSI 七层参考模型 的关系
TCP/IP 协议在一定程度上参考了 OSI 的体系结构。OSI 模型共有七层,从下到上分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。但是这显然是有些复杂的,所以在 TCP/IP 协议中,它们被简化为了四个层次。
(1)应用层、表示层、会话层三个层次提供的服务相差不是很大,所以在 TCP/IP 协议中,它们被合并为应用层一个层次。
(2)由于传输层和网络层在网络协议中的地位十分重要,所以在 TCP/IP 协议中它们被作为独立的两个层次。
(3)因为数据链路层和物理层的内容相差不多,所以在 TCP/IP 协议中它们被归并在网络接口层一个层次里。
只有四层体系结构的 TCP/IP 协议,与有七层体系结构的 OSI 相比要简单了不少,也正是这样,TCP/IP 协议在实际的应用中效率更高,成本更低。
四层介绍
- 应用层:应用层是 TCP/IP 协议的第一层,是直接为应用进程提供服务的。
(1)对不同种类的应用程序它们会根据自己的需要来使用应用层的不同协议,邮件传输应用使用了 SMTP 协议、万维网应用使用了 HTTP 协议、远程登录服务应用使用了有 TELNET 协议。
(2)应用层还能加密、解密、格式化数据。
(3)应用层可以建立或解除与其他节点的联系,这样可以充分节省网络资源。 - 传输层:作为 TCP/IP 协议的第二层,运输层在整个 TCP/IP 协议中起到了中流砥柱的作用。且在运输层中, TCP 和 UDP 也同样起到了中流砥柱的作用。
- 网络层:网络层在 TCP/IP 协议中的位于第三层。在 TCP/IP 协议中网络层可以进行网络连接的建立和终止以及 IP 地址的寻找等功能。
- 网络接口层:在 TCP/IP 协议中,网络接口层位于第四层。由于网络接口层兼并了物理层和数据链路层所以,网络接口层既是传输数据的物理媒介,也可以为网络层提供一条准确无误的线路。
5.协议(网络协议)
协议的概念和三要素
协议,网络协议的简称,网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定,计算机之间才能相互通信交流。
协议三要素是:语法、语义、时序。
为了使数据在网络上从源到达目的,网络通信的参与方必须遵循相同的规则,这套规则称为协议(protocol),它最终体现为在网络上传输的数据包的格式。
协议往往分成几个层次进行定义,分层定义是为了使某一层协议的改变不影响其他层次的协议。
常见协议
- 应用层常见的协议有:
FTP协议
(File Transfer Protocol 文件传输协议)、HTTP协议
(Hyper Text Transfer Protocol 超文本传输协议)、NFS(Network File System 网络文件系统)。 - 传输层常见协议有:
TCP协议
(Transmission Control Protocol 传输控制协议)、UDP协议
(User Datagram Protocol 用户数据报协议)。 - 网络层常见协议有:
IP 协议
(Internet Protocol 因特网互联协议)、ICMP 协议
(Internet Control Message Protocol 因特网控制报文协议)、IGMP 协议
(Internet Group Management Protocol 因特网组管理协议)。 - 网络接口层常见协议有:
ARP协议
(Address Resolution Protocol 地址解析协议)、RARP协议
(Reverse Address Resolution Protocol 反向地址解析协议)。
UDP协议首部格式
- 源端口号:发送方端口号
- 目的端口号:接收方端口号
- 长度:UDP用户数据报的长度,最小值是8B(仅有首部)
- 校验和:检测UDP用户数据报在传输中是否有错,有错就丢弃
MD5算法?
TCP协议
- 源端口号:发送方端口号;
- 目的端口号:接收方端口号;
- 序列号
seq
:本报文段的数据的第一个字节的序号; - 确认序号
ack
:期望收到对方下一个报文段的第一个数据字节的序号 - 首部长度(数据偏移):TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远,即首部长度。单位:32位,即以 4 字节为计算单位;
- 保留:占 6 位,保留为今后使用,目前应置为 0;
- 紧急 URG :此位置 1 ,表明紧急指针字段有效,它告诉系统此报文段中有紧急数据,应尽快传送;
- 确认 ACK:仅当 ACK=1 时确认号字段才有效,TCP 规定,在连接建立后所有传达的报文段都必须把 ACK 置1;
- 推送 PSH:当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP 就可以使用推送(push)操作,这时,发送方TCP 把 PSH 置 1,并立即创建一个报文段发送出去,接收方收到 PSH = 1 的报文段,就尽快地(即“推送”向前)交付给接收应用进程,而不再等到整个缓存都填满后再向上交付;
- 复位 RST:用于复位相应的 TCP 连接
- 同步 SYN:仅在三次握手建立 TCP 连接时有效。当 SYN = 1 而 ACK = 0 时,表明这是一个连接请求报文段,对方若同意建立连接,则应在响应的报文段中使用 SYN = 1 和 ACK = 1。因此,SYN 置1 就表示这是一个连接请求或连接接受报文;
- 终止 FIN:用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接;
- 窗口:指发送本报文段的一方的接收窗口(而不是自己的发送窗口);
- 校验和:校验和字段检验的范围包括首部和数据两部分,在计算校验和时需要加上 12 字节的伪头部;(跟IP首部中的校验和字段的功能区分开,人家只能校验首部的内容)
- 紧急指针:仅在 URG = 1 时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),即指出了紧急数据的末尾在报文中的位置,注意:即使窗口为零时也可发送紧急数据;
- 选项:长度可变,最长可达 40 字节,当没有使用选项时,TCP 首部长度是 20 字节。
IP协议首部格式
- 版本:IP 协议的版本。通信双方使用过的 IP 协议的版本必须一致,目前最广泛使用的 IP 协议版本号为 4(即IPv4);
- 首部长度:单位是 32 位(4 字节);
- 服务类型:一般不使用,取值为 0;
- 总长度:指首部加上数据的总长度,单位为1个字节;
- 标识(identification)(16位):IP 软件在存储器中维持一个计数器,每产生一个数据报,计数器就加 1,并将此值赋给标识字段;
- 标志(flag)(3位):目前只有两位有意义。
标志字段中的最低位记为MF
。MF = 1 即表示后面“还有分片”的数据报。MF = 0 表示这已是若干数据报片中的最后一个;
标志字段中间的一位记为DF
,意思是“不能分片”,只有当 DF = 0 时才允许分片; - 片偏移(13位):指出较长的分组在分片后,某片在源分组中的相对位置,也就是说,相对于用户数据段的起点,该片从何处开始。片偏移以 8 字节为偏移单位。
- 生存时间
TTL
:表明是数据报在网络中的寿命,即为“跳数限制”,由发出数据报的源点设置这个字段。路由器在转发数据之前就把 TTL 值减一,当 TTL 值减为零时,就丢弃这个数据报。 - 协议:指出此数据报携带的数据使用何种协议,以便使目的主机的 IP 层知道应将数据部分上交给哪个处理过程,即IP数据报传到传输层之后具体给到哪个协议取决于
协议
字段,常用的有ICMP(1),IGMP(2),TCP(6),UDP(17),IPv6(41)
; - 首部校验和:只校验数据报的首部,不包括数据部分;(注意和TCP的首部校验和区分开)
- 源地址:发送方 IP 地址;
- 目的地址:接收方 IP 地址。
以太网帧协议
注意:
这里的类型字段决定了以太网帧传到网络层之后具体给到哪个协议,0x800表示 IP协议、0x806表示 ARP协议、0x835表示 RARP协议。
ARP协议(IP地址 --> MAC地址)
(可以参考 计算机网络的笔记 中的 ARP协议)
地址解析协议(ARP,Address Resolution Protocol),用来实现IP地址到MAC地址的映射。每台主机都有一个ARP高速缓存,用来存放本局域网上各主机和路由器的IP地址到MAC地址的映射表,称为ARP表。
工作原理:
主机A欲向本局域网上的某台主机B发送IP数据报,先在主机A的ARP高速缓存中查看有无主机B的IP地址:
- 如果有,就可以查出对应的硬件地址,再将此硬件地址写入MAC帧,然后发送过去;
- 如果没有,就向局域网内的所有主机发送一个广播,内容是ARP请求分组,主机B收到该ARP请求之后,会向主机A单播发送一个响应ARP分组,内容包含主机B的IP地址和MAC地址的映射关系,主机A收到后将此映射写入ARP缓存,然后按查询到的硬件地址发送MAC帧;
下一次主机A再向主机B发送数据的时候就可以直接在ARP缓存中查找到主机B的地址。
总结:
1.ARP协议就是用来寻找某个主机IP地址对应的MAC地址,即是一个寻址的协议。
2.ARP用于解决同一个局域网上的主机或路由器的IP 地址和硬件地址的映射问题。
3.如果所要找的主机和源主机不在同一个局域网上,那么就要通过 ARP找到一个位于本局域网上的某个路由器的硬件地址(MAC地址),然后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络。剩下的工作就由 下一个网络来做,尽管 ARP 请求分组是广播发送的,但 ARP响应分组是普通的单播,即从一个源地址发送到一个目的地址。
(计算机网络笔记中还有一个例子)
- 硬件类型:1 表示 MAC 地址
- 协议类型:0x800 表示 IP 地址
- 硬件地址长度:6
- 协议地址长度:4
- 操作:1 表示 ARP 请求,2 表示 ARP 应答,3 表示 RARP 请求,4 表示 RARP 应答
封装
上层协议是如何使用下层协议提供的服务的呢?其实这是通过封装(encapsulation)实现的。
应用程序数据在发送到物理网络上之前:1.将沿着协议栈从上往下依次传递;2.每层协议都将在上层数据的基础上加上自己的头部信息(有时还包括尾部信息),以实现该层的功能;这个过程就称为封装。
分用(解封装)
当帧到达目的主机时,将沿着协议栈自底向上依次传递。各层协议依次处理帧中本层负责的头部数据,以获取所需的信息,并最终将处理后的帧交给目标应用程序。这个过程称为分用(demultiplexing)。
分用是依靠头部信息中的类型
字段、协议
字段、端口号
字段实现的:
- 数据链路层–>网络层:以太网帧中的类型字段决定往上层走去找哪个协议(
0x800表示 IP、0x806表示 ARP、0x835表示 RARP
); - 网络层–>传输层:IPv4头部中的协议字段决定往上层走去找哪个协议(
ICMP(1),IGMP(2),TCP(6),UDP(17),IPv6(41)
); - 传输层–>应用层:TCP/UDP头部中的端口号字段决定往上层走去找哪个进程(
80 端口分配给 WWW 服务,21 端口分配给 FTP 服务,23 端口分配给Telnet服务等
)
发送前封装,接收后解封装
6.网络通信过程
7.socket介绍(IP地址,端口号)
(视频课从01:28:00开始)
(可以参考②Linux简明系统编程(嵌入式公众号的课)—总课时12h 中的TCP编程 — 第22、23节课:TCP服务端、客户端编程)
所谓 socket(套接字),就是对(网络中不同主机上的应用进程之间进行双向通信的)端点
的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。
socket 可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的 API,也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 socket
中,该 socket 通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 socket
中,使对方能够接收到这段信息。
socket 是由 IP 地址和端口结合的,提供向应用层进程传送数据包的机制。
socket 本身有“插座”的意思,在 Linux 环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区
形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux 系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地
进程间通信,而套接字多应用于网络
进程间数据的传递。
套接字通信分两部分:
- 服务器端:被动接受连接,一般不会主动发起连接;
- 客户端:主动向服务器发起连接;
socket是一套通信的接口,Linux 和 Windows 都有,但是有一些细微的差别。
8.字节序
概念(大端字节序 和 小端字节序)
字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。
字节序分为大端字节序(Big-Endian) 和小端字节序(Little-Endian):
- 大端字节序是指一个整数的最高位字节(23 ~ 31 bit)存储在内存的低地址处,低位字节(0 ~ 7 bit)存储在内存的高地址处;
- 小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地址处。
字节序举例
如何验证自己电脑上是大端还是小端?
// 通过代码检测当前主机的字节序
#include
int main() {
union {
short value; // 2字节
char bytes[sizeof(short)]; // char[2]
} test;
test.value = 0x0102;
if((test.bytes[0] == 1) && (test.bytes[1] == 2)) {
printf("大端字节序\n");
} else if((test.bytes[0] == 2) && (test.bytes[1] == 1)) {
printf("小端字节序\n");
} else {
printf("未知\n");
}
return 0;
}
结果:
小端字节序
[1] + Done "/usr/bin/gdb" --interpreter=mi --tty=${
DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-yj4tncle.ue3" 1>"/tmp/Microsoft-MIEngine-Out-g52kkyor.quk"
root@VM-16-2-ubuntu:/home/reus/牛客网-Linux高并发服务器开发#
字节序转换函数(网络字节序-大、主机字节序-小)
网络字节顺序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用大端排序方式。
主机字节序一般是小端排序方式。
从主机字节序到网络字节序的转换函数:htons
、htonl
;
从网络字节序到主机字节序的转换函数:ntohs
、ntohl
。
其中,
h - host 主机,主机字节序
to - 转换成什么
n - network 网络字节序
s - short, unsigned short(两个字节:端口号)
l - long, unsigned int(四个字节:IP地址)
函数原型:
#include
// 转换端口
uint16_t htons(uint16_t hostshort); // 主机字节序 - 网络字节序
uint16_t ntohs(uint16_t netshort); // 网络字节序 - 主机字节序
// 转IP
uint32_t htonl(uint32_t hostlong); // 主机字节序 - 网络字节序
uint32_t ntohl(uint32_t netlong); // 网络字节序 - 主机字节序
typedef unsigned short uint16_t;//16位无符号整型
typedef unsigned int uint32_t;//32位无符号整型
示例:
示例1:htons()函数、htonl()函数、ntohl()函数
#include
#include
int main() {
//printf("a = %d, b = %d\n", sizeof(unsigned short), sizeof(unsigned short int)); // a = 2, b = 2
// htons 转换端口(short类型,占2个字节)
unsigned short a = 0x1234;//主机字节序(小端模式)
printf("a : %x\n", a);
unsigned short b = htons(a);//转换成网络字节序(大端模式)
printf("b : %x\n", b);
printf("=======================\n");
// htonl 转换IP(int类型,占4个字节)
char buf[4] = {
100, 80, 1, 100};
int num = *(int *)buf;
printf("num = %d\n", num);
int sum = htonl(num);
unsigned char *p = (unsigned char *)∑
printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));
printf("=======================\n");
// ntohl
unsigned char buf1[4] = {
1, 1, 80, 100};
int num1 = *(int *)buf1;
int sum1 = ntohl(num1);
unsigned char *p1 = (unsigned char *)&sum1;
printf("%d %d %d %d\n", *p1, *(p1+1), *(p1+2), *(p1+3));
// ntohs
return 0;
}
结果:
a : 1234
b : 3412
=======================
num = 1677807716
100 1 80 100
=======================
100 80 1 1
示例2:htons()函数
(②Linux简明系统编程(嵌入式公众号的课)—总课时12h中的示例)
1.把主机字节序转换成网络字节序:
htons(8800);//端口号
9.socket地址
socket地址其实是一个结构体,封装端口号和IP地址等信息。后面的socket相关的api中需要使用到这个socket地址。
通用socket地址(结构体sockaddr)
socket 网络编程接口中表示 socket 地址的是结构体 sockaddr
,其定义如下:
#include
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};
typedef unsigned short int sa_family_t;
参数1:
其中sa_family
成员是地址族类型(sa_family_t
)的变量。地址族类型通常与协议族类型对应。常见的协议族(protocol family,也称 domain
)和对应的地址族入下所示:
协议族 | 地址族 | 描述 |
---|---|---|
PF_UNIX | AF_UNIX | UNIX本地域协议族 |
PF_INET | AF_INET | TCP/IPv4协议族 |
PF_INET6 | AF_INET6 | TCP/IPv6协议族 |
宏 PF_*
和 AF_*
都定义在 bits/socket.h
头文件中,且后者与前者有完全相同的值,所以二者通常混用。
参数2:
sa_data
成员用于存放 socket 地址值。但是,不同的协议族的地址值具有不同的含义和长度,如下所示:
协议族 | 地址值含义和长度 |
---|---|
PF_UNIX | 文件的路径名,长度可达到108字节 |
PF_INET | 16 bit 端口号和 32 bit IPv4 地址,共 6 字节 |
PF_INET6 | 16 bit 端口号,32 bit 流标识,128 bit IPv6 地址,32 bit 范围 ID,共 26 字节 |
由上表可知,14 字节的 sa_data 根本无法容纳多数协议族的地址值。因此,Linux 定义了下面这个新的通用的 socket 地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的。
#include
struct sockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[ 128 - sizeof(__ss_align) ];
};
typedef unsigned short int sa_family_t;
专用socket地址(结构体sockaddr_in 和 结构体sockaddr_in6)
很多网络编程函数诞生早于 IPv4 协议,那时候都使用的是 struct sockaddr 结构体,为了向前兼容,现在sockaddr 退化成了(void *)的作用,传递一个地址给函数,至于这个函数是 sockaddr_in
还是sockaddr_in6
,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。
注意:
所有专用 socket 地址(以及 sockaddr_storage)类型的变量在实际使用时都需要转化为通用 socket 地址类型 sockaddr
(强制转化即可),因为所有 socket 编程接口使用的地址参数类型都是 sockaddr
。
1.UNIX 本地域协议族使用如下专用的 socket 地址结构体:
#include
struct sockaddr_un { sa_family_t sin_family; char sun_path[108];