TCP协议——网络通信

                          一、  网络通信概念

网络通信概述:从进程间通信说起网络域套接字socket,网络通信其实就是位于网络中不同主机上面的两个进程之间的通信;网络通信的层次可分为(1)硬件部分:网卡(2)操作系统底层:网卡驱动(3)操作系统API:socket接口(4)应用层:低级(直接基于socket接口编程)(5)应用层:高级(基于网络通信应用框架库)(6)应用层:更高级(http、网络控件等)。

发展历程和传输媒介:单机阶段、局域网阶段、广域网Internet阶段、移动互联网阶段、物联网阶段;无线传输有Wifi、蓝牙、Zigbee、4G/5G等,有线通信包括双绞线、同轴电缆、光线等。

OSI7层网络模型:物理层、数据链路层、网络层、传输层、表示层、会话层、应用层。

基础知识

网卡:(1)计算机上网必备硬件设备,CPU靠网卡来连接外部网络   (2)串转并设备  (3)数据帧封包和拆包 (4)网络数据缓存和速率适配

集线器(HUB):(1)信号中继放大,相当于中继器  (2)组成局域网络,用广播方式工作。  (3)注意集线器是不能用来连接外网的

交换机 (1)包含集线器功能,但更高级 (2)交换机中有地址表,数据包查表后直达目的通信口而不是广播 (3)找不到目的口时广播并学习

路由器:(1)路由器是局域网和外部网络通信的出入口 (2)路由器将整个internet划分成一个个的局域网,却又互相联通。 (3)路由器对内管理子网(局域网),可以在路由器中设置子网的网段,设置有线端口的IP地址,设置dhcp功能等,因此局域网的IP地址是路由器决定的。 (4)路由器对外实现联网,联网方式取决于外部网络(如ADSL拨号上网、宽带帐号、局域网等)。这时候路由器又相当于是更高层级网络的其中一个节点而已。 (5)所以路由器相当于有2个网卡,一个对内做网关、一个对外做节点。(6)路由器的主要功能是为经过路由器的每个数据包寻找一条最佳路径(路由)并转发出去。其实就是局域网内电脑要发到外网的数据包,和外网回复给局域网内电脑的数据包。 (7)路由器技术是网络中最重要技术,决定了网络的稳定性和速度。

DNS(Domain Name Service 域名服务): (1)网络世界的门牌号:IP地址  (2)IP地址的缺点:难记、不直观   (3)IP地址的替代品:域名,譬如www.baidu.com  (4)DNS服务器就是专门提供域名和IP地址之间的转换的服务的,因此域名要购买的  (5)我们访问一个网站的流程是:先使用IP地址(譬如谷歌的DNS服务器IP地址为8.8.8.8)访问DNS服务器(DNS服务器不能是域名,只能是直接的IP地址),查询我们要访问的域名的IP地址,然后再使用该IP地址访问我们真正要访问的网站。这个过程被浏览器封装屏蔽,其中使用的就是DNS协议。  (6)浏览器需要DNS服务,而QQ这样的客户端却不需要(因为QQ软件编程时已经知道了腾讯的服务器的IP地址,因此可以直接IP方式访问服务器)

DHCP(dynamic host configuration protocl,动态主机配置协议):

(1)每台计算机都需要一个IP地址,且局域网内各电脑IP地址不能重复,否则会地址冲突。

(2)计算机的IP地址可以静态设定,也可以动态分配

(3)动态分配是局域网内的DHCP服务器来协调的,很多设备都能提供DHCP功能,譬如路由器。

(4)动态分配的优势:方便接入和断开、有限的IP地址得到充分利用

NAT(network address translation,网络地址转换协议):

(1)IP地址分为公网IP(internet范围内唯一的IP地址)和私网IP(内网IP),局域网内的电脑使用的都是私网IP(常用的就是192.168.1.xx)

(2)网络通信的数据包中包含有目的地址的IP地址

(3)当局域网中的主机要发送数据包给外网时,路由器要负责将数据包头中的局域网主机的内网IP替换为当前局域网的对外外网IP。这个过程就叫NAT。

(4)NAT的作用是缓解IPv4的IP地址不够用问题,但只是类似于打补丁的形式,最终的解决方案还是要靠IPv6。

(5)NAT穿透简介

IP地址分类(IPv4):

(1)IP地址实际是一个32位二进制构成,在网络通信数据包中就是32位二进制,而在人机交互中使用点分十进制方式显示。

(2)IP地址中32位实际包含2部分,分别为:网络地址和主机地址。子网掩码,用来说明网络地址和主机地址各自占多少位。

(3)由网络地址和主机地址分别占多少位的不同,将IP地址分为5类,最常用的有3类

如何判断2个IP地址是否在同一子网内?

(1)网络标识 = IP地址 & 子网掩码

(2)2个IP地址的网络标识一样,那么就处于同一网络。

源IP地址:发出数据包的网络的IP地址   ;    目标IP地址:要接收数据包的计算机的IP地址

二进制方式                  0xffffffff                 0xC0A80166/0x6601A8C0          本质

点分十进制方式           255.255.255.255           192.168.1.102                     方便人看的

 

IP地址 = 网络地址 + 主机地址  ,  网络地址用来表示子网  ,  主机地址是用来表示子网中的具体某一台主机的。

譬如可以8位表示网络,24位表示主机 ;  也可以16位表示网络,16位表示主机  ;14为表示网络,18位表示主机

 

子网掩码为255.255.255.0时表示前24位为网络地址,后8位为主机地址

子网掩码为255.255.0.0时表示前16位为网络地址,后16位为主机地址

 

网络地址决定了这种网络中一定可以有多少个网络,譬如子网掩码为255.255.255.0时表示我们这一种网络一共最多可以有2^24个,每个这种网络中可以有2^8个主机。

如果子网掩码为255.255.0.0时,表示我们这种网络可以有2^16个网络,每个这种网络中最多可以有2^16个主机。

 

192.168.1.102 & 255.255.255.0 = 192.168.1.0

192.168.1.253 & 255.255.255.0 = 192.168.1.0

 

192.168.1.4和192.168.12.5,如果子网掩码是255.255.255.0那么不在同一网段,如果子网掩码是255.255.0.0那么就在同一个网段.

                                二 、 socket编程

1. 套接字类型:

流格式套接字(sock_stream),可靠的、双向的通信数据流,数据准确无误如果损坏可以重新发送;特征表现为:数据不会消失,按照顺序传输,数据的发送和接受不是同步的;类比传送带。TCP协议确保数据的正确性,IP用来控制数据如何从源头到达目的地。

例如:浏览器所使用的的http协议就是基于面向连接的套接字。

数据报格式套接字(sock_dgram):无面向连接的套接字。只管传输数据不做校验,若有错误无法重传;特征表现为强调速度而非顺序,数据可能丢失或损毁,限制每次传输的数据大小,数据的发送和接受是同步的;数据报套接字是一种不可靠、不按顺序传递的、追求速度的套接字;使用IP协议作路由,但不使用TCP协议,而是UDP协议(user datagram protocol)。例如:qq视频聊天语音聊天。

2 面向连接和无面向连接的区别

                                      

无连接套接字传输效率高,但是不可靠,有丢失数据包、捣乱数据的风险; 有连接套接字非常可靠,但是传输效率低、耗费资源多;应用:有连接的套接字(TCP服务),比如http、ftp;无连接的套接字(UDP服务),比如DNS、即时聊天工具。

3 . OSI网络七层模型

                                         

     网络模型简而言之就是用来数据封装的,socket编程是站在传输层的基础上,所以可以用TCP/UDP协议,但是不能干【访问网页】的事,因为访问网页所需要的http协议位于应用层。两台计算机通信原则:同一层次;每一层功能必须相同;数据只能逐层传输;每一层可以使用下层提供的服务。

4 .TCP/IP协议族

                                      

    找到一台计算机需要知道IP地址、MAC地址(LAN)和端口号,IP地址寻找局域网,每个网卡的MAC地址独一无二,定位哪台计算机;端口号定位哪个网络程序例如Web服务端口号80、FTP服务端口号21。

5. socket函数用法详解

  Int socket (int af , int type , int protocol)

注:af为IP类型,常用的有IPv4和IPv6,AF_INET表示IPv4, AF_INET6表示IPv6。type为数据传输方式/套接字类型,常用的有流格式面向连接的套接字和数据报无面向连接的套接字;protocol表示传输协议,常用的有TCP协议和UDP协议。

6.  bind和connect函数

Socket函数用来创建套接字,然后服务器端要用bind函数将套接字与特定的IP地址和端口绑定起来;类似的客户端也要用connect函数建立连接。socket被翻译为套接字,它是计算机之间进行通信的一种约定或方式。

 bind 原型:int bind (int sock, struct sockaddr *addr, socklen_t addrlen)

举例:

                                        

Connect 函数原型:connect (int sock , struct sockaddr *addr, socklen_t addrlen)

7. 对于服务器端程序,使用bind()绑定套接字后,还需要用listen()函数让套接字进入被动监听状态,再调用accept()函数,响应客户需求。

  Int listen (int sock , int  backlog);sock为需要进入监听状态的套接字,backlog为请求队列的最大长度。Listen()只是让套接字处于监听状态,并没有接收请求,接收请求需要使用accept()函数。 accept()函数来接收客户端请求,原型为int accept (int sock, struct sockaddr *addr, socklen_t *addrlen);accept()返回一个新的套接字来和客户端通信,addr保存了客户端的IP地址和端口号,而sock是服务器端的套接字,后面和客户端通信时要使用这个新生成的套接字,而不是原来服务器端的套接字。accept()会阻塞程序执行(后面代码不被执行),直到有新的请求到来。

8 Linux中的数据接收和发送

服务器端用write()向套接字写入数据,客户端就能收到,再使用read()从套接字中读取出来,就完成了一次通信。write()原型:ssize_t write (int fd , const void *buf, size_t nbytes);fd为要写入的文件的描述符,buf为要写入的数据的缓冲区地址,nbytes为要写入的数据的字节数。

  Write()函数会将缓冲区buf中的nbytes个字节写入文件fd,成功则返回写入的字节数,失败则返回-1。

 Read()原型:ssize_t read(int fd , void *buf, size_t nbytes);read()函数会从fd文件中读取nbytes个字节并保存到缓冲区buf,成功则返回读取到的字节数,失败则返回-1。

9 TCP协议的粘包问题

 发送1和3服务器可能当成13来处理。

10 . TCP数据的传输过程

  Ack号=Seq号+传递的字节数+1;如果传输错误会有自适应算法的定时器重新发送。

                                             

TCP协议的三次握手:

(1)建立连接需要三次握手

(2)建立连接的条件:服务器listen时客户端主动发起connect

                                          

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

四次挥手:

                                           

1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

……………………………………………………………………………………………………………………………………………………

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

 

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

【问题3】为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

       现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值