网络协议编程

一、网络协议和网络常用工具

一计算机网络体系结构

1、TCP/IP模型 OSI七层模型

TCP/IP协议族 TransmissionControlProtocol/InternetProtocol 的简写,中译名为传输控制协议/因特网 互联协议,是 Internet 最基本的协议、Internet 国际互联网络的基础,由网络层的 IP 协议和 传输层的 TCP 协议组成。协议采用了 4 层的层级结构。然而在很多情况下,它是利用 IP 进 行通信时所必须用到的协议群的统称。也就是说,它其实是个协议家族,由很多个协议组成, 并且是在不同的层, 是互联网的基础通信架构。


 

 

2、数据包结构

3、TCP概述

    概念:tcp是面向链接的通信协议,通过三次握手建立链接然后才能开始数据的读写,是一种可靠的数据流服务,数据有可能被拆分后发送,那么采用超时重传机 制是和应答确认机制是组成 TCP 可靠传输的关键设计

   基本特性 (可靠性原因):

  1.   面向链接,可靠的数据流服务:
  2.   RTT(重传超时值)和RTO(超时重传机):   超时的时长就需要根据网络情况动态调整,就需要采样统计一个数据包从发送端发送出去到接收到这个包的回复这段时长来动态设 置重传超时值,这个时长就是为 RTT,学名 round-triptime,然后再根据这个 RTT 通过各种 算法和公式平滑 RTT 值后,最终确定重传超时值。 
  3.  数据排序 : IP 层进行数据传输时,是不能保证数据包按照发送的顺序达到目的机器。当 IP 将把 它们向‘上’传送到 TCP 层后,TCP 将包排序并进行错误检查。TCP 数据包中包括序号和确认, 所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
  4.  流量控制、:TCP 还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用 以限制发送方的发送速度。
  5. 一种双全工协议: 同时 TCP 还允许在一个 TCP 连接上,通信的双方可以同时传输数据,也就是所谓的全双工

  TCP连接中的三次握手

           所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认 连接的建立。在 socket 编程中,这一过程由客户端执行 connect 来触发。

  •  第一次握手:客户端将标志位 SYN 置为 1,随机产生一个值 seq=J,并将该数据包发送 给服务器端,客户端进入 SYN_SENT(发送) 状态,等待服务器端确认。
  •  第二次握手:服务器端收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务 器端将标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个值 seq=K,并将该数据包发送给 客户                         端以确认连接请求,服务器端进入 SYN_RCVD 状态。
  • 第三次握手:客户端收到确认后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确则将 标志位 ACK 置为 1, ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为 K+1,                            ACK 是否为 1,如果正确则连接建立成功,客户端和服务器端进入 ESTABLISHED(链接建立的) 状态,完成 三次握手,随后客户端与服务器端之间可以开始传输数据了

   三次握手的全过程全部由操作系统来负责,由内核来负责的

为什么需要三次握手?

            tcp是面对连接的,所以需要双方都确认连接的建立

           TCP 是可靠的传输控制协议,而三次握手是保证数据可靠传输又能提高传输效率的最小 次数。为什么?RFC793,也就是 TCP 的协议 RFC 中就谈到了原因,这是因为: 为了实现可靠数据传输, TCP 协议的通信双方,都必须维护一个序列号, 以标识发送 出去的数据包中,哪些是已经被对方收到的。

           举例说明:发送方在发送数据包(假设大小为 10byte)时, 同时送上一个序号( 假设 为 500),那么接收方收到这个数据包以后, 就可以回复一个确认号(510=500+10) 告 诉发送方 “我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 511 开始” 。
         三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号 起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列 号则得不到确认。至于为什么不是四次,很明显,三次握手后,通信的双方都已经知道了对方序列号起始 值,也确认了对方知道自己序列号起始值,第四次握手已经毫无必要了

TCP的三次握手的漏洞------SYN洪泛攻击

         概念:通过网络服务所在的端口发送大量伪造原地址的攻击报文,发送到服务器端,造成服务端上的半开连接队列被占满,从而阻止其他用户访问

         原理:攻击者客户端利用伪造的IP地址向服务端发出请求(第一次握手) 而服务器端的响应(第二次握手)的报文将永远发送不到真实的客户端,服务端在等待客户端第三次握手永远也不会等到,服务端在等待这种半开的连接过程中消耗了资源,如果有成千上万的这种连接,主机资源将被耗尽,从而达到攻击的目的

         解决方案:

  •    防火墙(最好):防火墙在确认了连接的有效性后,才向内部的服务器(Listener)发起 SYN 请求
  •    延缓TCB分配方法:一般的做完第一次握手之后,服务器就需要为该请求分配一个 TCB(连接控 制资源),通常这个资源需要 200 多个字节。延迟 TCB 的分配,当正常连接建立起来后再分配 TCB 则可以有效地减轻服务器资源的消耗。
  •   无效连接监控释放:这种方法不停监视所有的连接,包括三次握手的,还有握手一次的,反正是 所有的,当达到一定(与)阈值时拆除这些连接,从而释放系统资源。这种方法于所有的连接  一视同仁,不管是正常的还是攻击的,所以这种方式不推荐

     

TCP的四次挥手

      定义:   四次挥手即终止 TCP 连接,就是指断开一个 TCP 连接时,需要客户端和服务端总共发 送 4 个包以确认连接的断开。在 socket 编程中,这一过程由客户端或服务端任一方执行 close 来触发。 由于 TCP 连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当甲方 完成数据发送任务后,发送一个 FIN 给乙方来终止这一方向的连接,乙方收到一个 FIN 只是 意味着不会再收到甲方数据了,但是乙方依然可以给甲方发送数据,直到这乙方也发送了 FIN 给甲方。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

      过程:

              第一挥手:客户端发送关闭请求

              第二次挥手:服务端响应客户端关闭请求

              第三次挥手:服务端发送关闭请求

              第四次挥手:客户端发送关闭确认请求

(1) 某个应用进程首先调用 close,我们称该端执行主动关闭(activeclose)。该端的 TCP 于是发送一个 FIN 分节,表示数据发送完毕,应用进程进入 FIN-WAIT-1(终止等待 1)状态。

(2)接收到这个 FIN 的对端执行被动关闭(passiveclose),发出确认报文。这个 FIN 由 TCP 确认。因为 FIN 的接收意味着接收端应用进程在相应连接上再无额外数据可接收。接收端进 入了 CLOSE-WAIT(关闭等待)状态,这时候处于半关闭状态,即主动关闭端已经没有数据 要发送了,但是被动关闭端若发送数据,主动关闭端依然要接受。这个状态还要持续一段时 间,也就是整个 CLOSE-WAIT 状态持续的时间。主动关闭端收到确认报文后进入 FIN-WAIT-2 (终止等待 2)状态。

(3)一段时间后,被动关闭的应用进程将调用 close 关闭它的套接字。这导致它的 TCP 也 发送一个 FIN。

(4)接收这个最终 FIN 的原发送端 TCP(即执行主动关闭的那一端)确认这个 FIN 发出一 个确认 ACK 报文,并进入了 TIME-WAIT(时间等待)状态。注意此时 TCP 连接还没有释放, 必须经过 2∗MSL(最长报文段寿命/最长分节生命期 maxsegementlifetime,MSL 是任何 IP 数据报能够在因特网中存活的最长时间,任何 TCP 实现都必须为 MSL 选择一个值。RFC 1122[Braden1989]的建议值是 2 分钟,不过源自 Berkelcy 的实现传统上改用 30 秒这个值。 这意味着 TIME_WAIT 状态的持续时间在 1 分钟到 4 分钟之间)的时间后,当主动关闭端撤 销相应的 TCB 后,才进入 CLOSED 状态。
(5) 被动关闭端只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结束了这次的 TCP 连接。可以看到,被动关闭端结束 TCP 连接的时间要比主动关闭 端早一些。 既然每个方向都需要一个 FIN 和一个 ACK,因此通常需要 4 个分节。我们使用限定词“通 常”是因为:某些情形下步骤 1 的 FIN 随数据一起发送;另外,步骤 2 和步骤 3 发送的分节 都出自执行被动关闭那-一端,有可能被合并成一个分节。
 

为什么要四次挥手?

      TCP是全双工(即客户端和服务端可以互相发送和接收请求),所以需要双方都确认关闭连接。

      TCP 是全双工的连接,必须两端同时关闭连接,连接才算真正关闭。 如果一方已经准备关闭写,但是它还可以读另一方发送的数据。发送给 FIN 结束报文给 对方,对方收到后,回复 ACK         报文。当这方也已经写完了准备关闭,发送 FIN 报文,对方回 复 ACK。两端都关闭,TCP 连接正常关闭

为什么需要TIME-WAIT状态(主动关闭连接的一端会进去time-wait状态)

      可靠的终止连接、保证让迟来的 TCP 报文有足够的时间被识别并丢弃  MSL

4、一次完整的http请求过程

  1. 首先进行DNS域名解析(本地l浏览器缓存,操作系统缓存或者DNS服务器)
  2. 三次握手建立TCP连接
  3. 客户端发起HTTP请求
  4. 服务器响应HTTP请求
  5. 客户端解析html代码,并请求html代码中的资源
  6. 客户端渲染展示内容
  7. 关闭TCP连接

二、JAVA原始网络编程

网络编程中Socket是什么

Scoket是应用层与TCP/IP协议族通信的中间软件抽象层,他是一组接口,其实j就是一个门面模式,TCP用主机的IP地址加上主机的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)

短连接: 连接->传输数据->关闭连接

               传统 HTTP 是无状态的,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,但任 务结束就中断连接。 也可以这样说:短连接是指 SOCKET 连接后发送后接收完数据后马上断开连接。
长连接: 连接->传输数据->保持连接 ->传输数据->。。。 ->关闭连接。

                 长连接指建立 SOCKET 连接后不管是否使用都保持连接。 什么时候用长连接,短连接? 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个 TCP 连 接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降 低很多,所以每个操作完后都不断开,下次处理时直接发送数据包就 OK 了,不用建立 TCP 连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成 socket 错误,而且 频繁的 socket 创建也是对资源的浪费。 而像 WEB 网站的 http 服务一般都用短链接,因为长连接对于服务端来说会耗费一定的 资源,而像 WEB 网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源。 总之,长连接和短连接的选择要视情况而定。

一、原生JDK网络编程-BIO

传统的同步阻塞模型开发中,ServerSocket 负责绑定 IP 地址,启动监听端口;Socket 负 责发起连接操作。连接成功后,双方通过输入和输出流进行同步阻塞式通信

BIO应用-RPC框架

实现RPC框架需要解决的那些问题?

代 理 问 题

               代理本质上是要解决什么问题?要解决的是被调用的服务本质上是远程的服务,但是调 用者不知道也不关心,调用者只要结果,具体的事情由代理的那个对象来负责这件事。既然 是远程代理,当然是要用代理模式了。 代理(Proxy)是一种设计模式,即通过代理对象访问目标对象.这样做的好处是:可以在目 标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。那我们这里额外的功能 操作是干什么,通过网络访问远程服务。 jdk 的代理有两种实现方式:静态代理和动态代理。
序 列 化 问 题

                序列化问题在计算机里具体是什么?我们的方法调用,有方法名,方法参数,这些可能 是字符串,可能是我们自己定义的 java 的类,但是在网络上传输或者保存在硬盘的时候, 网络或者硬盘并不认得什么字符串或者 javabean,它只认得二进制的 01 串,怎么办?要进 行序列化,网络传输后要进行实际调用,就要把二进制的 01 串变回我们实际的 java 的类, 这个叫反序列化。java 里已经为我们提供了相关的机制 Serializable。(JDK提供的序列号机制相比其他第三方序列化框架而言性能较差)
通 信 问 题 

            我们在用序列化把东西变成了可以在网络上传输的二进制的 01 串,但具体如何通过网 络传输?使用 JDK 为我们提供的 BIO。
登 记 的 服 务 实 例 化

           登记的服务有可能在我们的系统中就是一个名字,怎么变成实际执行的对象实例,当然 是使用反射机制。
实现RPC框架

  1. 服务端定义接口和服务实现类并且注册服务
  2. 客户端使用动态代理调用服务
  3. 客户端代理把调用对象、方法、参数序列化成数据
  4. 客户端代理与服务端通过Socket通讯传输数据
  5. 服务端反序列化数据成对象、方法、参数
  6. 服务端代理拿到这些对象和参数后通过反射的机制调用服务的实例

TCP(Dubbo)和HTTP(SpringCloud)哪个更好?

  1. 协议上来说:http相对更加规范,更标准,更通用,无论那种语言都是支持http协议的,。如 果你是对外开放 API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的 支持,相应的,如果采用 http,无疑在你实现 SDK 之前,支持了所有语言,所以,现在开 源中间件,基本最先支持的几个协议都包含 RESTful。 
  2. TCP 协议性能要高的多,例如 Protobuf、Thrift、Kyro 等,(如果算上序列化)吞吐量大 概能达到 http 的二倍。响应时间也更为出色。千万不要小看这点性能损耗,公认的,微服 务做的比较好的,例如,netflix、阿里,曾经都传出过为了提升性能而合并服务。
  3. 服务全面上比较:当然是 springloud 更胜一筹,但也就意味着在使用 springloud 上其实 更重量级一点,dubbo 目前版本专注于服务治理,使用上更轻量一点。 就国内的热度来说,如果我们看百度指数的查询结果,springloud 和 dubbo 几乎是半斤 八两,dubbo 相比起来还略胜一筹 总的来说对外开放的服务推荐采用 RESTful,内部调用推荐采用 RPC 方式。当然不能一 概而论,还要看具体的业务场景。

二、原生JDK网络编程-NIO

什么是NIO?

      NIO 库是在 JDK1.4 中引入的。NIO 弥补了原来的 I/O 的不足,它在标准 Java 代码 中提供了高速的、面向块的 I/O。NIO 翻译成 no-blockingio 或者 newio 

     NIO是多路复用的机制

和BIO的区别

1、 BIO 是面向流的,NIO 是面向缓冲区的。JavaIO 面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地 方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它 缓存到一个缓冲区。 JavaNIO 的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓 冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查 是否该缓冲区中包含所有需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要 覆盖缓冲区里尚未处理的数据。

就一次网络读写而言 BIO还是更快  操作系统实现角度来讲  BIO一次系统调用,NIO俩次系统调用,系统调用是一个比较昂贵的操作

阻塞与非阻塞IO JavaIO 的各种流是阻塞的。

         这意味着,当一个线程调用 read() 或 write()时,该线程被 阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 JavaNIO 的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目 前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以 直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线 程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞 IO 的空闲时间用于在其它通道上执行 IO 操作,所以一个单独的线程现在 可以管理多个输入和输出通道(channel)。
NIO三大核心组件以及关系

一、Selector(选择器)

           JavaNIO 的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用 一个选择器(Selectors),然后使用一个单独的线程来操作这个选择器,进而“选择”通道:
这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个 单独的线程很容易来管理多个通道。 应用程序将向 Selector 对象注册需要它关注的 Channel,以及具体的某一个 Channel 会 对哪些 IO 事件感兴趣。Selector 中也会维护一个“已经注册的 Channel”的容器。 

二、Channel(通道)

           通道,被建立的一个应用程序和操作系统交互事件、传递内容的渠道(注意是连接到操 作系统)。所有被 Selector(选择器)注册的通道,只能是继承了 SelectableChannel 类的子类。

          ServerSocketChannel:应用服务器程序的监听通道。只有通过这个通道,应用程序才 能向操作系统注册支持“多路复用 IO”的端口监听。同时支持 UDP 协议和 TCP 协议。 

          ScoketChannel:TCPSocket 套接字的监听通道,一个 Socket 套接字对应了一个客户 端 IP:端口 到 服务器 IP:端口的通信连接。

三、Buffer (缓冲区)

Buffer 用于和 NIO 通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。 以写为例,应用程序都是将数据写入缓冲,再通过通道把缓冲的数据发送出去,读也是一样, 数据总是先从通道读到缓冲,应用程序再读缓冲的数据。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存( 其实就是数组)。 这块内存被包装成 NIOBuffer 对象,并提供了一组方法,用来方便的访问该块内存

基本关系:channel把自己感兴趣的事件注册到Selector,如果有自己需要的事件就通知到对应的通道,ServerSocketChannel告诉selector注册关注客户端的连接,ScoketChanne告诉selector关注客户端的输入 socketchannel会去网络上读取数据写入到buffer中,业务端从buffer中读取数据,业务处理完了将相关的数据也写入到buffer,进而通过socketchannel写回到对应的客户端

 

什 么 是 SelectionKey

           SelectionKey是一个抽象类,表示selectableChannel在Selector中注册的标识.每个Channel 向 Selector 注册时,都将会创建一个 SelectionKey。SelectionKey 将 Channel 与 Selector 建立了 关系,并维护了 channel 事件。可以通过 cancel 方法取消键,取消的键不会立即从 selector 中移除,而是添加到 cancelledKeys 中,在下一次 select 操作时移除它.所以在调用某个 key 时,需要使用 isValid 进行 校验

.操作类型 就绪条件及说明

  • OP_READ 当操作系统读缓冲区有数据可读时就绪。并非时刻都有数据可读,所 以一般需要注册该操作,仅当有就绪时才发起读操作,有的放矢,避免浪 费 CPU。
  • OP_WRITE 当操作系统写缓冲区有空闲空间时就绪。一般情况下写缓冲区都有空 闲空间,小块数据直接写入即可,没必要注册该操作类型,否则该条件不 断就绪浪费 CPU;但如果是写密集型的任务,比如文件下载等,缓冲区很 可能满,注册该操作类型就很有必要,同时注意写完后取消注册。
  • OP_CONNECT 当 SocketChannel.connect()请求连接成功后就绪。该操作只给客户端 使用。
  • OP_ACCEPT 当接收到一个客户端连接请求时就绪。该操作只给服务器使用

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值