此文章是根据C语言中文网和网络资源学习所做笔记,内容多有相似,请见谅
1. IP地址(IP Address)
计算机分布在世界各地,要想和他们进行通信,必须知道确切的位置。确定计算机位置的方式有多种,例如,114.114.114.114 是国内第一个、全球第三个开放的 DNS 服务地址,127.0.0.1 是本机地址。其实,我们的计算机并不知道 IP 地址对应的地理位置,当要通信时,只是将 IP 地址封装到要发送的数据包中,交给路由器去处理。路由器有非常智能和高效的算法,很快就会找到目标计算机,并将数据包传递给它,完成一次单向通信。
2. 端口(Port)
有了IP地址,虽然可以找到目标计算机,但是仍然不能进行通信。一台计算机可以提供多种网络服务,例如Web服务、FTP服务(文件传输服务)、SMTP服务(邮箱服务)等,仅有 IP 地址,计算机虽然可以正确接收到数据包,但是却不知道要将数据包交给哪个网络程序来处理,所以通信失败。
为了区分不同的应用程序,计算机为每个网络程序分配一个独一无二的端口号,例如,Web服务器的端口号是80,FTP服务器的端口号是21,SMTP服务的端口号是25.
端口是一个虚拟,逻辑上的概念,可以将端口号理解为一道门,数据从这道门流入流出,每道门有不同编号,就是端口号,如图所示:

3. 协议
协议(Protocol)就是网络通信的约定,通信的双方必须都遵守才能正常收发数据。协议有很多种,例如 TCP、UDP、IP 等,通信的双方必须使用同一协议才能通信。协议是一种规范,由计算机组织制定,规定了很多细节,例如,如何建立连接,如何相互识别等。
协议仅仅是一种规范,必须由计算机软件来实现。例如 IP 协议规定了如何找到目标计算机,那么各个开发商在开发自己的软件时就必须遵守该协议,不能另起炉灶。
所谓协议族(Protocol Family),就是一组协议(多个协议)的统称。最常用的是 TCP/IP 协议族,它包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百个互为关联的协议,由于 TCP、IP 是两种常用的底层协议,所以把它们统称为 TCP/IP 协议族。
4. 数据传输方式
计算机之间的传输方式有很多种,常用的有两种:SOCK_STREAM和SOCK_DGRAM。
SOCK_STREAM表示面向连接的数据传输方式。数据可以准确无误到达另一台计算机,如果数据丢失,计算机重新发送,但是效率相对较慢。常用的http协议就是使用SOCK_STREAM传输数据,要确保数据的准确性,否则网页不能正常解析。
SOCK_DGRAM 表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响。 注意:SOCK_DGRAM 没有想象中的糟糕,不会频繁的丢失数据,数据错误只是小概率事件。 有可能多种协议使用同一种数据传输方式,所以在 socket 编程中,需要同时指明数据传输方式和协议。
综上所述,IP地址和端口能够在广袤都互联网中定位到要通信的程序,协议和数据传输方式规定了如何传输数据,有了这些,计算机就可以正常通信了。 ,实际上是两个 socket 文件的相互读写。
5.TCP数据结构以及三次握手
TCP是一种面向连接的,可靠的,基于字节流的通信协议,数据在传输前要建立连接,传输完毕之后要断开连接。TCP建立连接时要传输三个数据包,俗称三次握手,可以比喻为:
- [Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。”
- [Shake 2] 套接字B:“好的,我这边已准备就绪。”
- [Shake 3] 套接字A:“谢谢你受理我的请求。
TCP的数据包结构
带阴影的几个字段需要重点说明一下:
- 序号:Seq序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。
- 确认号:Ack,确认号占32位,客户端和服务端都可以发送,Ack = Seq+1
- 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
- URG:紧急指针(urgent pointer)有效。
- ACK:确认序号有效。
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接。
- SYN:建立一个新连接。
- FIN:断开一个连接。
对英文字母缩写的总结:Seq 是 Sequence 的缩写,表示序列;Ack(ACK) 是 Acknowledge 的缩写,表示确认;SYN 是 Synchronous 的缩写,愿意是“同步的”,这里表示建立同步连接;FIN 是 Finish 的缩写,表示完成。

- 第一次握手:客户端向服务器发出连接请求报文,这是报文首部SYN=1,同时选择初始化序列号seq=x,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
- 服务器接收到SYN之后,发出确认报文,确认报文中ACK=1,SYN=1,确认号ack=x+1,同时也要为自己初始化一个序列号seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
- TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
简单来说就是:
- 客户端发送SYN到服务器
- 服务器接收到SYN,发送ACK,SYN到客户端
- 客户端接收到服务端数据,发送确认ACK到服务端,客户端进入ESTABLISHED状态,服务端接收到确认也进入ESTABLISHED状态,之后双方就可以进行通信了
6.TCP四次挥手

- 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
- 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也3. 就是整个CLOSE-WAIT状态持续的时间。客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
- 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
- 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
简单来说:
- 客户端发出连接释放报文FIN到服务端(客户端FIN_WAIT1)
- 服务端收到客户端发来的连接释放报文,发送ACK给客户端(FIN_WAIT2)
- 服务端将未发送的数据全部发送完毕之后,发送连接释放报文FIN给客户端
- 客户端接收到服务端的释放连接报文,发送确认包到服务端,进入TIME_WAIT状态,服务端收到应答立马关闭此连接。
7.TIME_WAIT状态:
TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待2*MSL(maximum segment lifetime)的时间后才能回到CLOSED状态。
等待2msl的原因:
- 保证客户端发送的最后一个ACK报文可以到达服务器,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
- 防止已经失效的连接请求报文段,客户端发送最后一个确认报文后在这个2MSL时间内所有产生的报文都从网络中消失
如何解决让其不进入TIME_WAIT状态?
- 使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个socket描述符.
流量控制:TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做 流量控制
拥塞控制:四种方式
- 四种启动方式:慢启动,拥塞避免,快重传
- 慢启动和拥塞避免:在发送数据时不知道当前网络状态,先发送小部分数据试探,如果网络状态良好就指数级增加发送数据,但也不可以无限制指数增长下去啊,设置一个慢启动阈值,超过这阈值就不指数级增长而是拥塞避免,让其线性增长。
- 快重传和快恢复:快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认,快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不用等待超时再重发。同时不进行慢启动,而是将发送量减半,进行拥塞避免算法,可以快速恢复原来的传输速率。
8.问题:
- 为什么不是两次握手?
如果使用两次握手连接,假设有这样一个场景,客户端发送第一个连接请求没有丢失,因为网络原因没有发送到服务器,这时服务器没有发送确认报文给客户端,那么客户端又重新发送连接请求给服务端,建立连接,此时之前那条连接请求又发送到了服务端,让客户端与服务端又建立了连接,造成资源浪费。
- 为什么不是4次握手?
浪费资源
- 为什么是三次握手,四次挥手?
在建立连接时,SYN和ACK可以一同发送到客户端,而断开连接时,只是客户端不再发送数据了,但还可以接收数据,服务端也不一定所有数据都已经传给对方,所以可以先把数据发完再去发送FIN报文,故就多了一次。
2.UDP
UDP用户数据报协议是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
UDP协议对比TCP优势:
- UDP无连接,不存在连接时延和维护连接的开销。
- UDP没有拥塞控制,实时性好。
- UDP面向报文,无需考虑粘包等问题。
UDP 广播,多播,单播。
3.Http
- Http协议是一个基于请求与响应模式,无状态的,应用层的协议,常基于TCP的连接方式
- 常用的HTTP方法
1,GET:示客户端向获取服务器上的资源(img/js/..),无请求主体 ,依靠地址栏传递数据给服务器
2,POST:表示客户端想传递数据给服务器,有请求主体
3,PUT:客户端想把文件防在服务器上
4,HEAD:表示只想获取指定的响应头
5,DELETE:表示客户端想删除服务器上指定的文件
6,OPTIONS:选项,保留以后使用
3.Get与Post的区别
1.Get重点在于从服务器中获取数据,POST则是发送数据
2.GET传输数据在URL中用户可见,post用户不可见
3.Get不安全,Post安全性较高
4.GET只支持ASCI字符,中文会乱码,Post支持标准字符
5.GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
4.HTTP请求与响应报文格式:
1.请求报文格式:
请求行
请求首部字体
请求内容实体
2,响应报文格式
状态行
响应首部字体
响应内容实体
4.Http状态码:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
5.HTTP缺点与HTTPS
A.通信使用明文,内容可能被窃听
B.不验证通信身份,可能遭到伪装
C.无法验证报文的完整性,可能被篡改
HTTPS就是HTTP加上加密处理(一般是SSL安全通信线路)+认证+完整性保护
本文使用 mdnice 排版