参考资料:
前言:
总结:
【计算机网络】套接字(应用层和传输层之间的接口)
- 套接字是一个通用的通信接口抽象
- 不仅限于TCP/IP协议族
- 作为应用层和传输层之间的桥梁
- 支持多种通信方式和协议族
套接字定义
在 TCP 或者 UDP 发送具体的报文信息前,需要先经过一扇 门
,这个门就是套接字(socket),套接字向上连接着应用层,向下连接着网络层。在操作系统中,操作系统分别为应用和硬件提供了接口(Application Programming Interface)。而在计算机网络中,套接字同样是一种接口,它也是有接口 API 的。
使用 TCP 或 UDP 通信时,会广泛用到套接字的 API,使用这套 API 设置 IP 地址、端口号,实现数据的发送和接收。
套接字在OSI和TCP/IP模型中的位置对比
OSI七层模型 TCP/IP四层模型
+---------------+ +---------------+
| 应用层 | | |
| 表示层 | ------> | 应用层 |
| 会话层 | | |
+---------------+ +---------------+
↑ ↑
| |
Socket接口 Socket接口
| |
↓ ↓
+---------------+ +---------------+
| 传输层 | ------> | 传输层 |
+---------------+ +---------------+
| 网络层 | ------> | 网络层 |
+---------------+ +---------------+
| 数据链路层 | | |
| 物理层 | ------> | 网络接口层 |
+---------------+ +---------------+
套接字类型
套接字的主要类型有三种,下面我们分别介绍一下
- 数据报套接字(Datagram sockets):数据报套接字提供一种无连接的服务,而且并不能保证数据传输的可靠性。数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP( User DatagramProtocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。
- 流套接字(Stream sockets):流套接字用于提供面向连接、可靠的数据传输服务。能够保证数据的可靠性、顺序性。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即 TCP(The Transmission Control Protocol)协议
- 原始套接字(Raw sockets): 原始套接字允许直接发送和接收 IP 数据包,而无需任何特定于协议的传输层格式,原始套接字可以读写内核没有处理过的 IP 数据包。
套接字使用
现在我们知道了, Socket 和 TCP/IP 没有必然联系,Socket 的出现只是方便了 TCP/IP 的使用,如何方便使用呢?你可以直接使用下面 Socket API 的这些方法。
方法 | 描述 |
create() | 创建一个 socket |
bind() | 套接字标识,一般用于绑定端口号 |
listen() | 准备接收连接 |
connect() | 准备充当发送者 |
accept() | 准备作为接收者 |
write() | 发送数据 |
read() | 接收数据 |
close() | 关闭连接 |
套接字处理过程
虽然套接字 API 位于应⽤程序层和传输层之间的通信模型中,但是套接字 API 不属于通信模型。套接字 API 允许应⽤程序与传输层和⽹络层进⾏交互。
在往下继续聊之前,我们先播放⼀个⼩插曲,简单聊⼀聊 IP。
【补充】聊聊 IP
【传输层】端口号
网络编程套接字(Socket)_scoket编程中ipv4长度宏-CSDN博客
端口(port)是伴随着传输层诞生的概念。它可以将网络层的IP通信分送到各个通信通道。UDP协议和TCP协议尽管在工作方式上有很大的不同,但它们都建立了从一个端口到另一个端口的通信。
端口号定义:
- 端口号是
传输层
的概念 - 端口号是一个
2字节/16位
的整数 端口号
用来标识主机上唯一一个网络进程
,公网IP标识互联网上唯一的主机。
-
- 端口号用来
标识一个进程
,用来告诉OS
,将数据交给哪一个进程
- 端口号用来
端口号+IP地址
可以标识互联网上唯一一个网络进程
。
-
IP地址+端口号
可以唯一的表示网络中一个主机的某一个进程
一个
端口号只能被一个进程占用
PS:
- 一台主机与另一台主机通信是进程间通信的另一种方式。
端口号和进程 ID:
一个进程PID
也可以唯一的标识一个进程
,那为什么还需要使用端口号
来标识一个主机中的进程呢?
- 当一个
进程退出
时,在次启动进程
时,它的PID
已经变化。所以要将进程和端口号绑定
来标识这个进程 一个进程
可以绑定多个端口号
,但是一个端口号
只能被一个进程
绑定
源端口号和目标端口号:
传输层
协议TCP/UDP
的数据段
中,也存在两个字段,一个是源端口号
,一个是目的端口号
,它用来表示这个数据是哪一个进程发的
,要发给哪一个进程
,也就是谁发的要发给谁
。
学习传输层协议之前,再谈端口号:
在网络编程套接字(Socket)_scoket编程中ipv4长度宏-CSDN博客中谈到端口号标识了一个主机上进行通信的不同应用程序
。
在TCP/IP
协议中, 用"源IP", "源端口号", "目的IP", "目的端口号", "协议号"
这样一个五元组来标识一个通信。
可以通过 netstat -n查看,协议号指的是那个使用协议
一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定。
- TCP 如何判断是哪个端口的呢?
端口号范围划分:
端⼝号是 16 位的⾮负整数,它的范围是 0 - 65535 之间,这个范围会分为三种不同的端⼝号段,由 Internet 号码分配机构 IANA 进⾏分配
0 - 1023
: 知名端口号,HTTP、FTP、 SSH等这些广为使用的应用层协议他们的端口号都是固定的,自己写的程序中,不能随意绑定知名端口号。1024 - 65535
:操作系统动态分配的端口号。 客户端程序的端口号,就是由操作系统从这个范围分配的。
-
- 注册端⼝号,范围是
1024 - 49151
- 私有端⼝号,范围是
49152 - 6553
- 注册端⼝号,范围是
常见的知名端口号:
- ssh服务器:22端口
- ftp服务器:21端口
- http服务器:80端口
- telnet服务器:23端口
- https服务器:443端口
- MYSQL服务器:3306端口
PS:
- 在Linux操作系统中使用命令cat /etc/services可以看到所有的知名端口。
应用程序&&端口号:
⼀台计算机上可以运⾏多个应⽤程序,当⼀个报⽂段到达主机后,应该传输给哪个应⽤程序呢?你怎么知道这个报⽂段就是传递给 HTTP 服务器⽽不是 SSH 服务器的呢?
是凭借端⼝号吗?当报⽂到达服务器时,是端⼝号来区分不同应⽤程序的,所以应该借助端⼝号来区分。
举个例⼦反驳⼀下 cxuan,假如到达服务器的两条数据都是由 80 端⼝发出的你该如何区分呢?或者说到达服务器的两条数据端⼝⼀样,协议不同,该如何区分呢?
所以仅凭端⼝号来确定某⼀条报⽂显然是不够的。
互联⽹上⼀般使⽤ 源 IP 地址、⽬标 IP 地址、源端⼝号、⽬标端⼝号、协议类型
这个五元组来进⾏区分。如果其中的某⼀项不同,就被认为是不同的报⽂段。这些也是多路分解和多路复⽤的基础。
确定端口号:
在实际通信之前,需要先确定⼀下端⼝号,确定端⼝号的⽅法分为两种:
- 标准既定的端⼝号
标准既定的端⼝号是静态分配的,每个程序都会有⾃⼰的端⼝号,每个端⼝号都有不同的⽤途。端⼝号是⼀个 16⽐特的数,其⼤⼩在 0 - 65535 之间, 0 - 1023 范围内的端⼝号都是动态分配的既定端⼝号,例如 HTTP 使⽤ 80端⼝来标识, FTP 使⽤ 21 端⼝来标识, SSH 使⽤ 22 来标识。这类端⼝号有⼀个特殊的名字,叫做 周知端⼝号(Well-Known Port Number) 。
- 时序分配的端⼝号
时序分配是⼀种动态分配的⽅式,它是由操作系统来进⾏分配端⼝号,能够保证不同应⽤程序使⽤不同的端⼝号。它的范围是从 1024 - 65535。
【补充】网络状态、进程查看工具:
netstat工具: 用来查看网络状态。
- n 拒绝显示别名,能显示数字的全部转化成数字
- l 仅列出有在
Listen (监听)
的服务状态 - p 显示正在使用
Socket
的程序识别码和程序名称 - t (tcp)仅显示
tcp
相关选项 - u u (udp)仅显示
udp
相关选项 - a (all)显示所有选项,默认不显示
LISTEN
相关
pidof [进程名]: 可以根据进程名直接查看服务器的进程id。例如:pidof sshd
。
【通信系统】多路复用和多路分解
多路复用(Multiplexing)
多路复用是一种技术,允许同时传输多个信号或数据流通过同一条通信信道。它通过不同的方法将多个信号合并成一个复合信号,以便在传输过程中共享资源。
主要方法:
- 频分复用(FDM):将不同的信号分配到不同的频率带宽上。
- 时分复用(TDM):按时间分割信道,每个信号占用不同的时间片。
- 码分复用(CDM):使用不同的编码区分信号。
- 波分复用(WDM):在光纤通信中,利用不同波长的光信号传输多个数据流。
多路分解(Demultiplexing)
多路分解是多路复用的逆过程,即接收端将复合信号分离回原来的各个独立信号。
主要方法:
- 频分多路分解:通过滤波器分离不同频率的信号。
- 时分多路分解:根据时间片分离信号。
- 码分多路分解:使用解码技术分离信号。
- 波分多路分解:通过分光器分离不同波长的光信号。
多路复用和多路分解在计算机网络中的应用
传输层通过多路复用和多路分解,利用端口号管理数据流,确保多个应用同时高效通信。这不仅提高了带宽利用率,还简化了网络结构,支持复杂的网络应用场景,如视频会议、在线游戏等,保障数据的准确传输。
- 传输层&&多路复用
其实就是本来就只有一条传输通道(在同一个 IP),但是一条通道的带宽是不完全占用满的,所以加入了端口号的概念(对数据包进行分组),实现多进程/通道数据传输;
- 传输层&&多路分解
其实就是把上面的端口号+IP 解包,给到不同的进程
多路复用(Multiplexing)在传输层的作用
- 定义:多路复用允许同时传输多个数据流,通过单一的物理或逻辑连接,提升带宽利用率。
- 实现方式:
-
- 端口号:传输层使用端口号区分不同应用的数据流。例如,HTTP使用80端口,FTP使用20和21端口。
- TCP和UDP:这两种协议处理多路复用,TCP通过端口号管理可靠连接,UDP则快速传输数据包,同样依赖端口号区分。
- 应用场景:当设备同时运行多个程序(如浏览器、邮件客户端、FTP客户端)时,传输层利用端口号封装数据包,确保各应用的数据不会混淆。
多路分解(Demultiplexing)在传输层的作用
- 定义:多路分解是接收端根据特定标识符(如端口号)将复合数据流分离到正确应用的过程。
- 实现方式:
-
- 端口号匹配:接收方传输层检查数据包的端口号,将其分配给对应的进程或应用。
- 套接字管理:每个连接由套接字(IP地址+端口号)唯一标识,确保数据正确分发。
- 应用场景:接收方的传输层拆分复合数据流,确保每个数据包到达正确的目的进程,如HTTP请求分发到Web服务器,FTP数据分发到文件传输应用。
传输层多路复用与分解的优势
- 高效带宽利用:允许多个应用共享网络连接,提升效率。
- 简化网络结构:无需为每个应用单独建立物理连接,减少网络复杂性。
- 支持并发处理:服务器可同时处理多个客户端连接,每个连接由唯一的端口号管理。
【计算机网络】多路复用和多路分解
我们上面聊到了在主机上的每个套接字都会分配一个端口号,当报文段到达主机时,运输层会检查报文段中的目的端口号,并将其定向到相应的套接字,然后报文段中的数据通过套接字进入其所连接的进程。
下面我们来聊一下什么是多路复用和多路分解的概念。
多路复用和多路分解分为两种,即无连接
的多路复用/多路分解和面向连接
的多路复用/多路分解
多路复用和多路分解是通信系统中的两个基本概念,用于提高资源利用效率和信号传输的灵活性。
无连接的多路复用和多路分解
开发人员会编写代码确定端口号是周知端口号还是时序分配的端口号。
假如主机 A 中的一个 10637 端口要向主机 B 中的 45438 端口发送数据,运输层采用的是 UDP 协议,数据在应用层产生后,会在运输层中加工处理,然后在网络层将数据封装得到 IP 数据报,IP 数据包通过链路层交付给主机 B,主机 B 会检查报文段中的端口号判断是哪个套接字的,这一系列的过程如下所示
UDP 套接字就是一个二元组,二元组包含目的 IP 地址和目的端口号。
所以,如果两个 UDP 报文段有不同的源 IP 地址和/或相同的源端口号,但是具有相同的目的 IP 地址和目的端口号,那么这两个报文会通过套接字定位到相同的目的进程。
这里思考一个问题,主机 A 给主机 B 发送一个消息,为什么还需要知道源端口号呢?
比如我给妹子表达出我对你有点意思的信息,妹子还需要知道这个信息是从我的哪个器官发出的吗?知道是我这个人对你有点意思不就完了?实际上是需要的,因为妹子如果要表达出她对你也有点意思,她是不是可能会亲你一口,那她得知道往哪亲吧?
这就是,在 A 到 B 的报文段中,源端口号会作为返回地址的一部分,即当 B 需要回发一个报文段给 A 时,B 需要从 A 到 B 中的源端口号取值,如下图所示
面向连接的多路复用与多路分解
如果说无连接的多路复用和多路分解指的是 UDP 的话,那么面向连接的多路复用与多路分解指的是 TCP 了,TCP 和 UDP 在报文结构上的差别是,UDP 是一个二元组而 TCP 是一个四元组,即源 IP 地址、目标 IP 地址、源端口号、目标端口号 ,这个我们上面也提到了。当一个 TCP 报文段从网络到达一台主机时,这个主机会根据这四个值拆解到对应的套接字上。
上图显示了面向连接的多路复用和多路分解的过程,图中主机 C 向主机 B 发起了两个 HTTP 请求,主机 A 向主机 C 发起了一个 HTTP 请求,主机 A、B、C 都有自己唯一的 IP 地址,当主机 C 发出 HTTP 请求后,主机 B 能够分解这两个 HTTP 连接,因为主机 C 发出请求的两个源端口号不同,所以对于主机 B 来说,这是两条请求,主机 B 能够进行分解。对于主机 A 和主机 C 来说,这两个主机有不同的 IP 地址,所以对于主机 B 来说,也能够进行分解。
【计算机网络】网络字节序(大小端)
内存中大于1个字节的数据相对于内存地址存在大小端之分,磁盘文件中多字节数据相对于偏移地址也存在大小端之分,网络中的数据流也存在大小端之分。
什么是大小端之分?
单独总结我的另一篇博客:数据存储大小端解析-CSDN博客
网络字节流的大小端:
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出。接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存。
- 网络数据流的地址规定,先发出的数据是低地址,后发出的数据是高地址。
- TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
- 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据。如果当前发送主机是小端, 就需要先将数据转成大端, 否则就忽略, 直接发送。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数对网络字节序和主机字节序的转换:
#include <arpa/inet.h>
//h--host主机,n--net网络,l--long长整型32位,s--short短整型16位
uint32_t htonl(uint32_t hostlong);//主机-->网络(32位)
uint16_t htons(uint16_t hostshort);//主机-->网络(16位)
uint32_t ntohl(uint32_t netlong);//网络-->主机(32位)
uint16_t ntohs(uint16_t netshort);//网络-->主机(16位)