[TOC]
## 前言
### 说在前面
**把**他叫做笔记,就是因为这些内容是我在阅读了各种书籍,论坛以及博客之后自己整理的,所以,不是百分百原创但是又可以说是百分百原创。所以特此声明一下。
**整**理这篇笔记我用了好几天的时间,虽然自己知道很多内容,但真的要一点一点整理出来还是挺麻烦的,因为要把和Swoole相关的知识单独拎出来,说简单也很简单,说难其实也挺难。
其实搞Swoole的话,我感觉最基本的就是TCP,UDP了。之前我把OSI七层的全写了,但是感觉太乱了,这么多层,知识点本来就杂乱,而且任意一层都会有不同的技术细节,都整理出来,GET不到重点,所以这里我们就从IP/TCP/UPD/HTTP开始。
>ps:作为一个初级phper,下面的内容了解即可,如果想深入学习网络编程,我推荐几本书,这几本书都是我看过并且经常翻阅的,都写的很好,作为一个程序员想计算机知识自上而下不说精通,光完全理解都谈何容易,所以个人感觉最好有个侧重点比较好,所以书籍我也只是推荐,毕竟我自己走了不少弯路,曾经年幼无知的我连cpu上电时序图都看,然而现在我只是个phper,curdboy~
>初级入门的话我推荐《图解HTTP》
然后我看了《一本书读懂TCP/IP》
下面的书是我平时当作字典遇到问题查的
《UNIX网络编程 卷1:套接字联网API》
《UNIX网络编程 卷2:进程间通信》
《TCP&IP网络编程》
## 正文
**首先贴一个TCP/IP协议栈的图,下面的知识参照这个图来理解。**
:-: ![](https://img.kancloud.cn/ed/80/ed80130010957e7dd938e97b8bd40783_654x339.png)
### IP地址(网络层)
IP地址众所周知,Windows系统查询网络IP地址为ipconfig,Linux中为ifconfig或者ip addr命令。Windows如下图所示。
:-: ![](https://img.kancloud.cn/2d/2c/2d2cf824955aab1d59c8c4be54e69e7f_595x289.png)
:-: **ipconfig效果图**
IPv4的IP地址是32个字节的,如百度的115.239.210.27就是一个IP地址,它的作用是一个网卡的地址,具有定位作用。现在想一想MAC地址是一个网卡出厂就具备的全球唯一的地址,那么有了MAC地址后,怎么还需要IP地址了?答案就是没有IP地址根本定位不了,给你一个百度的服务器MAC地址,你怎么能找到他了。MAC地址就像我们的身份证,IP地址就如同我们的家庭住址+名字。比如给你小王的MAC地址,你也不可能找到他,只有先通过他的家庭住址和名字,才能找到他。**所以说MAC地址不具备大范围的定位作用,只有在局域网内才有作用**,这就是MAC地址和IP地址的一个区别。
32位的IP地址被分成了一下五类,又大大的减少了IP地址数量。A、B、C是有网络号和主机号组成的。这样是为了区别是不是在同一个局域网内,网络号代表的是小区,主机号代表的是哪一号房间。这样不同的小区就可以都有1001号房间了,但不会产生冲突,因为他们的网络号不同。
:-: ![](https://img.kancloud.cn/26/39/2639b7ee25a10dc2d0cbb27c4d91f509_1090x458.png)
:-: **IP地址分类图**
如下图所示,A、B、C三类的最大主机数量,很容易产生浪费。私密地址代表什么了,我们上学的时候IP都是172.16开头的,貌似很多大学的IP都是一样的,你会问这不是产生冲突了吗,只能说,这些IP在局域网里面是正常使用的,一段到了公网后,这个就会被替换成一个不冲突的IP了,数据请求返回时,再被替换回来,这样就保证了不冲突,详情下面会说,现在有个概念就可以了。
:-: ![](https://img.kancloud.cn/5b/a6/5ba6a973479040775d562a9abe51c41c_1200x340.png)
**怎么判断是否是同一个局域网的IP地址了?**
通过配置的子网掩码。如下图是一个C类的私有IP地址,网络号为24位,主机号位8位,广播地址为192.168.1.255,一般默认的网关为192.168.1.1.将子网掩码和IP地址按位与计算后,就可以得到网络号了,也就可以判断目标IP是否是要出网关了。
D类地址是组播地址,也就是说这个组的网卡都会收到改组的数据。
此外还介绍一个特殊的IP地址,127.0.0.1。他是个环回接口,这个地址用于本机通信,经过内核处理后直接返回给本机。
:-: ![](https://img.kancloud.cn/16/26/1626f415269690db08729ea342518e21_414x430.png)
:-: **IPv4相关配置**
Linux中配置IP地址如下:
~~~cpp
sudo ifconfig eth1 192.168.1.174/24 //给eth1这个网卡配置IP和子网掩码
sudo ifconfig eth1 up // 启动
~~~
**简单的数据发送过程:**系统会判断数据包的目标IP是不是在同一个网段中,如果是是同一个网段,他会通过ARP协议广播获取目标IP的MAC地址,直接发送给目标即可。如果是跨网段,那么获取网关的MAC地址,把数据发给网关就不管了。
>关于IP协议我就不写了,如果后续有时间了,我争取整理一份网络编程的笔记,但应该会是很久之后了。
### TCP(传输层)
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内 另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元( MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体 的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
#### 三次握手
TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK ,并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接,TCP使用的流量控制协议是可变大小的滑动窗口协议。 TCP三次握手的过程如下:
* 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN\_SEND状态。
* 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN\_RECV状态。
* 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
#### 连接成功
连接成功之后双方即可互相传输字节流,并随时可关闭连接,传输的数据有以下特性
* 传输的数据被tcp分割成了最适合发送的数据块 传递给ip协议,这个发送数据称为 报文段 或 段
* tcp作为可靠性连接,每次发送数据段,会启动一个定时器,每次接收数据段,会发送一次确认,如果定时器没有及时收到确认,则会重发数据
* TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
* 两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(bytestreamservice)。如果一方的应用程序先传10字节,又传20字节,再传50字节,连接的另一方将无法了解发方每次发送了多少字节。只要自己的接收缓存没有塞满,TCP 接收方将有多少就收多少。一端将字节流放到TCP连接上,同样的字节流将出现在TCP连接的另一端。
#### 四次挥手
建立一个连接需要三次握手,而终止一个连接要经过四次挥手,这是由TCP的半关闭(half-close)造成的。具体过程如下所示。
* 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
* 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。
* 注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
* 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
* 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。 既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
> “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。 无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。
#### php中的tcp
php可通过socket函数,swoole扩展,stream流函数进行创建tcp协议的socket,绑定网卡端口,进行tcp服务端/客户端操作 在php中,我们并不需要了解tcp的握手/挥手,我们只需要知道ip:port能连接/创建 一个tcp服务端/客户端就行了
使用php的socket,我们可以直接发送字符串,接收的也是字符串,其他一切都是语言,操作系统所需要做的事,
我们只需要处理好字符串的完整性,例如我们使用php做tcp服务端
* 客户端连接成功后,发送了一个"abcabcabcabc"的字符串
* 而服务端每次只接收9个字节,那第一次获取只会接收到"abcabcabc"的残缺字符串,需要继续获取数据
### HTTP
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。
#### 技术架构
HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。(我们称这个客户端)叫用户代理(user agent)。应答的服务器上存储着(一些)资源,比如HTML文件和图像。(我们称)这个应答服务器为源服务器(origin server)。在用户代理和源服务器中间可能存在
多个中间层,比如代理,网关,或者隧道(tunnels)。尽管TCP/IP协议是互联网上最流行的应用,HTTP协议并没有规定必须使用它和(基于)它支持的层。 事实上,HTTP可以在任何其他互联网协议上,或者在其他网络上实现。HTTP只假定(其下层协议提供)可靠的传输,任何能够提供这种保证的协议都可以被其使用。
通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端发送过来的请求。一旦收到请求,服务器(向客户端)发回一个状态行,比如"HTTP/1.1 200 OK",和(响应的)消息,消息的消息体可能是请求的文件、错误消息、或者其它一些信息。
HTTP使用TCP而不是UDP的原因在于(打开)一个网页必须传送很多数据,而TCP协议提供传输控制,按顺序组织数据,和错误纠正。
通过HTTP或者HTTPS协议请求的资源由统一资源标示符(Uniform Resource Identifiers)(或者,更准确一些,URLs)来标识。
:-: ![](https://img.kancloud.cn/65/ec/65ec16abdeba733f8be8afbd41e8ac9d_396x300.png)
#### 过程解析
http一次请求的过程大概如下:
* 用户在浏览器输入www.baidu.com
* dns服务器解析/或者本机hosts,路由器hosts对比 获得ip
* 浏览器访问默认端口80,则访问的tcp地址为 ip:80
* tcp协议3次握手,建立连接
* 发送一个http request请求头
* 服务器获得http request请求头,表明该次访问为http访问,解析http请求头,获得请求类型,请求格式,以及请求数据(cookie,get,post数据)
* 服务器发送response响应数据,主动断开
* 浏览器接收response响应数据,解析响应文本类型,解析数据,断开连接
> https协议中,在请求以及响应时多了一层tls,ssl加密解密协议,默认端口从80变为了443
### WebSocket
- 微服务
- 服务器相关
- 操作系统
- 极客时间操作系统实战笔记
- 01 程序的运行过程:从代码到机器运行
- 02 几行汇编几行C:实现一个最简单的内核
- 03 黑盒之中有什么:内核结构与设计
- Rust
- 入门:Rust开发一个简单的web服务器
- Rust的引用和租借
- 函数与函数指针
- Rust中如何面向对象编程
- 构建单线程web服务器
- 在服务器中增加线程池提高吞吐
- Java
- 并发编程
- 并发基础
- 1.创建并启动线程
- 2.java线程生命周期以及start源码剖析
- 3.采用多线程模拟银行排队叫号
- 4.Runnable接口存在的必要性
- 5.策略模式在Thread和Runnable中的应用分析
- 6.Daemon线程的创建以及使用场景分析
- 7.线程ID,优先级
- 8.Thread的join方法
- 9.Thread中断Interrupt方法学习&采用优雅的方式结束线程生命周期
- 10.编写ThreadService实现暴力结束线程
- 11.线程同步问题以及synchronized的引入
- 12.同步代码块以及同步方法之间的区别和关系
- 13.通过实验分析This锁和Class锁的存在
- 14.多线程死锁分析以及案例介绍
- 15.线程间通信快速入门,使用wait和notify进行线程间的数据通信
- 16.多Product多Consumer之间的通讯导致出现程序假死的原因分析
- 17.使用notifyAll完善多线程下的生产者消费者模型
- 18.wait和sleep的本质区别
- 19.完善数据采集程序
- 20.如何实现一个自己的显式锁Lock
- 21.addShutdownHook给你的程序注入钩子
- 22.如何捕获线程运行期间的异常
- 23.ThreadGroup API介绍
- 24.线程池原理与自定义线程池一
- 25.给线程池增加拒绝策略以及停止方法
- 26.给线程池增加自动扩充,闲时自动回收线程的功能
- JVM
- C&C++
- GDB调试工具笔记
- C&C++基础
- 一个例子理解C语言数据类型的本质
- 字节顺序-大小端模式
- Php
- Php源码阅读笔记
- Swoole相关
- Swoole基础
- php的五种运行模式
- FPM模式的生命周期
- OSI网络七层图片速查
- IP/TCP/UPD/HTTP
- swoole源代码编译安装
- 安全相关
- MySql
- Mysql基础
- 1.事务与锁
- 2.事务隔离级别与IO的关系
- 3.mysql锁机制与结构
- 4.mysql结构与sql执行
- 5.mysql物理文件
- 6.mysql性能问题
- Docker&K8s
- Docker安装java8
- Redis
- 分布式部署相关
- Redis的主从复制
- Redis的哨兵
- redis-Cluster分区方案&应用场景
- redis-Cluster哈希虚拟槽&简单搭建
- redis-Cluster redis-trib.rb 搭建&原理
- redis-Cluster集群的伸缩调优
- 源码阅读笔记
- Mq
- ELK
- ElasticSearch
- Logstash
- Kibana
- 一些好玩的东西
- 一次折腾了几天的大华摄像头调试经历
- 搬砖实用代码
- python读取excel拼接sql
- mysql大批量插入数据四种方法
- composer好用的镜像源
- ab
- 环境搭建与配置
- face_recognition本地调试笔记
- 虚拟机配置静态ip
- Centos7 Init Shell
- 发布自己的Composer包
- git推送一直失败怎么办
- Beyond Compare过期解决办法
- 我的Navicat for Mysql
- 小错误解决办法
- CLoin报错CreateProcess error=216
- mysql error You must reset your password using ALTER USER statement before executing this statement.
- VM无法连接到虚拟机
- Jetbrains相关
- IntelliJ IDEA 笔记
- CLoin的配置与使用
- PhpStormDocker环境下配置Xdebug
- PhpStorm advanced metadata
- PhpStorm PHP_CodeSniffer