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

网络基础——Socket编程预备

文章目录

  • Socket编程预备
    • 网络通信的本质
    • 认识端口号Port
      • 端口号的大致使用流程
      • 端口号的划分
      • port vs pid
      • 理解socket(套接字)
    • 传输层的代表——TCP、UDP
      • 认识协议
      • 对比差别
    • 网络字节序
      • 大小端存储问题
      • 字节序问题
      • 大小端转化接口
    • Socket编程接口初步认识(宏观)
      • Socket常见API
      • sockaddr结构

Socket编程预备

有了对网络工作的整体认识,现在我们需要了解一下关于网络编程需要知道的话题!能够以方便我们后序快速上手编写代码!

网络通信的本质

我们已经知道了网络传输的基本流程!但是,网络通信的目的仅仅是为了传输吗?
答案是当然不是,网络通信只是手段!真正要通信的是人!人需要收发、处理数据!

所以,网络、计算机都是工具!是人使用它们来进行通信的!但是,我们用户是以什么样的方式来使用计算机的资源的呢?


其实早有讲过,我们用户只要是使用资源,都是通过进程作为载体的!
我们使用的操作,最终在操作系统看来,都是一个个的进程!

所以,未来我们看待网络通信的时候(比如正在使用一个软件):
我们要在客户端发送数据,本质上就是把数据交付给对应进程,然后网络传输发送给服务器端的进程!所以,上网只有两种行为:

1.从远端服务器获取数据
2.将本地数据发送到远端服务器

在这里插入图片描述

所以,最终对于网络通信而言:
只不过是两台不同的主机在进行进程间通信!进程通信需要看到同一份资源!
而在不同主机下的看到资源的方式就是通过网络!

认识端口号Port

网络通信,本质上是不同主机中的两个进程在做异地进程间通信!
现在会很自然的提出一个问题:

一台主机下是有很多的进程在同时运行的!那么,如何确定要通信的进程呢?
即怎么确保数据一定能够正确地交付给指定的进程?

在这里插入图片描述
如上图所示:
因为存在着多个进程,对方发送来的数据被网卡接收后,需要经过解包分用向上传递。但是,传递到传输层的时候,如何传给指定的进程呢?

这也就意味着:
需要有一种解决方案,能够正确解决识别进程!也就是说,这种方案需要具有唯一性!
在网络协议栈的传输层中,使用端口号来实现的!

端口号(port)是传输层协议的内容

  • 端口号是一个 2 字节 16 位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  • IP 地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  • 一个端口号只能被一个进程占用

端口号的大致使用流程

我们大致用下面一张图来解释!
在这里插入图片描述

即网卡接收到了对应的数据报文的时候,向上解包分用。
一些进程是需要进行网络通信的,所以会绑定一个端口号!然后,数据报解包到网络层的时候,因为需要交付给正确进程,所以会带有该进程需要的端口号!
到了传输层的时候,就会根据这个端口号在hash表内进行索引,找到对应的进程!

所以,如果需要通信,就需要说明几个重要内容:

1.源IP地址 + 源端口号
2.目标IP地址 + 目标端口号

最后,如果不同的主机需要进行通信,就需要表明通信的IP地址 + 对应的端口号

端口号的划分

  • 0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 端口号都是固定的.
  • 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 由操作系统从该范围分配的.

有些端口号是不能绑定的!因为它们已经被固定了!就像我们生活中一样,电话号码有些是固定的!如110,119,10086...
因为它们绑定的是固定的服务!就和这里的0 - 1023端口号一样!

这里还需要说一点注意事项:
一个端口号只能绑定一个进程,这个是毋庸置疑的!因为要标识进程的唯一性!
但是,一个进程可以绑定不止一个端口号!只需要保证端口号检索进程的方向唯一即可。

这个就和我们学习数学上的函数概念类似:
一个自变量只能映射一个值,但是一个值可能会被多个自变量映射!

有一些特殊的服务可能会绑定多个端口号,这点我们需要注意!

port vs pid

其实我们肯定是会有疑问的:
系统内标识进程的唯一性不是已经有进程的pid了嘛?为什么还要搞一套端口号出来呢?

这个问题其实非常好理解,将分为以下几点:
1.并不是所有的进程都需要进行网络通信!
2.从技术角度上来说可行!但是,这必然会导致网络部分的代码和系统部分的代码强耦合!

主要基于以上的两点,所以就没有直接使用pid作为网络通信中标识进程唯一性的标志!

其实最重要的原因就是,需要进行解耦合!万一关于进程部分的代码修改过了,那么就必然需要修改网络的代码,这在工程开发中是需要避免的!

理解socket(套接字)

最后,我们已经明白一个道理,即在网络通信中:
标识进程唯一性的方法就是:主机IP + 端口号

所以,通信的时候,本质是两个互联网进程代表人来进行通信,{srcIP,srcPort,dstIP,dstPort}这样的 4 元组就能标识互联网中唯二的两个进程!

在网络通信中,socket(套接字) = 主机IP + 端口号

socket
n. (电源)插座;(电器上的)插口,插孔,管座;槽;窝;托座;臼;孔穴
vt. 把…装入插座;给…配插座

英文解释中,这个单词是插座的意思!其实是比较形象的。因为网络通信就是相当于两边通过主机IP + 端口号来进行进程身份的确认!确认了就能通信!就和插座插头相连接就使用电力一样!只不过翻译到国内教材上,习惯叫作套接字!

所以,未来学习网络的通信中,使用的就是socket编程!

传输层的代表——TCP、UDP

认识协议

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

• 传输层协议
• 有连接
• 可靠传输
• 面向字节流

认识 UDP 协议
此处我们也是对 UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.

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

因为我们目前还没有办法深入理解 tcp、udp 协议,此处只做了解即可。

对比差别

最直观的就是,这两个协议都是处在传输层的!即负责传输数据!

TCP需要进行连接、但是UDP不需要!即前者需要确认对方能接收才发,后者是不管对方状况如何,直接把数据进行传输!(前者是电话,后者像是对讲机)


对于可靠性的解释,这里最大的区别就是:
TCP协议是会做很多处理,如果数据丢了会重发,即可靠!但是UDP则不会!UDP是直接进行发送,而且不会处理丢包地数据!这叫做不可靠!

但是,这里的可靠不可靠,不能当成缺点,而是特点!

因为,TCP会对数据包进行检测,丢包就要重发。前面也说到,它要建立连接。UDP则简单得多。这就导致,在代码实现上,TCP肯定是比UDP复杂的多的!
如果说一个设备内所有进程都通过TCP协议来进行接收数据,这会导致服务器压力过大!所以,只有在一些比较重要的数据传输情况下使用TCP(如银行数据流水.),但是像是直播、视频通话这种,如果使用TCP压力过大。所以是允许丢几个包的!因为无伤大雅!


最后一个就是二者面向数据的不同之处!一个面向字节流,一个面向数据报!
字节流就像自来水传输,传输到我们这里,我们都是一次性进行接收指定量的!
但是数据报就像收快递,必须是一个一个的包裹送达!

其实我们在学习文件系统调用接口的使用就已经谈到了这个概念了!

本质上都是面向字节流(二进制数据)!只不过说:
TCP协议底层隐藏了数据报的形式,边界隐藏!
UDP协议强制保留了数据报的边界形式!


最后,我们还会有一个疑问:为什么一层中要出现两个协议呢?直接用不好吗?
这个问题其实回答过了!两种协议特点不同,需要根据不同场景来选择应用!

网络字节序

大小端存储问题

我们知道,本质上传输数据,都是二进制数据!这里就面临着一个问题:
不同的机器,很可能存储数据的方式不同——大小端问题!

假设有一个数据0x123456aa
这个时候,高权值位在前,低权值位在后(就如1234十进制一样,前面的位大)
权值由高到低 : 0x12 0x34 0x56 0xaa


低地址 ------------------------>高地址
0xaa 0x56 0x34 0x12 -> 小端存储
0x12 0x34 0x56 0xaa -> 大端存储

记忆口诀:小小小 -> 小地址,小权值,小端机,反之为大端!

字节序问题

因为早期的时候,不同的厂家对于数据的存储没有做要求,就导致了市面上大小端的存储方式都有,都还挺多的!

但是,这在网络通信中会导致一个问题:
在这里插入图片描述

所以,必须有相关的解决方案!
所以,TCP/IP协议就规定,凡是入网的通信的数据,一律转化为大端!
这里为什么是大端没有具体理由,而且是大端小端无所谓!重要的是要有这么个协议!

对于发送的主机而言: 如果是小端,那就需要转化为大端发送;反之忽略
对于接受的主机而言: 如果是小端,那就需要接收后化为小端,反之忽略

大小端转化接口

其实,我们自己也可以手动做大小端转化!但是这非常麻烦,所以工程师就设计了一套接口:

在这里插入图片描述

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

Socket编程接口初步认识(宏观)

Socket常见API

// 创建 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);

当然,这里我们只是看一下,了解一下。这里先不介绍接口的使用!

sockaddr结构

这里我们需要先介绍一下关于这些API中的一个结构:sockaddr

首先,socket通信是隶属于POSIX标准的!我们之前又学过POSIX标准的通信!也就是说,POSIX标准既可以本地通信!又可以网络通信!

像是system V标准下,不同的通信方式就有不同的接口!这是很好理解的。但是,设计socket的工程师不想这样,他们希望能够使用一个统一的接口来完成这些工作!


当socket使用本地通信的时候:
在这里插入图片描述
就是用struct sockaddr_un来进行操作!这个结构体会指向本地通信的方法,即打开同一个文件,让进程都看到!然后进行通信!这不就和管道类似嘛?

当使用网络通信的时候:
在这里插入图片描述
就是用struct sockaddr_in来进行操作。


这里我们先不管具体是如何通信的,我们就来看这两个结构体的头部:
都是一个16位的地址类型,用于标识自己是哪一种通信方式的结构体!

但是,在socket的相关API中,并没有这两个结构体!这是因为,工程师们又设计了一个机构体sockaddr:
在这里插入图片描述
其头部也是一个16位地址类型。

这样子,传参的时候就直接把对应通信类型的结构体做强转即可!在API内部,因为传进来的结构体头部都是16位地址类型,所以判断一下是哪一种,就执行哪种通信方式即可!

这不就是c语言方式实现的继承和多态吗?通过这样的方式,就可以实现一个接口来使用不同的通信方式了!这十分好理解!


这里提一点:
肯定会有疑问:为什么不用void*进行接受呢?
答案:设计这个标准的时候,void*对应的语法还没有出来!后来也没必要再改了,因为没有必要!现在这样反而能看出继承体系!

http://www.dtcms.com/a/338524.html

相关文章:

  • 专题:2025母婴行业消费洞察与分龄营养趋势报告|附40 +份报告PDF、交互图表数据汇总下载
  • MongoDB知识速查
  • uni-app页面使用u-view组件简化版列表页+详情页实现
  • 【最新版】CRMEB Pro版v3.4系统源码全开源+PC端+uniapp前端+搭建教程
  • Selenium自动化测试入门:cookie处理
  • C语言实战:从零开始编写一个通用配置文件解析器
  • Docker+Nginx+Node.js实战教程:从零搭建高可用的前后端分离项目
  • 阿里云参数配置化
  • Apache Doris 4.0 AI 能力揭秘(一):AI 函数之 LLM 函数介绍
  • Python训练营打卡 DAY 41 简单CNN
  • Apache IoTDB 大版本升级记录(成熟的2.0.2版本)
  • 100202Title和Input组件_编辑器-react-仿低代码平台项目
  • AI 小游戏批量生产工厂(Deepseek深度推理reasoner模型64K tokens)
  • 如何计算 PCM 音频与 YUV/RGB 原始视频文件大小?
  • Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
  • 在相机空间中落地动作:以观察为中心的视觉-语言-行动策略
  • OpenHarmony之打造全场景智联基座的“分布式星链 ”WLAN子系统
  • 如何理解关系型数据库的ACID?
  • 【技术揭秘】AI Agent操作系统架构演进:从单体到分布式智能的跃迁
  • Android 数据可视化开发:从技术选型到性能优化
  • 在 Cursor 、 Vscode 中配置 SFTP 实现安全的手动文件上传
  • 利用解优化问题解欠定方程组
  • Redis缓存加速测试数据交互:从前缀键清理到前沿性能革命
  • OpenCV计算机视觉实战(20)——光流法运动分析
  • 云手机矩阵:重构企业云办公架构的技术路径与实践落地
  • 亚矩阵云手机智能定位:助力Snapchat矩阵账号的本地化内容运营穿透技术
  • MySQL实战45讲 24-25
  • Commons-io
  • Web11-Java Web服务:使用SOAP与RESTful API
  • 网络编程day3