Java面试题8-网络协议与网络编程

TCP建立连接的过程-三次握手

所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:

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

TCP断开连接的过程-四次挥手

所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:

 由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

  • 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  • 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

SYN攻击

在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态. 

Syn攻击就是 攻击客户端 在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。 

Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击.在Linux下可以如下命令检测是否被 Syn攻击

netstat -n -p TCP | grep SYN_RECV1

一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等

为什么连接的时候是三次握手,关闭的时候却是四次握手

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

只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手

浏览器发生302跳转背后的逻辑

301 redirect: 301 代表永久性转移(Permanently Moved)

302 redirect: 302 代表暂时性转移(Temporarily Moved )

详细来说,301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址

301缓存的时间,有大体的统计,总的来说都是重启无效的

IE7, IE8 不会缓存301

IE 11 会缓存301,时间未知,重启无效

Chrome 会缓存301,时间未知,重启无效

Firefox 会缓存301,时间未知,重启无效

HTTP协议的交互流程

步骤一:客户端和服务器端建立连接 

步骤二: 客户端发送请求数据到服务器端(HTTP协议) 

步骤三: 服务器端接收到请求后,进行处理,然后将 处理结果响应客户端(HTTP协议) 

步骤四: 关闭客户端和服务器端的连接(HTTP1.1后不会立即关闭) 

SSL的交互流程

HTTP和HTTPS的差异

Rest和Http什么关系

restfull是一种风格,不是规范,也不是所谓的封装,他只是将http协议用的更彻底了,我们在普通的开发中,虽然说是基于http的,但是http中很多东西我们都没有用到,比如http的put,delete提交方式,通过http的Accept和Content-Type参数获得不同格式的数据。

大家都说Rest很轻量,你对Rest风格如何理解


RESTFUL特点包括:

1、每一个URI代表1种资源;

2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;

3、通过操作资源的表现形式来操作资源;

4、资源的表现形式是XML或者HTML;

5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

Restful

看Url就知道要什么

看http method就知道干什么

看http status code就知道结果如何

TCP的滑动窗口协议有什么用?讲讲原理

HTTP协议都有哪些方法

 

HTTP请求报文


HTTP请求报文结构:
第一部分是请求行, 有3个字段: 1 请求方法:(get,post,move,delete等)。 2 URL字段:(访问的URL信息)。 3 HTTP协议版本(主要有http1.0 http1.1 http2.0三种,其中http1.0属于TCP短连接类型协议,http1.1属于TCP长连接类型协议)。 第二部分是请求头部: 由关键字和值配对组成,每行一对,关键字和值用英文冒号:分隔,请求头部的作用是客户端把请求的详细信息告诉服务端,比如 Accept:Image/gif (媒体类型) Accept-Language:zh-cn(语言类型) Host:www.taobao.com(服务端主机名) 第三部分是空行: 空行的作用是通过发送回车符和换行符,告诉服务端请求头部结束。 第四部分是请求报文主体

HTTP响应报文

image.png

HTTP响应报文结构:
第一部分是起始行,用来说明服务端响应客户端的情况,一般由协议版本号, 数字状态码, 状态情况组成 HTTP/1.1:协议类型和版本号 200:状态码 OK:状态情况(访问成功) 响应报文的第二部分是响应头部 第三部分是空行,和请求报文类似 第四部分是响应报文的主体,包含所有要返还给客户端的数据,可以是文本,也可以是图片

HTTP常见响应状态码

不同范围状态码的含义:

100~199:用于指定客户端执行的某些动作

200~299:表示请求成功

300~399:用于已经跳转的页面

400~499:指出客户端的错误

500~599:指出服务端的错误

常见的状态码有:

200-OK:访问成功

301-Moved Permanently:永久跳转

403-Fobbidden:禁止访问

404-Not found:服务器找不到客户请求的页面,可能是客户端访问了不存在的页面

500-Internal Server Error:内部服务器错误

502-Bad Geteway:坏的网关

503-Service Unavailable:服务当前不可用,可能是服务器维护导致

504-Gateway timeout:网关超时

 

 

HTTP断点续传

要实现断点续传的功能,通常都需要客户端记录下当前的下载进度,并在需要续传的时候通知服务端本次需要下载的内容片段。

HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:

1.客户端下载一个1024K的文件,已经下载了其中512K

2. 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:

Range:bytes=512000-

这个头通知服务端从文件的512K位置开始传输文件

3. 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:

Content-Range:bytes 512000-/1024000

并且此时服务端返回的HTTP状态码应该是206,而不是200

但是在实际场景中,会出现一种情况,即在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?显然此时我们需要有一个标识文件唯一性的方法。在RFC2616中也有相应的定义,比如实现Last-Modified来标识文件的最后修改时间,这样即可判断出续传文件时是否已经发生过改动。同时RFC2616中还定义有一个ETag的头,可以使用ETag头来放置文件的唯一标识,比如文件的MD5值。

终端在发起续传请求时应该在HTTP头中申明If-Match 或者If-Modified-Since 字段,帮助服务端判别文件变化。

另外RFC2616中同时定义有一个If-Range头,终端如果在续传是使用If-Range。If-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时候。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据

HTTP多线程下载

假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如4个部分,然后创建4个线程,每个线程负责下载一个部分,如果文件大小为403个byte,那么你的分割方式可以为:0-99 (前100个字节),100-199(第二个100字节),200-299(第三个100字节),300-402(最后103个字节)。

分割完成,每个线程都明白自己的任务,比如线程3的任务是负责下载200-299这部分文件,现在的问题是:线程3发送一个什么样的请求报文,才能够保证只请求文件的200-299字节,而不会干扰其他线程的任务。这时,我们可以使用HTTP1.1的Range头。Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的

什么是HTTP长连接

HTTP 请求是在TCP连接上进行发送的。而TCP的连接分为:长连接,短连接。

长连接:HTTP 请求发送的时候,要先去创建一个TCP连接,然后在这个TCP连接上,把HTTP 的请求发送并接受完。一次HTTP请求结束了,浏览器就会跟服务端商量是否关闭TCP 连接。如果不关闭,TCP 连接一直开着,会有一定的消耗,但如果还有请求,可以直接在这个TCP 上发送(不需要经过三次握手这样的连接的消耗);如果关闭了,下次有请求的时候,就会重新创建连接,但它的好处是请求完即关闭能减少服务端与客户端并发连接数。

实际情况,网址的并发量可能比较大,当创建连接的次数很多时,它实际的开销可能比维持一个长连接的开销还要高一些。而且,长连接可以设置timeout (过多长时间在这个TCP 上没有请求,就会关闭),并不会一直保持这连接。因此,一般我们实际使用中,使用的都是长连接。

我们随意打开一个网站,打开控制台。点开network,然后看ConnectionID (同一个ID即同一个TCP连接),就能看到很多重复的ID。也就是存在长连接。

在HTTP1.1 版本中,HTTP连接在TCP连接中是有先后顺序的。意思是,比如有十个请求,不能并发的在一个TCP连接上发送。在一个TCP连接上,只能一个接一个发送。当我们在加载首页的时候,当然是希望它可以并发发送HTTP请求,这个时候,浏览器是可以允许创建并发的TCP连接,比如Chrome 允许的是6个(并发TCP连接)。正常情况下,我们在Chrome 中,加载首页,可以达到并发创建6个TCP连接。当页面后面还要有并发的TCP连接,那么该TCP连接将等待,浏览器会等前面的六个TCP连接中有结束的了,再调用新的TCP连接。

那么,如何保证我们的服务创建的是长连接,而不是短连接呢。我们看HTTP 请求和返回的Request Headers,Response Headers 中的Connection,如下。值是“keep-alive” 时,则表示这个连接是长连接。(发送请求的时候,浏览器希望是长连接的;如果返回的Connection 也是keep-alive 那么这个连接就是长连接的)。Connection 一般使用两个值:“keep-alive”/"close"

TCP/IP模型和OSI七层模型

image.png


image.png

webservice协议(wsdl/soap格式)

WebServices 提供一个建立分布式应用的平台,使得运行在不同操作系统和不同设备上的软件,或者是用不同的程序语言和不同厂商的软件开发工具开发的软件,所有可能的已开发和部署的软件,能够利用这一平台实现分布式计算的目的。WebServices的思想是:使得应用程序也具有 Web 分布式编程模型的松散耦合性。

WebServices三种基本元素之 SOAP

SOAP 即 Simple Object AccessProtocol 也就是简单对象访问协议。

SOAP 呢,其指导理念是“唯一一个没有发明任何新技术的技术”,

是一种用于访问 Web 服务的协议。

因为 SOAP 基于XML 和 HTTP ,其通过XML 来实现消息描述,然后再通过 HTTP 实现消息传输。

SOAP 是用于在应用程序之间进行通信的一种通信协议。

因为是基于 XML 和HTTP 的,所以其独立于语言,独立于平台,并且因为 XML 的扩展性很好,

所以基于 XML 的 SOAP 自然扩展性也不差。

通过 SOAP 可以非常方便的解决互联网中消息互联互通的需求,

其和其他的 Web 服务协议构建起 SOA 应用的技术基础。

SOAP 协议的一个重要特点是它独立于底层传输机制,Web 服务应用程序可以根据需要选择自己的数据传输协议,

可以在发送消息时来确定相应传输机制。

由于 HTTP 协议本身的一些特点和局限性,

使得当 SOAP 使用HTTP 绑定的 Web 服务并不能满足某些企业应用的需求。

比如,HTTP 不是一个可靠传输协议,所以有可能在传输过程中出现问题,

然后 HTTP 协议基于Request/Response 模型,也就是说客户端需要在等待响应消息接收完成后才能继续执行,

而此时如果响应时间过长呢?

基于上面的这些需求,便需要选择合适的传输协议了。

关于这方面的内容的话,有点深奥了,有兴趣的可以去看看 IBM 的一些关于这方面内容的介绍。

还有一点需要提及一下,那就是 SOAP 是可以绕过防火墙的,将来将会作为 W3C 的标准进行发展。

            

          

          

WebServices三种基本元素之 WSDL

WSDL 即Web Services Description Language也就是 Web 服务描述语言。

是基于 XML的用于描述 Web 服务以及如何访问 Web 服务的语言。

服务提供者通过服务描述将所有用于访问 Web服务的规范传送给服务请求者,

要实现 Web服务体系结构的松散耦合,服务描述是一个关键,

不管是请求者还是服务提供者,通过服务描述便可以不必了解对方的底层平台,编程语言等,

服务描述与底层的 SOAP 基础结构相结合,

足以封装服务请求者的应用程序和服务提供者的 Web服务之间的这个细节。

WSDL 描述了 Web服务的三个基本属性:

(1)服务所提供的操作

(2)如何访问服务

(3)服务位于何处(通过 URL 来确定就 OK 了)

        

       

    

WebServices三种基本元素之 UDDI

UDDI 即 Universal Description,Discovery and Integration,也就是通用的描述,发现以及整合。

WSDL 呢,用来描述了访问特定的 Web 服务的一些相关的信息,可以在互联网上,

或者是在企业的不同部门之间,如何来发现我们所需要的 Web 服务呢?

而 Web 服务提供商又如何将自己开发的 Web 服务公布到因特网上,

这就需要使用到 UDDI 了,UDDI的话,是一个跨产业,跨平台的开放性架构,

可以帮助 Web 服务提供商在互联网上发布 Web 服务的信息。

UDDI 呢是一种目录服务,企业可以通过 UDDI 来注册和搜索 Web 服务。

简单来时候话,UDDI 就是一个目录,只不过在这个目录中存放的是一些关于 Web 服务的信息而已。

并且 UDDI 通过SOAP 进行通讯,构建于 . Net 之上。

spdy/http2.0协议是否有了解

背景介绍

HTTP2.0跟SPDY在不少理念上是相似的,目的都是为了提升HTTP1.1的性能。

HTTP2.0将会是业界的标准,比SPDY要完善,今后可能会都转向http2.0而放弃SPDY。

SPDY流程

SPDY需要TLS1.1以上版本的支持,需要TLS的NPN扩展(Next Protocol Negotiation:13172),也就是加了一个域Query Supported Protocol List。

严重依赖SSL,不管收到的是HTTP请求,还是HTTPS请求,SPDY都会走一趟SSL握手的流程,以确定服务器是否支持SPDY。

On HTTP Request:

    TCP连接on Port 443,再SSL握手确认服务器是否支持SPDY

             不支持: 没有规定要如何处理,Drop或者走http1.1都可以

             支持: 发一些Setting Frame,做些配置,根据需要创建stream

On HTTPS Request:

   TCP连接on Port 443,再SSL握手确认服务器是否支持SPDY

             不支持: 没有规定要如何处理,Drop或者走普通https都可以

             支持: 发一些Setting Frame,做些配置,根据需要创建stream

HTTP2.0流程

需要TLS1.2以上版本,因为需要一个ALPN扩展(application Layer Protocol Negotiation)。

对HTTP1.1有很好兼容,HTTP请求就不用走SSL握手了。

On HTTP Request:

      TCP连接on Port 80

      根据是否有proir knowledge,相应配置HTTP Headers

On HTTPS Request:

      ALPN协商具体用哪个协议,HTTP2.0, SPDY or HTTP1.1

NIO的好处

Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞直到读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。

java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据。NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行

Java NIO提供了与标准IO不同的IO工作方式: 

Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。

Asynchronous IO(异步IO):Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。

Selectors(选择器):Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。

什么是零拷贝

为了更好地理解这个问题的解决方案,我们需要先理解这个问题本身。我们来看看网络服务器将存储在文件中的数据通过网络传输到客户端的简单过程。示例代码:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

看起来很简单。你可能认为就两次系统调用并没有什么开销。实际上,这可能是与真相相去甚远。这两次调用的背后,数据至少拷贝了四次,用户/内核上下文转换也几乎执行了相同的次数(这个执行过程比这复杂得多,但是我想先使它简单)。为了更好的理解这个执行过程,请看图1。上面部分展示的是上下文切换,下面部分展示的是拷贝操作。

图1 两个系统调用中的拷贝过程

  1. 第一步:read 系统调用导致一次从用户态到内核态的上下文切换。这第一次拷贝在 DMA 引擎中执行,它从磁盘中读取文件内容,并且存入内核地址空间缓存中。
  2. 第二步:数据从内核缓存拷贝到用户缓存,同时 read 系统调用返回。read 调用的返回导致一次从内核态到用户态的上下文切换。现在数据用户地址空间缓存中,并且再次开始向下移动。
  3. 第三步:write 系统调用导致一次从用户态到内核态的上下文切换。第三次拷贝执行是为了再次把数据放到内核地址空间缓存中。此时,数据被放到一个不同的缓存中,一个和特定的 sockets 关联的缓存。
  4. 第四步:write 系统调用返回,并且造成第四次上下文切换。第四次拷贝在独立且异步的情况下,通过 DMA 引擎将数据从内核缓存拷贝到协议引擎中。你很可能要问,“独立且异步是什么意思?调用返回之前,难道没有数据传输吗?”事实上,调用返回不能保证数据传输;它甚至不能保证数据传输的开始。它仅仅意味着以太网驱动程序的队列中有空闲的描述符,可以接收我们的数据传输。在我们之前可能有很多数据包在排队。除非驱动程序或硬件实现优先级环或队列,否则数据按先进先出原则传输。(图1 中的 DMA 拷贝说明了最后一次拷贝可以被延迟的事实)。

如你所见,很多的数据复制并不是真正需要的。有些复制可以消除以减少开销,提升性能。作为一个驱动程序开发者,我工作中使用的硬件具有相当高级的特性。一些硬件可以完全绕过主存,直接传输数据到另一个设备。这个特性减少了一次在系统内存中的拷贝,是一个很好的特性,但是这不是所有硬件都支持的。数据从磁盘重新打包到网络中也是存在问题的,这引入了一些复杂性。为了减少开销,我们从减少内核缓存和用户缓存之间的拷贝开始。

一种减少拷贝的方法,是调用 mmap 代替调用 read。例如:

tmp_buf = mmap(file, len);
write(socket, tmp_buf, len);


在内核 2.1 版本中,sendfile 系统调用被引入,以简化网络和两个本地文件之间的数据传输。sendfile 的引入不仅减少了数据拷贝,也减少了上下文切换。它使用起来像这样:

sendfile(socket, file, len);

猜你喜欢

转载自www.cnblogs.com/reload-sun/p/12216754.html