Linux网络——网络套接字
系列文章目录
文章目录
- 系列文章目录
- 一、 IP
- 二、端口号
- 三、 认识TCP与UDP 协议
- 1. TCP 协议
- 2. UDP 协议
- 四、网络字节序 (大小端问题)
- 四、socket 套接字
- 1. socket 常见 API
- (1)socket
- (2)bind
- (3)listen
- (4)accept
- (5)connect
- 2. sockaddr 结构
- 五、总结
一、 IP
理解源 IP 地址和目的 IP 地址
举例理解:(唐僧西天取经)
在 IP 数据包头部中 有两个 IP 地址, 分别叫做源 IP 地址 和目的 IP 地址
如果我们的台式机或者笔记本没有 IP 地址就无法上网,而因为每台主机都有 IP 地址,所以注定了数据从一台主机传输到另一台主机就一定有源 IP 地址和目的 IP 地址,所以在报头中就会包含源 IP 地址和目的 IP 地址
而我们将数据从一台主机传递到另一台主机并不是目的,真正通信的其实是应用层上的软件
我们知道应用层可不止一个软件,既然有了公网 IP 标识了一台唯一的主机,那么数据就可以由一台主机传递到另一台主机,但是有这么多的软件(进程),如何保证软件 A 发送的被软件 B 接收呢?(用什么来标识主机上的进程的唯一性呢?)
二、端口号
端口号是用于标识在一台设备上运行的不同网络应用程序或服务的数字标识符,它是一个 16 位的数字,可以是 0~65535 之间的任意值。当一个应用程序或服务需要通过网络进行通信时,它会打开一个特定的端口,并侦听该端口上的连接,这个侦听过程称为绑定(binding),当其他设备或应用程序尝试连接到此端口时,操作系统会将连接转发给已经绑定到该端口的应用程序进程
因此,可以说端口号和进程之间存在一对一的映射关系。一个特定的端口号通常与一个特定的进程或应用程序相关联,而且一个端口号只能与绑定一个进程。当网络通信发生时,数据包会通过端口号被正确地路由至相应的进程,以确保通信的正确进行
同一台设备上的不同进程可以绑定不同的端口号,这样就使得多个应用程序能够同时进行网络通信,而无需担心冲突。每个进程可以通过独立的端口号进行区分和识别,从而实现并发的网络通信
为了更好的表示一台主机上服务进程的唯一性,规定用端口号标识服务进程、客户端进程的唯一性
端口号(port)是传输层协议的内容
- 端口号是一个 2 字节 16 位的整数
- 端口号用来标识一个进程,告诉操作系统:当前的这个数据要交给哪一个进程来处理
- 一个端口号只能被一个进程占用(一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定)
IP 地址(标识唯一主机)+ 端口号(标识唯一进程)能够标识网络上的某一台主机的某一个进程(全网唯一的进程)
端口号的解释:
- HTTP 通信使用的端口号是 80
在浏览器中输入网址并访问一个网站时,浏览器会与服务器进行 HTTP 通信。在这个过程中,浏览器将通过端口号 80 发送请求,以与服务器上运行的 Web 服务器进行通信。Web 服务器接收到请求后,会将相应的网页内容返回给浏览器,并通过端口号 80 将响应发送回浏览器。因此,端口号 80 在这种情况下用于标识 HTTP 通信
- FTP 通信使用的端口号是 21
使用 FTP 客户端与远程服务器进行文件传输时,通常使用的端口号是 21。FTP 客户端通过端口号 21 与 FTP 服务器建立连接并发送指令来上传、下载或删除文件。端口号 21 被 FTP 协议保留,用于标识 FTP 通信
每个端口号都有特定的作用和用途,例如常见的端口号有:
- 20 和 21:FTP
- 22:SSH
- 25:SMTP(用于发送电子邮件)
- 53:DNS(域名系统)
- 80:HTTP
- 443:HTTPS
将数据送给对方的机器是我们的目的吗?
不是,而是手段。真正的网络通信过程的本质其实就是进程间通信
将数据在主机间转发仅仅是手段,机器收到之后,需要将数据交付给指定的进程
前面说过进程间通信的本质是看到同一份资源,现在这个资源就是网络,而通信的本质就是 IO,因为我们上网的行为就两种情况:
- 把数据发送出去
- 接收到数据
标识一个进程有 pid,为什么还需要端口号呢?
- 首先 pid 是系统规定的,而 port 是网络规定的,这样就可以把系统和网络解耦
- port 标识服务器的唯一性不能做任何改变,要让客户端能找到服务器,就像 110,120 一样不能被改变,而 pid 每次启动进程,pid 就会改变
- 不是所有的进程都需要提供网络服务或请求(不需要 port),但每个进程都需要 pid
虽然一个端口号只能绑定一个进程,但是一个进程可以绑定多个端口号,前面说了有源 IP 和目的 IP,而这里的 port 也有源端口号和目的端口号,我们在发送数据的时候也要把自己的 IP 和端口号发送过去,因为数据还要被发送回来,所以发送数据时一定会多出一部分数据(以协议的形式呈现)
如何理解源端口号和目的端口号:
传输层协议( TCP 和 UDP) 的数据段中有两个端口号 , 分别叫做源端口号和目的端口号, 就是在描述 “ 数据是谁发的, 要发给谁”
三、 认识TCP与UDP 协议
我们用的套接字接口一定会使用传输层协议,不会绕过传输层去调用下面的协议
传输层的协议分为 TCP 协议和 UDP 协议
1. TCP 协议
TCP (Transmission Control Protocol 传输控制协议)的特点:
- 传输层协议
- 有连接(在正式通信前要先建立连接)
- 可靠传输(在内部帮我们做可靠传输工作)
- 面向字节流
2. UDP 协议
UDP (User Datagram Protocol 用户数据报协议)的特点:
- 传输层协议
- 无连接
- 不可靠传输(可能会出现网络丢包或数据包乱序、重复等问题)
- 面向数据报
传输层就是用来解决可靠性的一个协议。
那为什么 UDP 是不可靠传输的,而我们还要有这个协议呢?
在网络通信中,现在的主流网络出现丢包的概率并不大,即使出现了丢包的情况,在有些场景下也是可以容忍的
可不可靠在这里只是一个中性词,形容的是他们的特点,可靠性是需要付出大量的编码和数据的处理成本的,往往在维护和编码上都比较复杂,而不可靠没有成本,使用起来也简单。所以二者要分场景使用
四、网络字节序 (大小端问题)
- 小端:低权值的数放入低地址
- 大端:低权值的数放入高地址
我们已经知道, 内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分。
那么如何定义网络数据流的地址呢?(如果一个大端机用大端的方式发送数据到一个小端机,现在跨网络我们也不知道数据到底是大端和小端)
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存
- 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址
TCP/IP 协议规定:网络数据流应采用大端字节序,即低地址高字节,不管这台主机是大端机还是小端机,都会按照这个 TCP/IP 规定的网络字节序来发送/接收数据,如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可
为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
对于 IP,首先我们要先转成整数,再解决字节序的问题,系统提供了一次性的接口,能同时解决这两个问题:
对于端口号:
- h 表示 host,n 表示 network,l 表示 32 位长整数,s 表示 16 位短整数
- 例如 htonl 表示将 32 位的长整数从主机字节序转换为网络字节序,例如将 IP 地址转换后准备发送
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回
四、socket 套接字
前面我们知道,IP + 端口号 port 标识了全网唯一的进程,我们把 IP + port 就叫做套接字socket
套接字(Socket)是计算机网络编程中用于实现网络通信的一个抽象概念。它提供了一种编程接口,允许不同计算机之间通过网络进行数据传输和通信。具体来说,套接字可以看作是通信的两个端点,一个是服务器端的套接字,另一个是客户端的套接字。通过套接字,服务器端和客户端可以相互发送和接收数据
在网络通信中,套接字使用网络协议(如 TCP/IP、UDP 等)来完成数据的传输和通信。根据所使用的网络协议的不同,套接字可以分为两种类型:
- 流套接字(Stream Socket,也称为面向连接的套接字):基于 TCP 协议,提供可靠的、面向连接的通信。使用流套接字时,数据可以按照发送的顺序和完整性进行传输,确保数据的准确性。流套接字的通信方式类似于电话通信,需要在通信前先建立连接
- 数据报套接字(Datagram Socket,也称为无连接的套接字):基于 UDP 协议,提供不可靠的、无连接的通信。使用数据报套接字时,数据以数据包的形式进行传输,不保证数据的顺序和完整性。数据报套接字适用于一次性发送不需要可靠传输的数据
1. socket 常见 API
(1)socket
创建 socket 文件描述符(TCP/UDP, 客户端 + 服务器)
(2)bind
绑定端口号( TCP/UDP, 服务器)
(3)listen
开始监听 socket(TCP, 服务器)
(4)accept
接收请求( TCP, 服务器)
(5)connect
建立连接( TCP, 客户端)
2. sockaddr 结构
socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如:IPv4、IPv6,以及后面要讲的 UNIX Domain Socket。然而,各种网络协议的地址格式并不相同
套接字有不少类型,常见的有三种:
- 原始 socket
- 域间 socket
- 网络socket
三种应用场景:网络套接字主要运用于跨主机之间的通信,也能支持本地通信,域间套接字只能在本地通信,而原始套接字可以跨过传输层(TCP/IP 协议)访问底层的数据
为了方便,设计者只使用了一套接口,这样就可以通过不同的参数来解决所有的通信场景。这里举两个具体的套接字类型:sockaddr_in 和 sockaddr_un:
可以看到 sockaddr_in 和 sockaddr_un 是两个不同的通信场景,区分它们就用 16 地址类型协议家族的标识符
但是,这两个结构体都不用,我们用 sockaddr
比方说我们想用网络通信,虽然参数是 const struct sockaddr *addr,但实际传递进去的却是 sockaddr_in 结构体(注意要强制类型转换)
在函数内部一视同仁,全部看成 sockaddr 类型,然后根据前两个字节判断到底是什么通信类型然后再强转回去。可以把 sockaddr 看成基类,把 sockaddr_in 和 sockaddr_un 看成派生类,实现了C语言式的多态
五、总结
IP+port
可以标志全网唯一进程- 套接字是一种通信机制(通信的两方的一种约定),而套接字的表示形式:
IP+port
。 - TCP和UDP的主要区别就是可靠传输和不可靠传输,而可不可靠是中性词。
- 网络字节序列简单粗暴的规定为大端。
- sockaddr用统一的接口方式来解决网络通信的大部分问题
- Socket可以看成在两个程序进行通讯连接中的一个站点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中