「网络编程」第二讲:网络编程socket套接字(一)

news2024/12/23 14:01:43

「前言」文章是关于网络编程的socket套接字方面的,下面开始讲解!

「归属专栏」网络编程

「笔者」枫叶先生(fy)

「座右铭」前行路上修真我

「枫叶先生有点文青病」

「每篇一句」

春风得意马蹄疾,一日看尽长安花。

——孟郊《登科后》

目录

一、预备知识

1.1 源IP和目的IP

1.2 源MAC地址和目的MAC地址

1.2 认识端口号

1.3 理解 "端口号" 和 "进程PID" 的关系

1.4 源端口号和目的端口号

1.5 认识TCP协议

1.6 认识UDP协议

1.7 网络字节序

二、socket编程接口

2.1 socket常见的API接口

2.2 sockaddr结构


一、预备知识

1.1 源IP和目的IP

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

  • 在IP数据包头部中(在网络层), 有两个IP地址, 分别叫做源IP地址, 和目的IP地址
  • IP地址通常在广域网中使用,准确来说,IP地址既可以在局域网中使用也可以在广域网中使用
  • 每台主机必须要有IP地址,否则就不能上网
  • IP地址标识唯一的主机

什么是源IP和目的IP?

还是张三从北京到云南骑自行车旅游的例子,张三每去到下一站都会说:我从北京来,要去云南旅游。这里的北京就是源IP,云南就是目的IP,旅途中张三会经过很多的站口,但是张三依旧是从北京来,去往云南旅游。其中从北京去往云南这个大目标是不会改变的,虽然旅途中会经过很多个小站。

源IP和目的IP的作用是:为未来的每一个阶段,提供方向目标,方便路径选择

如果在北京主机A向云南主机B发消息,那么主机A的IP地址就是源IP地址,主机B的IP地址就是目的IP

1.2 源MAC地址和目的MAC地址

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

  • 源MAC地址和目的MAC地址是包含在链路层的报头当中的
  • 而MAC地址实际只在当前局域网内有效

什么是源MAC地址和目的MAC地址?

依旧是张三从北京到云南骑自行车旅游的例子:

  • 张三从北京出发
  • 张三去到石家庄说:我上一站从北京来,下一站去往郑州;
  • 张三去到郑州后说:我上一站从石家庄来,下一站去往西安;
  • 张三去到西安后说:我上一站从郑州来,下一站去往成都;
  • 张三去到成都后说:我上一站西安来,下一站去往云南;
  • 张三到达云南

其中我们发现,张三口中的地址一直在变化,这些变化的地址就是MAC地址,比如:北京去石家庄,北京是源MAC地址,石家庄是目的MAC地址;石家庄去郑州:石家庄就变成了源MAC地址,郑州就变成了目的MAC地址...

同理当数据跨网络到达另一个局域网时,其源MAC地址和目的MAC地址就需要发生变化,因此当数据达到路由器时,路由器会将该数据当中链路层的报头去掉,然后再重新封装一个报头,此时该数据的源MAC地址和目的MAC地址就发生了变化

源MAC地址和目的MAC地址提供了网络通信的可行性

1.2 认识端口号

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

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

注:(这里的IP是公网IP),IP到后面再详细解释

1.3 理解 "端口号" 和 "进程PID" 的关系

我们把数据从主机A发送到主机B,目的是让这两台主机进行通信吗?答案肯不是,把数据从主机A发送到主机B是手段不是目的,真正进行通信的其实是主机上的软件(或人),比如小A和小B在各自的主机上下了QQ,小A和小B使用QQ进行聊天,通信的是QQ软件(或人)。

A主机上,可能会同时存在多个正在进行跨网络通信的进程,发送数据是由该QQ软件对应的进程进行发送,发送的数据也不是直接发给B主机,而是先发给客户端软件的服务端进程上,再由服务端进程转发数据给B主机。

此时,B主机上也可能会同时存在多个正在进行跨网络通信的进程,如何识别哪个进程是对应该QQ软件的进程???

  • 此时,就需要用到端口号了,端口号的作用是:用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理
  • IP地址(标识主机在全网的唯一性)+ 该主机上的端口号port(标识主机上进程的唯一性)
  • 所以,IP地址 + 端口号port(可以标识该主机上对应的进程,在全网中唯一性)
  • 所以,主机A对应进程:IP+port,主机B对应进程:IP + port,这样就可以标识这两个进程在全网都是唯一的
  • 所以网络通信的本质是:其实就是进程间通信
  • 而进程间通信的前提是:双方进程看到同一份公共资源,而这份公共资源在这里就是网络

通信其实就是在 I/O,所以我们的上网行为无外乎就两种:

  1. 我把我的数据发出去
  2. 我要收到别人给我发的数据

进程PID就已经标识了同一台主机上进程的唯一性,为什么不使用PID进行标识?为什么要使用端口号port??

  • 进程IPID是用来标识同一台主机上进程的唯一性,它是属于系统级的概念;
  • 而端口号(port)也是用来标识同一台主机上进程的唯一性,它是属于网络的概念 
  • 事实上,用进程的PID标识同一台主机上进程的唯一性,从技术上这也是可以的,但是并没有这么做
  • 是因为,系统是系统,网络是网络,系统已经够复杂了,网络再来掺和一脚系统会变得更加复杂
  • 单独设置端口号是为了与系统进行解耦
  • 标识进程在全网的唯一性,两台主机的的PID可能会相同
  • 不是所有的进程都需要提供网络服务或请求(即port),但是所有的进程都需要PID

软件都是用户主动打开的,所以几乎大部分情况都是用户端先向服务端发起请求,那如何保证客户端每次都能找到服务端进程??

  • 要保证客户端每次都能找到服务端的进程,就必须要保证服务端的 IP + port 的唯一性,服务端的进程的端口号不能随意改变

底层OS如何根据port找到指定的进程??

  • 实际底层采用哈希的方式建立了端口号和进程PID或PCB之间的映射关系,当底层拿到端口号时就可以匹配对应的哈希表,然后就能够找到该端口号对应的进程

注意:一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定

事实上,一台主机发送数据给另一台主机,发送方除了要发送数据外还要把自己的 IP + 端口号port 发送给服务端,服务端进程再转发数据给另一台主机。通信是双方的

所以在未来发送数据的时候一定会多发一部分数据,多发的这部分数据以协议的形式呈现 

1.4 源端口号和目的端口号

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

这个与源IP与,目的IP类似,就不举张三的例子了,比如主机A给主机B发数据,主机A就是源端口,数据要去下一个局域网的路由器,下一个局域网的路由器就是目的端口,以此类推,直到一直跳跃到主机B

1.5 认识TCP协议

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

TCP概述:

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

TCP协议是面向连接的,如果两台主机之间想要进行数据传输,那么必须要先建立连接,当连接建立成功后才能进行数据传输

其次,TCP协议是保证可靠的协议,数据在传输过程中如果出现了丢包、乱序等情况,TCP协议都有对应的解决方法

1.6 认识UDP协议

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

UDP概述:

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

使用UDP协议进行通信时无需建立连接,如果两台主机之间想要进行数据传输,那么直接将数据发送给对端主机就行了

但是UDP协议是不可靠的,数据在传输过程中如果出现了丢包、乱序等情况,UDP协议本身是不知道的,也无法处理

注:面向字节流和面向数据报暂时不谈

UDP是不可靠传输,为什么还要有UDP,TCP是可靠传输难道不好吗??

  •  这里的 可靠 VS 不可靠 是中性词,没有任何的褒贬义,不是说可靠就是好,不可靠就是不好,这里的可靠和不可靠描述的是一种现象
  • 可靠是伴随着成本的提高的,实现是更复杂的,维护和编码成本更高
  • 不可靠的实现成本低,实现比较简单,维护和使用成本低
  • UDP和TCP都是有适合自己的场景的,比如TCP就比较适合银行的交易系统等,UDP就比较适合直播或者投递广告,两者一般都是一起结合使用的:网络流畅时就使用UDP协议进行数据传输,而当网速不好时就使用TCP协议进行数据传输

1.7 网络字节序

计算机的存储是分大小端的,在C语言已经学习过了

  • 大端模式: 数据的高字节内容保存在内存的低地址处,数据的低字节内容保存在内存的高地址处。
  • 小端模式: 数据的高字节内容保存在内存的高地址处,数据的低字节内容保存在内存的低地址处。

内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分

如果只在一台主机上,那么是不需要考虑大小端问题的,因为同一台机器上的数据采用的存储方式都是一样的,要么采用的都是大端存储模式,要么采用的都是小端存储模式。

但如果涉及跨主机网络通信,那就必须考虑大小端的问题否则其他主机识别出来的数据可能与发送端想要发送的数据是不一致的

比如,两台主机之间在进行网络通信,其中发送端是小端机,而接收端是大端机。发送端将发送缓冲区中的数据按内存地址从低到高的顺序发出后,接收端从网络中获取数据依次保存在接收缓冲区时,也是按内存地址从低到高的顺序保存的

  • 但由于发送端和接收端采用的分别是小端存储和大端存储
  • 发送端按小端的方式发送数据,比如:0x12345678,发送的顺序是:78 56 34 12,小端识别数据是正常的:0x12345678
  • 而接收端是大端存储,接受数据的顺序是 78 56 34 12,最后识别的数据是:0x78563412
  • 此时接收端识别到的数据与发送端原本想要发送的数据就不一样了,这就是由于大小端的偏差导致数据识别出现了错误

解决方法

  • 解决方法简单粗暴:规定网络中的数据都是大端
  • 即发送端是小端,需要先将数据转成大端,然后再发送到网络当中
  • 发送端是大端,则可以直接进行发送
  • 接收端是小端,需要先将接收的网络数据转成小端后再进行数据识别
  • 接收端是大端,则可以直接进行数据识别

以上综述:

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

网络字节序与主机字节序之间的转换

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

注:转换工作不需要我们自己做。直接调用库函数即可完成

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
  • 函数名当中的h表示 host,n表示 network,l表示 long,32位长整数,s表示 short,16位短整数
  • htonl 的意思就是:把32位的主机字节序转换成(to)32位网络字节序
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回
  • 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回

二、socket编程接口

socket的中文意思是插座,在计算机叫套接字

在进行网络通信时,客户端就相当于插头,服务端就相当于一个插座,但服务端上可能会有多个不同的服务进程(多个插孔),因此当我们在访问服务时需要指明服务进程的端口号(对应规格的插孔),才能享受对应服务进程的服务

套接字的种类大致分三种:

  1. 网络套接字编程:应用于跨主机网络通信,也支持本地通信
  2. unix域间套接字:只能进行本地通信
  3. 原始套接字:可以从应用层直接绕开传输层,直接去访问底层协议,通常用于各种抓bao软件、网络侦测工具

注:后面只讲第一种套接字,即网络编程套接字,网络编程套接字懂了,unix域间套接字也可以看懂(接口相同)

由于有三种套接字,为了使用方便,接口设计者就只设计了一套接口,可以通过传不同的参数,解决所有网络或者其他场景下的网络通信

2.1 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);

注:参数用到再解释

2.2 sockaddr结构

前面说到设计者只设计了一套接口,这套接口里面最重要的就是 sockaddr结构体,除此之外还有两个结构体:sockaddr_in 和 sockaddr_un

  • sockaddr_in 结构体是用于跨网络通信,其中 sockaddr_in 的 in 是 inet,"inet" 是Internet Protocol(IP)的简写
  • sockaddr_un 结构体是用于本地通信,其中 sockaddr_un 的 un 是 unix

但是我们使用函数时,传的参数是 sockaddr结构体,并不是 sockaddr_in 和 sockaddr_un

  • sockaddr_in 和 sockaddr_un结构体头部的16个比特位(2字节)都是一样的,这16位地址类型代表的是使用网络通信还是本地通信
  • 而 sockaddr结构体设计前两个字节的内容也与 sockaddr_in 和 sockaddr_un结构体一样,sockaddr结构体其他字段不重要,重要的是前两个字节
  • 我们需要做的就是对 sockaddr_in 或 sockaddr_un结构体进行填充,然后传参给 sockaddr,这个过程必须要强制类型转换
  •  在socket函数的内部,对于传进来的参数 sockaddr 直接去前两个字节,进行判断是网络通信还是本地通信,知道这个结果后再强制类型转换回  sockaddr_in 和 sockaddr_un结构体

用这样的设计方式,就可以设计出同一套接口套接字接口了,这就是面向对象语言的多态

为什么不用 void* 代替 struct sockaddr* ??

因为当时设计这些 socket 接口时,C语言的语法还不支持 void*。并且在C语言支持了 void* 之后也没有将它改回来,因为这些接口是系统接口,直接内嵌在OS里面的,系统接口是所有上层软件接口的基石,系统接口是不能轻易更改的,否则会带来某些严重的后果

文章暂时到这里,下一篇开始编写代码

--------------------- END ----------------------

「 作者 」 枫叶先生
「 更新 」 2023.6.15
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
          或有谬误或不准确之处,敬请读者批评指正。

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

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

相关文章

这有可能是全网最好的《基于CUDA的GPU并行程序优化实战课程》!预售开启!

大模型一出&#xff0c;各类企业的各类“模型”竞赛般的亮家伙&#xff0c;算力时代抢先到来。2023年4月超算互联网的正式部署&#xff0c;标志着&#xff0c;很快&#xff0c;越来越多的应用都需要巨大的计算资源。 这给传统的计算机体系结构带来了巨大的挑战&#xff0c;计算…

C语言指向结构体的指针(二)

示例 #include <stdio.h> void main(){struct student{char name[10];int age;char *xiaoming;}stu1{"豪哥",23,"zz"},*p;p &stu1;//struct student stu2 {"豪哥",23};printf("结构体指针变量p的姓名是:%s,年龄是:%d,小名是&am…

『手撕 Mybatis 源码』08 - 动态代理 invoke 方法

动态代理 invoke 方法 问题 mapperProxy.findByCondition(1); 是怎么完成的增删改查操作&#xff1f; 当通过 JDK 代理方式生成代理对象后&#xff0c;可以通过代理对象执行代理方法 public class MybatisTest {/*** 问题3&#xff1a;mapperProxy.findByCondition(1); 是怎…

Linux学习之rpm安装软件

包管理器是方便软件安装、卸载&#xff0c;解决软件依赖关系的重要工具。 CentOS、RedHat使用yum包管理器&#xff0c;软件安装包格式为rpm。 Debian、Ubuntu使用apt包管理器&#xff0c;软件安装包格式为deb。 rpm包格式&#xff1a;vim-common-7.4.629-8.el7_9.x86_64.rpm vi…

移植微雪例程-1.54寸双色水墨屏

微雪官网&#xff1a;E-Paper ESP32 Driver Board - Waveshare Wiki 去微雪官网&#xff0c;把墨水屏的例程下下来。 我这个使用的是1.54寸的双色墨水屏。 下载下来之后&#xff0c;然后移植到IDF上面。 移植epd1in54c-demo这个例程。 一.移植前的准备工作: 复制以下内容到…

扩展卡尔曼滤波在目标跟踪中的应用(1)

前面几节相继介绍的不同维度的卡尔曼滤波算法&#xff0c;在线性高斯模型的条件下&#xff0c;具有很好的跟踪效果&#xff0c;当时在实际生活中&#xff0c;不可能所有的运动都呈现一种线性关系&#xff0c;也存在着非线性关系&#xff0c;比如说&#xff1a;飞机的飞行状态&a…

DBA 从业者在行业的变革下 --- 可行性出路

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

玩转ChatGPT:基于Mucloud建立本地知识库

一、写在前面 人们普遍认为GPT有潜力颠覆教育行业&#xff0c;然而这种颠覆会以何种方式呈现呢&#xff1f; 在刘慈欣的科幻世界中&#xff0c;三体人拥有知识遗传的能力&#xff0c;这使得他们的技术迭代成本降至最低。然而&#xff0c;我们人类并未具备这样的特性&#xff…

mysql数据库学习日记第一天

一、简介 数据库&#xff08;DB&#xff09;&#xff1a;存储数据的仓库 数据库管理系统&#xff08;DBMS&#xff09;&#xff1a;数据库管理系统 SQL&#xff1a;操纵关系数据库的一种编程语言&#xff0c;定义一套关于操作关系数据库的一套标准 二、安装教程 到MYSQL官…

拼多多攻势凌厉,中小电商崛起,京东和阿里更换掌门人

日前阿里董事会主席兼CEO都由新的人士担任&#xff0c;此前京东也更换了CEO&#xff0c;两大电商掌门人更换&#xff0c;电商行业引发震动&#xff0c;这不免让人想起另一家正快速崛起的电商拼多多&#xff0c;业界人士指出拼多多的崛起让两大电商闪了腰。 一、拼多多和众多中小…

第十章 ShuffleNetv2网络详解

系列文章目录 第一章 AlexNet网络详解 第二章 VGG网络详解 第三章 GoogLeNet网络详解 第四章 ResNet网络详解 第五章 ResNeXt网络详解 第六章 MobileNetv1网络详解 第七章 MobileNetv2网络详解 第八章 MobileNetv3网络详解 第九章 ShuffleNetv1网络详解 第十章…

RISCV-semi host原理以及实践

嵌入式裸机调试需要在有限资源的目标硬件上尽可能挖掘更多的信息&#xff0c;比如打印寄存器等等&#xff0c;但是即便看似很简单的串口打印&#xff0c;在有的情况下也是奢望&#xff0c;针对这种情况&#xff0c;能够有效利用主机资源协同调试的semi-host&#xff08;半主机&…

基于YOLACT的目标跟踪算法移植与测试

基于YOLACT的目标跟踪算法移植与测试 一、初始化开发环境&#xff08;基于x86架构CPU的开发环境中完成&#xff09; 1.1 初始化开发环境 1.下载SOPHON SDK开发包 #下载SOPHON SDK wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/06/15/16/Release_230501-pub…

大数据就业路线

✨博文作者&#xff1a;烟雨孤舟 &#x1f496; 喜欢的可以 点赞 收藏 关注哦~~ ✍️ 作者简介: 一个热爱大数据的学习者 ✍️ 笔记简介&#xff1a;作为大数据爱好者&#xff0c;以下是个人总结的学习笔记&#xff0c;如有错误&#xff0c;请多多指教&#xff01; 数仓&#x…

English Learning - L3 作业打卡 Lesson7 Day46 2023.6.19 周一

English Learning - L3 作业打卡 Lesson7 Day46 2023.6.19 周一 引言&#x1f349;句1: If your life were a book and you were the author, how would you want your story to go?成分划分弱读连读语调 &#x1f349;句2: That’s the question that changed my life foreve…

ps beta爱国版下载全过程

​前言&#xff1a; 前段时间也是写了一篇ps beta版本下载的全过程呀&#xff0c;当时那篇文章还没有将软件变成永久免费试用&#xff0c;所以ps beta只能进行7天的免费使用&#xff0c;很多朋友可能意犹未尽呀&#xff0c;所以现在继续&#xff0c;将软件变成永久免费使用​。…

步长(stride) | 填充(padding) | 扩长(dilation)

这几个名词中文真的好难翻译&#xff0c;不是大佬就不要造名词了&#xff0c;后面还是老老实实用英文吧&#xff01;&#xff08;标题是机翻的 。&#xff09; stride stride 很好理解&#xff0c;stride 就是卷积核移动的步长。 如下图&#xff1a; stride1 stride2 paddi…

【嘉立创EDA】复合焊盘的引线居中对齐,typc接口引线对齐方法

文章路标👉 文章解决问题主题内容小结文章解决问题 1️⃣ 嘉立创EDA中对齐工具越发完善,但一些特殊的器件引线中,由于对齐属性设置等原因,部分引线无法与焊盘完全居中对齐,影响了线路的表象美观度与里内信号铺面。本文主要讲述如何应用嘉立创EDA的其他技巧将器件引线与…

基於Hadoop HA 在kerberos中配置datax

概要 提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 概要 前言一、基於HADOOP HA 搭建datax二、基於HADOOP HA 配置好的datax去配置kerberos1.在datax的配置文件中進行配置2.在shell腳本中加入認證語句 总结 前言…

detrex | 面向detr系列的目标检测开源框架

DETR作为Transformer应用于目标检测领域的开山之作&#xff0c;后续有大量的算法都是在其基础上改进而来&#xff0c;如Deformable-DETR&#xff0c;DAB-DETR&#xff0c;DN-DETR&#xff0c;DINO等。这些模型尽管都是采用DETR的基本架构&#xff0c;但其改进创新却各有千秋&am…