网站建设推广哪个好,武安网站建设价格,模板算量,社交媒体平台文章目录 1. 源IP地址和目的IP地址2. 理解MAC地址和目的MAC地址3. 理解源端口号和目的端口号4. PORT与PID5. 认识TCP协议和UDP协议6. 网络字节序7. socket编程接口7.1 socket常见API7.2 sockaddr结构 1. 源IP地址和目的IP地址
因特网上的每台计算机都有一个唯一的IP地址#… 文章目录 1. 源IP地址和目的IP地址2. 理解MAC地址和目的MAC地址3. 理解源端口号和目的端口号4. PORT与PID5. 认识TCP协议和UDP协议6. 网络字节序7. socket编程接口7.1 socket常见API7.2 sockaddr结构 1. 源IP地址和目的IP地址
因特网上的每台计算机都有一个唯一的IP地址如果一台主机上的数据要传输到另一台主机那么对端主机的IP地址就应该作为该数据传输时的目的IP地址。但仅仅知道目的IP地址是不够的当对端主机收到数据后对端还需要对该主机作出相应因此对端主机也需要发送数据给该主机此时对端主机就需要知道该主机的IP地址。因此一个传输的数据中应该涵盖其IP地址和目的IP地址目的IP地址表明该数据传输的目的源IP地址作为对端主机相应时的目的IP地址。
在数据传输之前会先自顶向下贯穿网络贯穿数据协议栈完成数据的封装其中在网络层封装的IP报头当中就涵盖了就涵盖了源IP地址和目的IP地址。
2. 理解MAC地址和目的MAC地址
大部分数据的传输都是跨局域网的数据在传输过程中会经过若干个路由器最终才能到达对端主机。 源MAC地址和目的MAC地址是包含在链路层的报头当中的而MAC地址实际只在当前局域网内有效。因此当数据跨网络到达另一个局域网时也就是数据到达路由器时路由器会将该数据当中链路层的报头去掉然后再封装一个报头此时该数据的源MAC地址和目的MAC地址就发生了变化。
因此数据在传输的过程中是有两套地址
一套是源IP地址和目的IP地址这两个地址在数据传输过程中基本是不会发生变化的存在一些特殊情况比如使用了NET技术其源IP地址会发生变化但是目的IP地址不会发生变化另一套就是源MAC地址和目的MAC地址这两个地址是会发生变化的因为在数据传输的过程中会路由器会进行解包和重新封装。
3. 理解源端口号和目的端口号 套接字通信的本质 首先我们需要理解的是两个主机之间进行通信不仅仅是为了将数据发给对端主机而是为了访问对端主机上的某个服务。比如我们在使用百度搜索引擎时我们不仅仅将我们的请求发给对端服务器而是想访问对端服务器上部署的百度相关的搜索服务。
我们可以通过IP地址和MAC地址将数据发给对端主机但实际上我们是要发给对端数据上的某个进程此外数据的发送者也不是主机而是主机上的某个进程。比如当我们用浏览器访问网站时实际也就是浏览器进程向对端服务器进程发起请求。 也就是说套接字通信的本质就是两个进程之间在进行通信只不过这里是跨网络的进程间通信。比如我们刷抖音的时候其实就是我们手机上的抖音进程在于对端服务器主机上的抖音服务器进程在进行通信。
因此进程间通信的方式除了管道共享内存消息队列信号量之外还有套接字只不过套接字是跨网络的。 认识端口号 实际在两台主机上可能会存在许多进行网络通信的进程当数据发送到该主机之后需要将数据交给指定的进程。而当进程处理完数据之后还要对发送端进行相应因此对端主机也需要知道是发送端上哪一个进程向它发起请求。
端口号port的作用就是标识一台主机上的一个进程。
端口号是传输层协议的内容端口号是一个2字节16位的整数端口号用来表示一个进程告诉操作系统当前这个数据要交给哪个进程处理一个端口号只能被一个进程占有
由于IP地址可以标识公网内的某一台主机而端口号又可以标识主机上的某一个进程因此用IP地址端口号就可以标识网络上某一台主机的某一进程了。
当数据在传输层进行封装时就会添加上对应源端口号和目的端口号的信息在网络层又会添加上对应源IP地址和目的IP地址这样一来通过源端口号和源IP地址就能在网络上标识发送数据的进程通过目的端口号和目的ID地址就可以在网络上标识接收数据的进程这就实现了跨网络的进程间通信。
注意因为端口号是属于某台主机的所以端口号可以在两台不同的主机当中重复但是在同一台主机上进行网络通信的端口号不能重复。此外一个进程可以绑定多个端口号但是一个端口号只能被一个进程绑定。 理解“套接字”这个名字 套接字源自于单词socket套接字编程实际上就是socket编程。socket在英文上也有插座的意思在进行网络通信的时候客户端就相当于接口服务端就相当于一个插座但服务端上可能会有许多不同的服务进程多个插孔因此当我们在访问服务时需要指明服务进程端口号对应规则的插孔才能得到对应服务进程的服务。
而套接字我们也可以姑且理解为一套用于连接的文字。
4. PORT与PID 端口号port的作用是表示主机上的某个进程进程PID的作用也是表示主机上的某个进程那为什么在进行网络通信的时候不直接使用PID来代替port呢 进程PID是用来表示系统内进程的唯一性的属于系统级别的概念。而端口号是在网络通信时标识进程的唯一性的属于网络级别的概念。
每个人都有自己的身份证号但是为了方便管理到了学习会有学号到了公司会有工号。网络通信使用port同理。
且在网络中使用port在系统中使用PID可以使网络和系统很好地解耦。
底层是如何通过port找到进程的 实际底层采用哈希的方式建立了端口号和进程PID或PCB之间的映射关系当底层拿到端口号时就可以直接执行对应的哈希算法然后就能找到该端口号对应的进程。
5. 认识TCP协议和UDP协议
当我们使用系统调用接口实现网络数据通信时不得不面对的协议层就是传输层而传输层最经典的两种协议就是TCP协议和UDP协议。 TCP协议 TCP协议叫做传输控制协议Transmission Control ProtocolTCP是一种面向连接的可靠的基于字节流的传输层控制协议。
TCP是面向连接的如果两台主机之间要进行数据传输必须先建立连接在连接建立完成之后才可以进行数据传输。其次TCP是保证可靠的协议数据在传输过程中如果出现了丢包、乱序等情况TCP都有对应的解决方案。 UDP协议 UDP协议叫做用户数据报协议User Datagram ProtocolUDP是一种无需建立连接的、不可靠的、面向数据报的传输层通信协议。
使用UDP协议进行通信时无需建立连接如果两台主机之间想要进行数据传输那么直接将数据发给对端主机就行了但这也就意味着UDP协议是不可靠的数据在传输过程中如果出现了丢包、乱序等情况UDP协议本身是不知道的。 既然UDP协议是不可靠的那为什么还要有UDP协议的存在 TCP协议是一种可靠的传输协议使用TCP协议可以保证数据传输时的可靠性而UDP协议是一种不可靠的传输协议它的存在有什么意义呢
首先可靠是需要我们更多的工作的TCP协议虽然是一种可靠的传输协议但这意味着TCP协议在底层一定要做更多的工作因此TCP协议底层的实现是比较复杂的我们不能只看到TCP协议面向连接这个优点。还要看到TCP协议对应的缺点。
同样的UDP协议虽然是一种不可靠的传输协议但这一定意味着UDP协议在底层不需要做过多的工作因此UDP协议底层的实现一定比TCP协议要简单的多UDP协议虽然不可靠但是它能把数据快速地发给对方虽然数据在传输的过程中可能会出错。
编写网络通信代码时具体采用TCP协议还是UDP协议完全取决于上层的应用场景。如果应用场景严格要求数据在传输过程中的可靠性我们就必须采用TCP协议如果应用场景允许数据在传输出现少量丢包那么我们肯定优先选择UDP协议因为UDP协议足够简单。
一些网站在设计网络通信算法时会同时采用TCP协议和UDP协议当网络流畅时就使用UDP协议进行数据传输当网络不好时就使用TCP协议进行数据传输此时就可以动态地调整后台通信算法。
6. 网络字节序 网络中的大小端问题 计算机在存储数据时是有大小端的概念的
大端模式数据的高字节内容保存在内存的低地址处数据的低字节内容保存在内存的高地址处。小端模式数据的高字节内容保存在内存的高地址处数据的低字节内容保存在内存的低地址处。
如果编写的程序只在本地机器上运行那么是不需要考虑大小端问题的因为同一台机器上采用的存储方式都是一样的要么采用大端存储模式要么采用小端存储模式。但如果设计网络通信那就必须考虑大小端的问题否则对端主机识别出来的数据可能与发送端想要发送的数据是不一致的。
例如现在两台主机在进行网络通信其中发送端是小端机而接收端是大端机。发送端将发送缓冲区内的数据按内存地址从低到高的顺序发出后接收端从网络中获取数据一次保存在接收缓冲区中也是按内存地址从低到高的顺序保存的。 但由于发送端和接收端采用的分别是小端存储和大端存储此时对于内存地址从低到高为 44332211 的序列发送端按小端的方式识别出来的是 0x11223344但是接收端按大端的方式识别的是 0x44332211此时接收端接收到的数据就与发送端原本想要发送的数据就不一样了这就是由于大小端的偏差导致数据识别出现了错误。
由于我们不能保证通信双方存储数据的方式是一样的因此网络当中传输的数据必须考虑大小端问题。因此TCP/IP协议规定网络数据流采用大端字节序即低地址高字节。无论是大端机还是小端机都必须按照TCP/IP协议当中规定的网络字节序来发送和接收数据。
如果发送端是小端需要先将数据转成大端然后再发送到网络当中如果发送端是大端则可以直接进行发送如果接收端是小端需要先将数据转换成小端后再进行数据识别如果接收端是大端则可以直接进行数据识别。 主机字节序和网络字节序直接的转换接口 为了使网络程序具有可移植性使同样的C代码在大端和小端机器上编译后都能正常运行系统提供了四个函数可以通过调用以下库函数实现网络字节序和主机字节序直之间的转换
函数名中的h表示hostn表示networkl表示32位长整数s表示16位短整数例如htonl表示将32位长整数从主机字节序转换为网络字节序如果主机是小端字节序则这些函数将参数做相应的大小端转换然后返回如果主机是大端字节序则这些函数不做任何转换将参数原封不动地返回
7. socket编程接口
7.1 socket常见API 创建套接字TCP/UDP客户端服务端 绑定端口号TCP/UDP服务器 监听套接字TCP服务器 接收请求TCP服务器 建立连接TCP客户端 7.2 sockaddr结构 sockaddr结构的出现 套接字不仅支持跨网络的进程间通信还支持本地的进程间通信域间套接字。在进行跨网络通信时我们需要传递的端口号和IP地址而本地通信则不需要因此套接字提供了sockaddr_in结构体和sockaddr_un结构体其中sockaddr_in结构体是用于跨网络通信的而sockaddr_un结构体是用于本地通信的。
为了让套接字的网络通信和本地通信能够使用同一套函数接口于是就出现了sockaddr结构体该结构体与sockaddr_in结构体和sockaddr_un的结构都不相同但这三个结构体头部的16个比特位都是一样的这个字段叫做协议家族。 此时当我们在传参时就不用传入sockaddr_in或者sockaddr_un这样的结构体而统一传入sockaddr这样的结构体。在设置参数时就可以通过设置协议家族这个字段来表明我们是要进行网络通信还是本地通信在这些API内部就可以提取sockaddr结构体的16位头部进行识别进而得出我们是要进行网络通信还是本地通信然后执行对应的操作。这样我们通过sockaddr结构就将套接字网络通信和本地通信的参数类型实现了统一。
注意实际我们在进行网络通信的时候定义的还是sockaddr_in这样的结构体只不过在传参时需要将该结构体的地址类型进行强转为sockaddr*罢了。 为什么不用 void* 代替 struct sockaddr* 类型呢 我们可以将这些函数接口形参的struct sockaddr参数改为void此时在函数背部也可以直接提取头部的16个比特位进行识别最终也能够判断是需要进行网络通信还是本地通信那为什么还要设计出sockaddr这样的结构呢
实际在设计这一套网络接口的时候C语言还不支持void* 于是就设计出了sockaddr这样的解决方案。