socket编程基础

上一篇 --- 网络基础概念(下)https://blog.csdn.net/Small_entreprene/article/details/147320155?fromshare=blogdetail&sharetype=blogdetail&sharerId=147320155&sharerefer=PC&sharesource=Small_entreprene&sharefrom=from_link

理解源IP地址和目的IP地址

在我们当前的认识当中,IP地址是用来标识主机的唯一性的,后面我们会详细的对IP进行分类。

数据传输到主机并不是最终目的,因为数据是给人使用的。例如,聊天是人在聊天,下载是人在下载,浏览网页是人在浏览。那么,人是如何看到聊天信息、执行下载任务以及浏览网页信息的呢?答案是通过启动的 QQ、迅雷、浏览器等软件。而这些启动的 QQ、迅雷、浏览器等都是进程。换句话说,进程是人在系统中的代表,只要把数据交给进程,人就相当于拿到了数据。

因此,数据传输到主机只是手段,而不是目的。真正的目的是将数据传输到主机内部,并交给主机内的目标进程。

我们上网,其实可以概括成两种行为:

  1. 从远端服务器,获取数据(刷抖音,其实就是将抖音推送到手机端)
  2. 本地数据,上传到远端服务器 (登入,将账号密码推送到远端;上传文件到百度网盘)

不管我们的上网行为有多么丰富多样,在技术角度也就只有两种情况,一种上传,一种下载!因为我们的数据是通过进程来做的,进程又是在内存当中的,上网的时候,所有的数据都是要经过网卡的,而网卡需要将数据给网络。(是进程和网卡之间的关系,网络和网卡的关系)

我们将上面两者两者之间的关系叫做IO!!! 说白了:冯诺依曼体系结构规定,网卡只能进行IO操作,就决定了我们的应用层软件上,只能做获取信息和发送信息的行为。

说明了网络通信的本质就是两个不同主机的进程在进行数据交互,更本质就是进程间通信!

进程间通信的本质就是要看到同一份资源,那么两个不同主机的进程要看到的同一份资源又是谁呢?就是网络!!! (今天只是从在同一台主机内进行进程间通信换成了在不同的两台主机间进行进程间通信而已)

我们现在知道,数据传输到主机只是手段,而不是目的。真正的目的是将数据传输到主机内部,并交给主机内的目标进程。然而,在系统中,同时会存在非常多的进程。因为收到的数据是要分配给一个或多个进程的,哪些数据对应哪一个进程,那么当数据到达目标主机之后,如何将数据转发给目标进程呢?这需要在网络的背景下,通过某种方式在系统中标识主机的唯一性,从而确保数据能够准确地被转发到目标进程。

 我们主机会收到来自远端主机发送来的各种数据,这些数据需要按照对应不同的数据分发到对应的进程当中,所以我们就必须要在系统层面上有一种办法来标识主机的唯一性,为了能够实现主机唯一性的标识,我们在网络的范畴当中,我们就引入了新的概念:端口号!

认识端口号

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

  • 端口号是一个2字节16位的整数。

  • 端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理。(也就是说,未来写的网络服务,比如说QQ,这个网络服务要进行启动的时候,需要通过操作系统提供的一些系统调用来让这个进行和对应的端口号(在传输层提取报文中的目的端口号)产生对应的关联)

  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程。

  • 一个端口号只能被一个进程占用。(就是端口号可以用来标识系统中唯一的一个网络进程!!!)(其实反过来,一个进程是可以和多个端口号进行绑定的,因为我们要的是从端口号查进程的方向是唯一的)

网络通信的本质是全网范围内唯二的两个进程在进行进程间通信!!!我们用对方的IP和Port标识对方的唯一性。我们将IP+Port称为Socket(套接字)

不过,端口号端口号可以用来标识系统中唯一的一个网络进程,但是我们学习过,pid也是进程的唯一标识,那为什么不直接用进程pid呢?

不是所有的进程都需要进行网络通信,不过我们从技术角度上来说,使用pid不使用端口号,这是可行的,但是pid是一个系统的概念,如果未来pid这个概念变化了,伴随着网络就需要变,这就是耦合性差,使用端口号就可以进行解耦!!!


端口号的范围划分是【0,65535】,因为是一个两字节(16比特位)的整数

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

传输层协议(TCP 和 UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号,就是在描述“数据是哪台主机的哪一个进程发的,要发给哪台主机上的哪一个进程”。


理解socket

综上,IP 地址用来标识互联网中唯一的一台主机,port 用来标识该主机上唯一的一个网络进程。

  • IP + Port 就能表示互联网中唯一的一个进程。

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

  • 所以,网络通信的本质,也是进程间通信。

  • 我们把 ip + port 叫做套接字 socket。


传输层的典型代表

如果我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的。那么我们要通过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行网络通信。

传输层有两个重要协议:TCB和UDP。 

认识 TCP 协议

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

  • 传输层协议

  • 有连接:在数据传输之前,需要先建立连接。(打电话,你喂我喂的过程就是建立连接的过程)

  • 可靠传输:保证数据的完整性和顺序性,通过确认和重传机制确保数据可靠传输。

  • 面向字节流:数据以字节流的形式传输,不保留消息边界。(自来水,怎么接,接多少,都是自己自主决定的;文件打开也叫文件流,字节流和文件流没有区别,都是流式的;学习完自定义协议后我们就能理解了)

认识 UDP 协议

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

  • 传输层协议

  • 无连接:不需要建立连接,直接发送数据。(对讲机)

  • 不可靠传输:不保证数据的完整性和顺序性,数据可能丢失或乱序到达。

  • 面向数据报:数据以数据报的形式传输,保留消息边界。(发快递,发几个就只能几个)

TCP是可靠的,丢包了可以再发,但是UDP不可靠,那为什么还要保留UDP呢?(属于同层协议,但是还保留一个不可靠的???)

我们要注意,这里的可靠和不可靠不可以将其视为贬义词,而是一种中性词,是一种特点。TCP保证可靠性,意味着他一定要做更多的工作,也就是意味着TCP协议会更加复杂一些,复杂带来的就是占有资源会比较多。UDP协议就会很简单,简单的话就是代表开发周期短,可维护性好。

因为我们暂时还没有深入了解 TCP 和 UDP 协议,此处只做了解即可。


网络字节序

我们以前学过,计算机在存储数据的时候,是有大端和小端的,大小端是按照字节为单位的。

大端(Big-Endian)

定义:大端字节序是指高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。

 假设有一个32位的整数 0x12345678,在大端字节序下,它在内存中的存储顺序如下:

内存地址: 0x00  0x01  0x02  0x03
存储内容: 12    34    56    78
  • 0x12 存储在最低地址 0x00

  • 0x78 存储在最高地址 0x03

小端(Little-Endian)(小-小-小)

定义:小端字节序是指低位字节存放在内存的低地址端,高位字节存放在内存的高地址端。

假设有一个32位的整数 0x12345678,在小端字节序下,它在内存中的存储顺序如下:

内存地址: 0x00  0x01  0x02  0x03
存储内容: 78    56    34    12
  • 0x78 (低权值位:就是16的几次方)存储在最低地址 0x00

  • 0x12 存储在最高地址 0x03

#include <stdio.h>// 函数:将整数从当前字节序转换为网络字节序(大端)
unsigned int htonl(unsigned int hostlong) {unsigned char *bytes = (unsigned char*)&hostlong;return ((unsigned int)(bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
}int main() {unsigned int x = 1;if (*((char *)&x) == 0) {printf("大端(Big-Endian)\n");} else {printf("小端(Little-Endian)\n");printf("转换前的值:%u\n", x);// 调用 htonl 函数将整数转换为大端字节序x = htonl(x);printf("转换后(大端)的值:%u\n", x);}return 0;
}

如果今天主机A是小端存储,主机B是大端存储,两台主机间要进行网络通信,A将数据发送给B的话,主机B就解释反了。所以在网络当中,两台主机,如果主机间的存储序列不同的话,经过网络通信,会导致对方将接收到的数据解释错了!

所以在网络中就有规定:凡是将数据发送到网络当中的话,一定是要按照大端的形式发送!

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

为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

  • 这些函数名很好记,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);

这些API的详细细节我们会在后续写代码的时候进行说明。

我们发现大部分的接口参数中都有const struct sockaddr*的结构体指针(其他暂时不关心)

下面,我们来聊一聊这个sockaddr这个结构体。

sockaddr结构体

我们现在清楚,网络通信的本质其实是进程间通信,我们之前学习的system V这个标准属于本地之间进行进程间通信,我们后面还会见到的POSIX标准,这个是主要用于网络通信的,网络通信也是进程通信,也能进行本地通信的,也就是为什么我们之前说System V版本的进程间通信被淘汰了,因为POSIX这套标准,我们直接就可以进行了,还顺带了网络通信。

socket套接字会有许多不同的种类来满足各种各样的不同的应用场景--网络socket/本地socket(unix域间通信)/原始socket,原始socket我们不需要考虑,未来我们只需要学懂网络socket,本地socket我们自然而然也就清楚了。也是正因为有不同的场景的socket,我们socket未来的接口,也是会有不同的通信接口规范(网络的一套,本地的一套......)但是socket的设计者并不想这么干,只想要提供一套通信接口!!!(这一套既可以做网络通信,也可以做本地通信)

所以就需要对接口进行设计,为了能够支持设计出来的接口可以进行不同种类的通信,就设计了一个结构体---sockaddr结构体!

  • 通用性struct sockaddr 提供了一个通用的接口,适用于各种网络协议。

  • 专用性struct sockaddr_instruct sockaddr_un 分别针对IPv4网络通信和本地通信进行了优化,提供了必要的信息和灵活性。

在网络编程中,sockaddr 结构体及其相关的结构体如 sockaddr_insockaddr_un 经常需要进行强制类型转换。这是因为 sockaddr 是一个通用的地址结构体,设计用来支持多种不同的网络协议和地址类型。而 sockaddr_insockaddr_un 是针对特定协议(如IPv4、IPv6和UNIX域套接字)的具体实现。

当你需要将 sockaddr_insockaddr_un 结构体传递给需要 sockaddr 类型参数的函数时,通常需要进行强制类型转换。例如,在调用 bind()connect() 函数时,你需要将 sockaddr_in 结构体的地址转换为 sockaddr 类型的指针。

这样做的原因是因为 sockaddr 结构体定义了一个通用的接口,它包含了一个地址族字段(sa_family),用于指示地址的具体类型。sockaddr_insockaddr_un 结构体都以这个地址族字段开始,但它们包含的地址信息不同。通过将它们转换为 sockaddr 类型,你可以确保函数能够正确识别和处理不同类型的地址。

至于为什么不将参数设置为 void*,原因在于 void* 类型虽然可以指向任何类型的数据,但它不提供足够的信息来处理不同协议的地址。使用 sockaddr 类型及其派生的结构体可以提供必要的语义信息,使函数能够根据地址类型字段来正确处理地址数据。此外,原始套接字API是在1983年发布的,早于1989年的ANSI C标准,其前身——K&R C——根本没有 void *,所以您无论如何都必须将其转换为某个东西。

其实本质就是继承和多态:(C语言实现的)



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS 解决手机浏览器默认行为(点击出现蓝色背景)

最近写了一个 Web 应用&#xff0c;可以兼容手机端和PC端&#xff0c;在PC端调试的时候没有发现这个问题&#xff0c;但是在手机上或者PC浏览器改成手机模式进行调试的时候就会出现下面这个场景&#xff1a; 这是两个 div&#xff0c;点击的时候&#xff0c;会出现一个蓝色的背…

多模态大语言模型arxiv论文略读(三十八)

Tables as Texts or Images: Evaluating the Table Reasoning Ability of LLMs and MLLMs ➡️ 论文标题&#xff1a;Tables as Texts or Images: Evaluating the Table Reasoning Ability of LLMs and MLLMs ➡️ 论文作者&#xff1a;Naihao Deng, Zhenjie Sun, Ruiqi He, A…

聊聊Spring AI Alibaba的YuQueDocumentReader

序 本文主要研究一下Spring AI Alibaba的YuQueDocumentReader YuQueDocumentReader community/document-readers/spring-ai-alibaba-starter-document-reader-yuque/src/main/java/com/alibaba/cloud/ai/reader/yuque/YuQueDocumentReader.java public class YuQueDocument…

OCR定制识别:解锁文字识别的无限可能

OCR 定制识别是什么&#xff1f; OCR&#xff0c;即光学字符识别&#xff08;Optical Character Recognition&#xff09; &#xff0c;它就像是一个神奇的 “文字翻译器”&#xff0c;能把图片里的文字转化成计算机可编辑的文本。比如&#xff0c;你扫描一份纸质文档成图片&am…

麒麟系统(基于Ubuntu)上使用Qt编译时遇到“type_traits文件未找到”的错误

在麒麟系统&#xff08;基于Ubuntu&#xff09;上使用Qt编译时遇到“type_traits文件未找到”的错误&#xff0c;通常是由于C标准库头文件缺失或项目配置问题导致的。以下是逐步解决方案&#xff1a; 1. 安装C标准库和开发工具 确保系统已安装完整的开发工具链和标准库&#…

服务器上安装node

1.安装 下载安装包 https://nodejs.org/en/download 解压安装包 将安装包上传到/opt/software目录下 cd /opt/software tar -xzvf node-v16.14.2-linux-x64.tar.gz 将解压的文件夹移动到安装目录(/opt/nodejs)下 mv /opt/software/node-v16.14.2-linux-x64 /opt/nodejs …

Vue3 + Vite + TS,使用 ExcelJS导出excel文档,生成水印,添加背景水印,dom转图片,插入图片,全部代码

Vue3 Vite TS,使用 ExcelJS导出excel文档&#xff0c;生成水印&#xff0c;添加背景水印&#xff0c;dom转图片&#xff0c;插入图片&#xff0c;全部代码 ExcelJS生成文档并导出导出表头其他函数 生成水印设置文档的背景水印dom 转图片插入图片全部代码 ExcelJS 读取&#…

devops自动化容器化部署

devops 一、简单案例体验gitlabrunner部署静态文件二、devops企业级部署方案1、流程图2、依赖工具3、流程图4、主机规划5、安装工具软件1、安装git2、安装gitlab3、安装jenkins-server4、安装harbor5、安装web-server&#xff0c;也就是部署服务的机子&#xff0c;需要安装dock…

高级 SQL 技巧:提升数据处理能力的实用方法

在数据驱动的时代,SQL 作为操作和管理关系型数据库的标准语言,其重要性不言而喻。基础的 SQL 语句能满足日常的数据查询需求,但在处理复杂业务逻辑、进行数据分析和优化数据库性能时,就需要掌握一些高级 SQL 技巧。这些技巧不仅能提高查询效率,还能实现复杂的数据处理任务…

21.disql命令登录达梦数据库,查询并操作数据库

目录 1.连接达梦数据库 1.1 windows或linux系统 步骤&#xff08;1&#xff09;&#xff1a;打开终端窗口 步骤&#xff08;2&#xff09;&#xff1a;进入梦数据库安装目录下的 bin 文件夹 步骤&#xff08;3&#xff09;&#xff1a;用disql命令进行登录 1.2 docker部署…

N8N MACOS本地部署流程避坑指南

最近n8n很火&#xff0c;就想在本地部署一个&#xff0c;尝尝鲜&#xff0c;看说明n8n是开源软件&#xff0c;可以在本地部署&#xff0c;于是就尝试部署了下&#xff0c;大概用了1个多小时&#xff0c;把相关的过程记录一下&#xff1a; 1、基础软件包 abcXu-MacBook-m2-Air…

qt之开发大恒usb3.0相机一

1.在大恒相机给的sample里没有看见qt开发的demo. 第一步先运行c sdk中中的demo&#xff0c;看了下代码&#xff0c;大恒使用的UI框架是MFC.然后 vs2022编译。运行结果 第一步&#xff0c;先用qt进行坐下页面布局&#xff0c;如下图&#xff08;保存图片的地方做了些更改&#…

leetcode-枚举

枚举 3200. 三角形的最大高度 题目 给你两个整数 red 和 blue&#xff0c;分别表示红色球和蓝色球的数量。你需要使用这些球来组成一个三角形&#xff0c;满足第 1 行有 1 个球&#xff0c;第 2 行有 2 个球&#xff0c;第 3 行有 3 个球&#xff0c;依此类推。 每一行的球必…

DeepSeek智能时空数据分析(三):专业级地理数据可视化赏析-《杭州市国土空间总体规划(2021-2035年)》

序言&#xff1a;时空数据分析很有用&#xff0c;但是GIS/时空数据库技术门槛太高 时空数据分析在优化业务运营中至关重要&#xff0c;然而&#xff0c;三大挑战仍制约其发展&#xff1a;技术门槛高&#xff0c;需融合GIS理论、SQL开发与时空数据库等多领域知识&#xff1b;空…

如何用WordPress AI插件自动生成SEO文章,提升网站流量?

1. 为什么你需要一个WordPress AI文章生成插件&#xff1f; 每天手动写文章太耗时&#xff1f;SEO优化总是不达标&#xff1f;WordPress AI插件能帮你24小时自动生成原创内容&#xff0c;从关键词挖掘到智能排版&#xff0c;全程无需人工干预。 痛点&#xff1a;手动写作效率低…

鼠标指定范围内随机点击

鼠标指定范围内随机点击 点赞神器 将鼠标移动到相应位置后按F5 F6键&#xff0c;设置点击范围&#xff0c; F8开始&#xff0c;ESC中止。 有些直播有点赞限制&#xff0c;例如某音&#xff0c;每小时限制3千次&#xff0c;可以设置1200毫秒&#xff0c;3000次。 软件截图&#…

数据库设置外键的作用

数据库外键&#xff08;Foreign Key&#xff09;是关系型数据库中用于建立表与表之间关联关系的重要约束&#xff0c;其核心作用是确保数据的一致性、完整性和关联性。以下是外键的主要作用及相关说明&#xff1a; 1. 建立表间关联关系 外键通过引用另一张表的主键&#xff0…

发币流程是什么,需要多少成本?

这是一个专注于Web3相关开发的账号&#xff0c;具体会讲解步骤以及开发方案 偶尔会有科普&#xff0c;有兴趣的可以点右上角关注一下 发币&#xff08;发行数字货币&#xff09;的流程通常涉及技术实现、法律合规、经济模型设计等多个环节&#xff0c;以下是关键步骤的简要说明…

测试常用的Linux系统指令详解

为什么测试工程师需要掌握Linux命令&#xff1f; 在现代软件测试领域&#xff0c;约75%的服务端应用运行在Linux环境中&#xff0c;能够熟练使用Linux命令的测试工程师&#xff0c;其工作效率比仅依赖GUI工具的测试人员高出40%以上。本文将系统介绍测试工作中最实用的Linux命令…

Java学习手册:Web 安全基础

一、常见 Web 安全威胁 在 Web 开发中&#xff0c;安全问题至关重要。以下是一些常见的 Web 安全威胁&#xff1a; 1. SQL 注入 SQL 注入是一种攻击方式&#xff0c;攻击者通过在输入字段中插入恶意的 SQL 代码&#xff0c;从而操纵数据库。例如&#xff0c;假设有一个登录表…