【linux网络编程】| 网络套接字socket | 初识网络开发

        前言:本篇内容将要正式进入网络的编程当中。 本篇的目的是为了能够看完就可以上手写一些网络代码了。 但是本篇也并不会单纯的只讲接口, 前面还是会铺垫一些理论知识更好的认识网络传输。下面, 开始我们的学习吧!

        ps:本篇内容的某些接口不好理解,建议先认识一下ip以及网络协议分层这些网络基础知识再来学习。 

目录

网络协议栈

端口号 

socket 

 端口号 VS 进程PID

 绑定端口号

 udp和tcp

tcp——传输控制协议

udp——用户数据报协议

 网络字节序列

套接字编程的种类

 套接字接口

socket

 bind

recvfrom

sendto 

sockaddr

ip地址的整数与字符串转化

整数如何转化成字符串

如何字符串转整数

htons


网络协议栈

        我们进行网络通信的时候,我们可能会认为是两台机器在通信。 但是其实,当我们进行通信的时候, 就比如我们下载了一个抖音, 一个微信,一个qq。这些软件我们不去启动它, 我们的机器不耗费流量, 更不会通信。 当我们启动这些软件, 我们的机器才能够进行通信, 并且消耗流量, 这说明什么呢? ——这说明我们真正通信的是应用层, 是应用层想要通信, 然后推动者下层的机器(其实就是下层的操作系统)进行数据一层一层向下交付, 然后由以太网甚至经过路由器中转分发给目标主机。

        所以, 我们现在理解的是:

  •         网络协议中的下三层(传输, 网络, 数据链路), 主要解决数据安全可靠的送到远端机器。
  •         用户使用应用层软件, 完成数据发送和接受的。 (用户使用应用层软件, 先要把这个软件启动起来。 软件启动起来的本质就是进程。)

        所以我们日常通信其实是进程间在通信。  

        即, 日常通信的本质其实就是——进程间通信,只不过是网络层面的进程间通信。——而进程间通信的本质就是让两个进程看到同一份资源, 这里面的同一份资源是谁呢? 在这里其实就是我们的网络。同样的, 我们以前的进程间通信使用个中创建管道, 读写管道,关闭管道的接口,而这里我们的网络同样要给上层提供系统调用来使用网络。而使用的网络资源我们认为系统提供的叫做网络协议栈。 

        所以, 网络通信的本质其实就是通过网络协议栈使用网络资源, 让两个不同的进程看到了同一份资源。 一个从网络里面写, 一个从网络里面读。

端口号 

        假如我们的手机上面有一个微信, 我们知道这个微信其实是一个客户端。 然后在厂家那里必定还有一个微信的服务端。 那么当我们用自己的手机发送数据的时候, 数据通过一些列交付过程与网络传送到了微信的服务端。 然后又从微信的服务端传回来。 这个过程中, 为什么我们手机上的微信发送数据, 数据能够精准的到达对面的微信服务端呢? 又为什么微信服务端发回数据, 数据能准确地到微信客户端呢? 要知道, 我们的应用层的应用软件有很多, 为什么数据偏偏到了微信, 而不是到qq呢? 我们的传输层怎么知道要把数据交给哪个应用呢? 所以, 这里的微信就必须和传输层协商一种规定, 这个规定, 就是端口号!

       这个端口号, 其实是一个两个字节的非负整数。 取值是0 ~ 65535。 它和ip地址不同, ip地址唯一标识一台全网的主机。 端口号则唯一标识某台主机里面唯一的一个网络进程。所以, 端口号和ip类似——ip是全网唯一, 而端口号是主机内唯一。所以在一个主机内一个端口号只能被一个进程绑定。即:端口号port,用来标识该主机上唯一的一个进程! 

socket 

端口号大概被客户端怎么使用的如下: 

  •         这个端口号, 商家在做客户端的时候, 就将服务端的端口号写到了客户端里面, 所以客户端天然就知道服务端的端口号是什么。
  •         当客户端传送数据的时候, 就将服务端的端口号以及自己的端口号当作报文封装起来, 交给传输层。 传输层封装自己的报文后,再向下交付。 依次按流程执行, 当报文交付到服务端的传输层的时候, 传输层解开报文后, 拿到报头和有效载荷, 就能得到端口号, 然后根据端口号将有效载荷交给对应的应用,而这个应用, 必然是服务端!
  •         然后, 我们知道, 客户端在封装报文时将自己的端口号也封装进去了, 所以服务端再将信息传回的时候,就能知道客户端的端口号是什么。 所以服务端就将客户端的端口号封装成报文, 依次交付直到交付到源主机的传输层。 传输层拿到后就能分离有效载荷和报头, 就能得知客户端的端口号, 就将有效载荷给客户端了!

 所以, 由上面我们就能够发现, 客户端和服务端都是用自身的ip和端口号。 ip + 端口号就能表示全网当中唯二的两个不同的进程。 所以我们进程间通信的时候我们就能够互相表示对方的唯一性了!!!——这种基于ip + 端口号的通信方式, 我们把它叫做socket。

 端口号 VS 进程PID

        我们可能会有疑问, PID已经能够表示进程唯一性了, 为什么还要有端口号呢?有两点原因, 如下:

        1、不是所有的进程都要网络通信, 但是所有的进程都要有pid。 (这句话是在告诉我们网络的功能我们需要单独设计。)

        2、为了让系统功能和网络功能更好的去解耦。

 绑定端口号

        我们说每一个进程都有一个端口号, 传输层根据端口号找到对应的进程。 问题是, 这里面的细节是什么, 传输层怎么查找到的对应的进程。

        是因为, 我们的操作系统内部都会给我们生成一张哈希表。 哈希表里面的每一个元素都是进程PCB的指针。 在哈希表中, 我们的进程将端口号作为key, 自己的PCB指针作为value映射到哈希表中的一个位置上面 ——这就是绑定。 未来传输层查找某一个进程的时候, 直接利用端口号作为key查找进程的PCB指针。 就能在O(1)的时间复杂度内快速找到对应的进程。 

        ps:一个进程可以绑定多个端口号, 但是一个端口号不可以被多个进程绑定。

 udp和tcp

tcp——传输控制协议

  • 保证可靠性
  • 面向连接
  • 面向字节流

udp——用户数据报协议

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

        ps:技术层面上可靠不可靠是一个中性词, 没有褒贬。 就比如化学里面的惰性气体。 因为可靠是要有很大成本的, 意味着设计更复杂, 时间成本更大, 维护更不简单。 所以, 可靠与不可靠是一个中性词。 

 网络字节序列

        我们已经知道, 内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据同样有大端小端之分。 那么如何定义网络数据流的大小端呢? 

        网络规定数据流必须是大端。 当主机发送数据流的时候如果是小端, 就先将数据转化成大端, 否则就忽略直接发送即可。 而规定的这个大端,其实就是TCP/IP规定的网络字节序

套接字编程的种类

套接字编程的种类有三种:

  • 1、域间套接字编程——》同一个机器内的进程间通信(本地通信)。
  • 2、原始套接字编程——》绕过传输层, 直接访问网络层, 用来编写网络工具。
  • 3、网络套接字编程——》用户的网络通信。

网络接口的设计者想要将网络接口统一。 保证参数的类型是统一的。 所以,我们的套接字类型就统一使用了struct sockaddr类型。 如下图:

其实, 本质上, 我们的网络套接字使用的是:

我们的域间套接字本质上是:

        如何做到这种情况呢, 16位比特位置之后的数字它其实不管, 关键是我们会发现无论是网络通信的这个sockaddr_in还是域间套接字的这个sockaddr_un, 他前16位比特位都是表示的类型。 一个叫做AF_INET, 一个叫做AF_UNIX。 所以, 我们sockaddr的前16个比特位其实也是一种类型。 

        所以, 未来我们使用接口, 比如bind函数, 它在他的内部实现的时候。 他其实可以对内部进行判断的。 因为我们的整个接口, 每一个结构体的前两个字节它里面就包含了AF_INET或者AF_UNIX的字段。 下面是伪代码:

if (address->type == AF_INET)
{//走网络的代码
}
else
{//走域间的代码
}

 套接字接口

socket

        这里面的第一个参数就是表示将来创建套接字的域, 这个域就是表示未来我们使用的是ipv4还是ipv6或者域间套接字。 ——即,表示套接字的类型。 

        第二个参数表示当前socket的类型, 第三个参数表示tcb还是udp, 我们一般不用填, 这个一般填零就可以了。 一般前两个参数就已经能够很好的表示到底是udp还是tcp了。 

这张表就是套接字的域选项, 比如说有AF_INET表示ipv4, AF_UNIX表示域间套接字等等。

 

然后这是第二个参数的套接字类型选项, 比如说是面向字节流还是面向数据报

        返回值就是一个新的套接字被返回, 否则就是-1被返回, 错误码被设置。

        所以, 套接字的本质其实就相当于在底层打开了一个文件, 只不过以前的struct file指向的是具体的磁盘, 键盘灯设备。 而这个套接字指向的是底层的网卡设备。 

 bind

        bind是用来绑定套接字的。第一个参数就是socket返回的值, 也就是网卡的pid。 然后第二个参数就是套接字结构体。 

返回值就是成功零被返回, 失败-1被返回, 错误码被设置。 

recvfrom

        上面的第一, 二, 三个参数不解释。 下面我们看第四个参数flags。 flags就类似于我们的waitpid里面的阻塞方式。 默认为0, 就是阻塞。 味蕾我们要受到一个消息, 我们是不是还得知道这个消息是谁给我们发的。 因为我们将来可能要给别人回消息。 

        谁给我发的就有最后两个参数来定。 最后两个参数其实是一个输出型参数。(最后的参数也是一个输入性参数。)什么意思, 将来我们如果要别人来访问我们, 那么他就会把对端的套接字信息保存到给指针指向的内存空间里面。 将来呢, 这个src_addr是一个缓冲区, 而这个addrlen就是它的长度。 (实际上我们这里传入的还是struct sockaddr_in)

    ps: udp没办法使用read和write, read和write是给面向字节流的文件使用的。 而我们的udp是一个数据报, 所以我们只能使用recvfrom接口, 这个接口就是收一个消息从一个套接字中。 从指定的套接字中得到指定的报文。 

sendto 

        sendto接口的参数,第一个就是, 第二个就是发送的字符串和长度。 第三个flags设为零。最后的这两个参数是两个输入性参数。 今天我要把消息发回给对方, 我现在知不知道我现在的消息应该发回给谁? ——我们知道, 所以我们这两个参数就是发回给的那个主机的sockaddr。

sockaddr

        我们看一下sockaddr的定义:

        这里面的in_port_t和in_addr其实都是整形:

        然后SOCKADDR_COMMON是一个宏。 这个宏里面传的是sin_, 转到宏定义其实就知道是将sa_family_t定义为sin_famliy

        然后sa_family_t就是

        可以看到, 也是个整形。

ip地址的整数与字符串转化

整数如何转化成字符串

ip地址是:[].[].[].[], 每个区域是0 ~ 255。 我们可以定义一个结构体:

struct IP
{uint8_t part1;uint8_t part2;uint8_t part3;uint8_t part4;
}//字节数为4;

        假如有一个整数int src_ip = 123456789.收到这个整数之后, 就定义一个struct IP* p = (struct IP*)src_ip;

        让然后转一下就可以了:to_string(p->part1) + "." + to_string(p->part2) + "." + to_string(p->part3) + "." + to_string(p->part4); 

如何字符串转整数

        假如 "192.168.50.100", 就先利用字符串分割。 以"."为分割符, 切割后——》"192", "168", "50", "100"。

        然后定义uint32_t IP;

struct ip* x = (struct ipt*)&IP;
x->part1 = stoi("192");
x->part2 = stoi("168");
x->part3 = stoi("50");
x->part4 = stoi("100");

        ps:我们的ip地址和端口号都必须是在双方的报文中携带的。 否则对方发送回来的时候无法得知源主机的ip地址。 如果ip要被网络使用, 除了要把它转化为4字节ip, ip地址也必须是网络序列的。 而转化的时候我们就可以根据主机是大端还是小端来控制上面四个part的赋值顺序。

htons

        其实, 我们在将主机上面的大小端转化为网络字节序列的时候, 不需要自己手动去做。 可以使用htons接口, 这个接口就是将主机字节序列转化为网络字节序列:

 ——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!

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

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

相关文章

摄像头点击器常见问题——摄像头视窗打开慢

【嵌入式开发】可编程4k蓝牙摄像头点击器_能编程的摄像头-CSDN博客 拥有上述文章产品的朋友出现标题所述问题,可继续往下阅读 出现以上问题,摄像头画面打开较慢,可以按以下操作进行设置 在环境变量里设置一下这个参数,值设置为1&…

美国超大型数据泄露事件曝光:超1亿人数据被盗

联合健康(UnitedHealth)首次证实,在 Change Healthcare 勒索软件攻击中,有超过 1 亿人的个人信息和医疗保健数据被盗,这是近年来最大的医疗保健数据泄露事件。 今年 5 月,UnitedHealth 首席执行官安德鲁-威…

深入理解gPTP时间同步过程

泛化精确时间协议(gPTP)是一个用于实现精确时间同步的协议,特别适用于分布式系统中需要高度协调的操作,比如汽车电子、工业自动化等。 gPTP通过同步主节点(Time Master)和从节点(Time Slave)的时钟,实现全局一致的时间参考。 以下是gPTP实现主从时间同步的详细过程:…

Uni-App-03

登录功能开发 实现POST提交 HTTP协议规定请求消息内容类型(Content-Type)有哪些?—— 只有四种 text/plain 没有编码的普通数据 application/x-www-form-urlencoded 编码后的普通数据 multipart/form-data 请求主体中包含文件上传域 application/json 请求主体是 J…

基于SpringBoot的“高校校园点餐系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“高校校园点餐系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 前台首页功能界面图 用户注册、登录界面图 我…

【C++ | 数据结构】八大常用排序算法详解

1. 排序的稳定性 排序是我们生活中经常会面对的问题,小朋友站队的时候会按照从矮到高的顺序排列;老师查看上课出勤情况时,会按照学生的学号点名;高考录取时,会按照成绩总分降序依次录取等等。那么对于排序它是如何定义…

【react 和 vue】 ---- 实现组件的递归渲染

1. 需求场景 今天遇到了一个需求,就是 HTML 的递归渲染。问题就是商品的可用时间,使用规则等数据是后端配置,然后配置规则则是可以无限递归的往下配置,可以存在很多级。后端实现后,数据返回前端,就需要前端…

ImageSharp报错

错误信息 System.MissingMethodException: Method not found: System.Span1<SixLabors.ImageSharp.PixelFormats.Rgba32> SixLabors.ImageSharp.Memory.Buffer2D1.GetRowSpan(Int32).需要升级项目 原来仅升级了SixLabors.ImageSharp没有升级drawing&#xff0c;都升级到…

paddleocr使用FastDeploy 部署工具部署 rknn 模型

在 PC 端转换 pdmodel 模型为 rknn 模型和在板端使用百度飞浆开发的 FastDeploy 部署工具部署 rknn 模型 以下内容是在 PC 端系统为 Ubuntu20.04&#xff0c;板端系统为ubuntu20.04 的环境下实现的 描述&#xff1a; 官网地址 rknn_zoo RKNPU2_SDK …

算法|40K*15.5 + 40w股票+5w签字费|美团北斗大模型面经 ,已拒offer

关注我&#xff0c;掌握目前面试行情&#xff0c;看面经&#xff0c;平均多拿3个offer 背景&#xff1a; 北京理工大学 985本硕&#xff0c;4篇顶会‍‍‍‍ 两面结束&#xff0c;二面面试官说虽然优秀&#xff0c;但不能够入选人才计划。 【第一次谈薪】 37k*15.5 30w股票5…

【C++面试刷题】快排(quick_sort)和堆排(priority_queue)的细节问题

一、快排的快速选择算法两种思路&#xff08;面试会考&#xff09;O(N) 快排的三数取中思路&#xff1a; 重要的是将它三个数进行排序最左为最小&#xff0c;中间为次小&#xff0c;最右为最大的数。&#xff08;错误原因&#xff1a;我刚开始没有将这三个数进行排序&#xff…

如何认识泛基因组?从单一到多元?

近年来&#xff0c;随着多种动植物参考基因组的不断公布及同种不同个体植物基因组间的相互比较&#xff0c;人们逐渐认识到单一参考基因组不能代表物种内的多样性&#xff0c;在此基础上泛基因组概念应运而生。随着三代测序技术的发展&#xff0c;泛基因组的研究迎来了黄金发展…

Android Activity 启动模式

Standard 启动模式 页面跳转顺序 MainActivity -> StandardActivity -> StandardActivity -> StandardActivity 页面栈 示例图 任务栈中只存在MainActivity时 任务栈中存在MainActivity、StandardActivity MainActivity -> StandardActivity MainActivity…

使用freemarker实现在线展示文档功能开发,包括数据填充

首先&#xff0c;在这个独属于程序员节日的这一天&#xff0c;祝大家节日快乐【求职的能找到心仪的工作&#xff0c;已经工作的工资翻倍】。 ---------------------------------------------------------------回到正文-----------------------------------------------------…

合约门合同全生命周期管理系统:企业合同管理的数字化转型之道

合约门合同全生命周期管理系统&#xff1a;企业合同管理的数字化转型之道 1. 引言 在现代企业中&#xff0c;合同管理已经不再是简单的文件存储和审批流程&#xff0c;而是企业合规性、风险管理和业务流程的关键环节之一。随着企业规模的扩大和合同数量的增加&#xff0c;传统…

web3.0 开发实践

优质博文&#xff1a;IT-BLOG-CN 一、简介 Web3.0也称为去中心化网络&#xff0c;是对互联网未来演进的一种概念性描述。它代表着对现有互联网的下一代版本的设想和期望。Web3.0的目标是通过整合区块链技术、分布式系统和加密技术等新兴技术&#xff0c;构建一个更加去中心化…

双非本秋招成功入职小米软开

大家好&#xff0c;我是程序员阿药。最近有位同学说用了这个刷题工具&#xff0c;入职小米软开了&#xff0c;推荐给大家。 简介 微学时光是一款专为计算机专业学生和IT行业求职者设计的面试刷题小程序&#xff0c;它汇集了丰富的计算机面试题和知识点&#xff0c;旨在帮助用…

Linux CentOS7下创建SFTP服务器

本文详细介绍了在Linux CentOS上部署安全文件传输协议&#xff08;SFTP&#xff09;服务器的全过程。SFTP基于SSH&#xff08;安全壳层协议&#xff09;提供文件传输服务&#xff0c;继承了SSH的安全特性&#xff0c;如数据加密、完整性验证和服务器认证等&#xff0c;确保数据…

速来!未发表!DTW-Kmeans-Transformer-BiLSTM组合模型!时序聚类+状态识别!

速来&#xff01;未发表&#xff01;DTW-Kmeans-Transformer-BiLSTM组合模型&#xff01;时序聚类状态识别&#xff01; 目录 速来&#xff01;未发表&#xff01;DTW-Kmeans-Transformer-BiLSTM组合模型&#xff01;时序聚类状态识别&#xff01;效果一览基本介绍程序设计参考…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-25

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-25 0. 前言 大语言模型在很多领域都有成功的应用&#xff0c;在本期计算机前沿技术进展研究介绍中&#xff0c;我们将带来一篇用大语言模型进行诺贝尔文学作品分析的论文。虽然有一定趁最近诺贝尔奖热潮的意味&…