当前位置: 首页 > article >正文

[网络] 网络基础概念--socket编程预备

文章目录

    • 1. 理解 ip 地址和目的 IP 地址 -> 区分主机唯一性
    • 2. 认识端口号
    • 3. socket 套接字
    • 4. 传输层的代表协议 -> `tcp` & `udp`
    • 5. 网络字节序列 -> 大端序列
    • 6. socket 编程接口

  继前文, 前文提到了网络传输的基本流程, 那下面我们继续来讨论一点关于网络基础概念的东西, 我们下一步要开始写简单的网络代码了, 因此我们这一节就为下一节的网络编程做筹备 -> 网络基础概念–socket编程预备.

1. 理解 ip 地址和目的 IP 地址 -> 区分主机唯一性

IP 在网络当中, 用来标识主机的唯一性.
  是的, 我们就是用两个不同的 ip 地址来标识两台在网络当中不同的主机来进行网络通信的.

2. 认识端口号

  思考: 数据传输到主机是目的吗? 不是的. 因为数据目的不是给机器看的, 是要给人看的, 所以说发数据给主机是一种手段.
  而人怎么看聊条信息呢? 如何进行下载任务呢? 都是通过各种应用来做的, 所以说, 各种应用在系统的进程是人的代表.

结论: 数据传输到主机不是目的, 而是手段. 到达主机内部, 交给对应的进程才是目的(进程代表的就是人).

  但是一个系统内的进程是大量的, 那数据如何确定到达哪个进程呢? -> 网络视角上区分进程的唯一性 -> 我们引入端口号.

在这里插入图片描述
为了在任意一个主机内部, 标识进程的唯一性, 我们引入端口号.

  • 端口号是一个 2 字节 16 位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  • IP 地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  • 一个端口号只能被一个进程占用.
    这个很好理解的, 我们 port 是用来标识一个主机内唯一的一个进程的, 如果一个端口号同时被多个进程占用, 这肯定不唯一了吧!

  端口号是传输层的概念, 当数据报到达目标主机的传输层的时候, 传输层会根据提前封装好的端口号信息来给到对应的进程. 这就要求我们的特定软件绑定对应的端口号.

3. socket 套接字

  实际通信的是网络当中的两个进程, 为了区分主机和进程, 我们用 IP + PORT的形式来标识互联网当中唯一的一个进程, 对于目标进程也是同理.

结论: 网络通信的本质是进程之间的通信.

在这里插入图片描述
进程之间的通信需要两个条件:

  1. 两个进程独立 -> 当然独立
  2. 公共资源 -> 网络

  所以说, 网络通信对于进程之间的通信条件全部满足, 本质上, 网络通信就是一种进程间通信(只不过物理距离变长了~)

从今天开始, 我们称IP + PORT的这种网络通信方式称之为 socket 通信.
在这里插入图片描述

强调三个点:

  1. 通常来说, ip 的概念在网络层, port 的概念在传输层, 而 mac 地址的概念在链路层, 因此每一层都有对应的关键概念.
  2. 因此, 服务端启动的时候, 就一定要和一个 port 关联起来(不关联数据到了传输层, 系统如何清楚要交给哪个进程, 总不能让 qq 发的消息, 让微信来显示吧?)
  3. 在传输层咋不用进程 pid 标识进程的唯一性呢? -> 为了解耦, 一旦系统层面变了, 网络也必须改变! 当然, 还有比如进程的 pid 会变化, 以及端口号可以自己指定等等各种原因, 但是最本质的还是解开强耦合问题.
      系统当中, 并不是所有的进程都需要网络通信, 因此单独拿出一个 port 而非直接使用 pid 是十分合理的. -> 在学校咋不用身份证标识而是用学号呢?

端口号的划分范围:

  • 0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的.
    这个知名端口号类似 110 和警察的关系.
  • 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.
    一般来说我们用的是这个普通的端口号, 如果想要用知名端口号在云服务器上默认需要 root 权限才可以.

理解源端口号和目的端口号
  传输层协议(TCP 和 UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号.
  就是在描述 “数据是谁发的, 要发给谁”;

理解 socket

  • 综上,IP 地址用来标识互联网中唯一的一台主机,port 用来标识该主机上唯一的一个网络进程
  • IP+Port 就能表示互联网中唯一的一个进程
  • 所以,通信的时候,本质是两个互联网进程代表人来进行通信,{srcIp,srcPort ,dstIp,dstPort}这样的 4 元组就能标识互联网中唯二的两个进程
  • 所以,网络通信的本质,也是进程间通信
  • 我们把 ip+port 叫做套接字 socket

理解: 网络操作都被转换为IO 操作.

  所有的网络行为, 就俩行为 -> 封装一下自己的数据, 发到网络上, 或者从网络上拿到数据, 就这俩行为. 因此, 所有的网络行为就是输入和输出操作, 也基本就是我们的 IO 操作了, 一个主机输入, 一个主机输出, 网络联系两台主机, 基本算是一个 网络版的冯诺依曼体系结构.

4. 传输层的代表协议 -> tcp & udp

  如果我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的,那么我们要通过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的网络通信。
  解释一下网络协议栈: 为啥叫做栈呢? 这是因为整个 tcp/ip 协议是分层的, 数据包在整个过程中封装的时候都是"压入"报文, 解包的时候都是"弹出"报文, 很类似栈, 就叫做网络协议栈咯.
  说白了, 这句话就想表达一个事情: 程序员你想用网络通信? 那你得调用系统接口.

在这里插入图片描述

下面我们简单的认识一下传输层的两个典型的代表协议.

  • 认识 TCP 协议
    此处我们先对 TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识;后面我们再详细讨论 TCP 的一些细节问题.

    • 传输层协议
    • 有连接
    • 可靠传输
    • 面向字节流
  • 认识 UDP 协议
    此处我们也是对 UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.

    • 传输层协议
    • 无连接
    • 不可靠传输
    • 面向数据报

因为我们暂时还没有深入了解 tcp、udp 协议,此处只做了解即可.

兄弟们, 可能你们会有个疑惑, 就是整体解决这个长物理距离通信问题的解决方案叫做tcp/ip协议, 那这个传输层除了tcp咋还有个udp呢?
  这里咱们来解释一下, 就是tcp/ip协议这个名词表示的是整个网络问题的解决方案, 然后这个网络问题是很大的一个难题, 势必有很多的难题, 每个难题都对应一个小的解决方案, 这个小的解决方案可能就是我们具体的某种协议了, 比如说ip协议, tcp协议, udp协议… 之后呢, 我们的tcp/ip协议代表的是这些许多小方案的一个集合, 当然也就包含udp协议咯.

  上面我们仅仅是对这个传输层代表协议的两个典型协议做一个初步的认识, 在这里了解一下有这个东西即可.

然后, 我们来解释一下两个协议当中提到的"可靠 与 不可靠"的理解:
  兄弟, 你可不要误解 可靠当作是好的, 不可靠是不好的, 这两个词表示的是两种协议的一种性质, 特征, 可靠的含义是当发生数据丢包的情况时, 两种协议对数据丢包问题的解决方式, 可靠的就是去修补一些数据, 不可靠呢则直接对这个丢包不做处理, 但是这并不意味着一个好一个坏, 因为可靠 往往以为着需要做更多的工作, 而不可靠则相对简单.

5. 网络字节序列 -> 大端序列

  我们的数字是有高低权值位的. 比如int有4个字节. 在这里插入图片描述

  我们的电脑因为历史原因, 在数据存储上没有做到统一, 有的电脑是把数值高权值位放到高地址处, 低权值位放到低地址处(大端机), 有的电脑呢则把高权值位放到低地址处, 低权值位放到高地址处(小端机). 也就是大端机小端机的区别.
  兄弟们/姐妹们有没有想过一个问题, 就是一个大端机和一个小端机在跨网络通信的时候, 会不会造成数据解析错误的情况呢? 毕竟数据的存储方式不一样啊!
  实际上, 网络设计者早就想到了这个问题, 他们规定: 所有机器向网络传输数据时, 全部是大端字节序.
  有同学可能会好奇, 为啥不把自己的大小端信息放到数据报里向目标主机发送呢? 实际上我感觉这样做是可以的, 但是处理起来会很麻烦. 最典型的一个问题就是数据报需要解析吧? 数据报需要解析之前就得需要知道是大端还是小端, 但是想要知道大端还是小端, 就必须解析数据报, 这个类似于一个先有鸡还是先有蛋问题.

下面是一些解释:

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个 TCP/IP 规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;


  当然, 我们笔记本电脑通常就是小端机, 如果在编码时候还需要自己转换高低字节序是比较麻烦的, OS给我们提供了对应的转换接口:
在这里插入图片描述

  • 这些函数名很好记,h 表示 host,n 表示 network,l 表示 32 位长整数,s 表示 16 位短整数。
  • 例如 htonl 表示将 32 位的长整数从主机字节序转换为网络字节序,例如将 IP 地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

6. socket 编程接口

常用的 socket 编程接口一览:

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
// 开始监听 socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

我们这些接口也有一些内容, 我们放到一下节编码的时候再去介绍各个接口的用法.

  socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如 IPv4IPv6,以及后面要讲的 UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同.
  socket 通信也是一种进程间通信, 他既可以网络通信和本地通信.

在这里插入图片描述

  • 解释第二个结构体: Pv4IPv6 的地址格式定义在 netinet/in.h 中,IPv4 地址用 sockaddr_in 结构体表示,包括 16 位地址类型, 16 位端口号和 32 位 IP 地址… IPv4IPv6 地址类型分别定义为常数 AF_INET, AF_INET6. 这样,只要取得某种 sockaddr 结构体的首地址,不需要知道具体是哪种类型的 sockaddr 结构体,就可以根据地址类型字段确定结构体中的内容.
  • 第一个结构体干啥的? socket API 可以都用 struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收 IPv4, IPv6, 以及 UNIX DomainSocket 各种类型的 sockaddr 结构体指针做为参数; -> 这仨玩意类似于一种多态的关系!
  • 解释第三个结构体: 第三个结构体是用于本地进程间通信的一个结构体, 这个类似于我们之前学过的"命名管道". sockaddr_un 是类似于一种命名管道的东西.

问题: 上面的接口咋不用 void而是 sockaddr 呢?
答: 因为历史原因, 并且本身也没啥问题, 写法上需要用到强制转换就是了~

好的, 本节就暂时介绍到这里, 我们下一节开始进入网络编码阶段~


http://www.kler.cn/a/586923.html

相关文章:

  • Ubuntu 24 常用命令方法
  • 【Git】配置Git
  • 按钮权限的设计及实现
  • uniapp-x vue 特性
  • 在线 SQL 转 SQLAlchemy:一键生成 Python 数据模型
  • AcWing--870.约数个数
  • Windows环境下安装部署dzzoffice+onlyoffice的私有网盘和在线协同系统
  • Java中的I/O
  • 通过qemu仿真树莓派系统调试IoT固件和程序
  • 深度解析国产推理大模型DeepSeek:从入门到本地化部署!
  • C++Primer学习(7.1 定义抽象数据类型)
  • FPGA为何要尽量减少组合逻辑的使用
  • 人工智能与人的智能,改变一生的思维模型【8】逆向思维
  • 国家网络安全事件应急预案
  • DC-6靶机详解
  • Vue3 Pinia $subscribe localStorage的用法 Store的组合式写法
  • 基于变分推理与 Best‑of‑N 策略的元 Prompt 自动生成与优化框架
  • 《Python实战进阶》No24: PyAutoGUI 实现桌面自动化
  • Spring Cloud LoadBalancer 原理与实践
  • unity基础——线段与拖尾