网络编程常识

-25.网络分层

  • 物理层:0 、1 的比特位
  • 链路层: 帧 ;以太网协议+MAC
  • 网络层:包;IP+DNS+ARP协议
  • 传输层:报文段;TCP
  • 应用层:报文; HTTP+WS等

-24.mqtt V.S. kafka

MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的消息协议,通常用于物联网(IoT)和即时通讯应用
MQTT 节省带宽,协议头小,网络开销小;对实时性要求高 【这应该是最核心的区别】

Kafka: 大数据量、大吞吐,比如日志处理、流处理场景

-23. Selector

selector: A multiplexor of SelectableChannel objects. 【多路复用器】

-22 tcp是基于“流”的

我们常说tcp 基于流、可靠到底在说啥?

  • 基于流,就是说,发送、接收都是没头没尾的,会存在半包现象
  • 可靠是说,TCP连接传送的数据是没有差错、不会丢失、不重复并且按序到达的。 TCP是通过序列号、checksum、确认应答信号、重发机制、连接管理、窗口控制、流量控制、拥塞控制一起保证TCP传输的可靠性的

-21 hop-by-hop、end-2-end

在这里插入图片描述

App A将一个请求,原封不动地转发给了App B,并且将App B的响应原封不动地返回给客户端。如果App A的代码或者web容器没有对App B的响应头做特殊处理,就容易出现上述情况:响应头中包含了两个key值一样的header:Connection:someValue。

由于响应头中Connection字段决定了http的长连接是否可用, 当样例中的两个Connection字段值不同时,客户端收到请求后无法明确辨析服务端对当前http连接的态度,会导致一些不可预知的情况。例如,如果valueA是“Close”,而valueB是“Keep-Alive”,这个时候客户端无法清晰的知道服务端是否会继续维系当前http连接。

在RFC 2612中,对响应头划分为了End-to-end HeadersHop-by-hop HeadersHop-by-hop Headers往往会影响客户端对http响应的连接维系、内容处理策略等。http协议中将请求头分为了hop-by-hopend-2-end两大类。
在这里插入图片描述

-20 listendrop 、listenoverflow

服务端遭受连接风暴,查看容器TCP连接状态监控可能会发现这二个指标很高。

sync 包太多,半连接syncQ放不下,listendrop;

全连接accept Q也满,会从syncQ 拿到包,listenoverflow

netty 的backlog就是accpetQ 大小

-19 如何模拟容器的连接ZK失败?

普通开发没有在容器上操作iptabel的权限,从宿主机层面也没有更好的方案。可利用的arthas的类覆盖功能(以CuratorZookeeperClient为例),将自己的类替代掉业务进程的类,“曲线”达到目的。

使用arthas对java进程的CuratorZookeeperClient进行覆盖,

  • 将自己的CuratorZookeeperClient.java上传到/tmp/sc/目录
  • ps -ef|grep java,找到java 进程ip
  • cd /apps/sh/tools/arthas; ./as.sh <pid>
  • sc -d org.apache.curator.CuratorZookeeperClient | grep classLoaderHash | head -n1
  • mc -c <classLoadHash> /tmp/sc/CuratorZookeeperClient.java -d /tmp/sc/ 【mc:编译器,将java文件编译成class文件】
  • redefine /tmp/sc/org/apache/curator/CuratorZookeeperClient.class

-18 单工、全双工、半双工

单工:数据传输只支持数据在一个方向上传输;在同一时间只有一方能接受或发送信息,不能实现双向通信,举例:电视,广播。

半双工:数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;在同一时间只可以有一方接受或发送信息,可以实现双向通信。举例:对讲机。

全双工:数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力;在同一时间可以同时接受和发送信息,实现双向通信,举例:电话通信。

网卡的全双工(Full Duplex)是指网卡在发送数据的同时也能够接收数据,两者同步进行。这好像我们平时打电话一样,说话的同时也能够听到对方的声音,目前的网卡一般都支持全双工。

图示:(分别为单工, 半双工, 全双工)
在这里插入图片描述
具体到HTTP协议,对工作模型的支持则要分情况:

  • 半双工:同一时间内,链接上只能有一方发送数据,另一方接受数据。
    http 1.0 是短连接模式,每个请求都要建立新的 tcp 连接,然后 C 发送,S 响应,断开,下一个请求重复此步骤。
  • http 1.1:是长连接模式,可以多路复用(?),建立 tcp 连接,资源1 C 发送,S响应,资源2 C发送 S响应,资源3 C发送 S响应,免去了要为每个资源都建立一次 tcp 的开销。
  • 全双工:同一时间内,两端都可以发送或接受数据
    http 2.0 资源1 C发送,不必等待 S响应就可以继续发送 资源2 的请求,可以并发的发送,一边发,一边收。

TCP 是基于全双工的可信传输协议。

-17 Http 协议

1)Options请求头
2)keep-alive

http请求头、响应头可以有Connection:keep-alive;还有个头就叫做keep-alive

  • header keep-alive 只在 Connection:keep-alive才生效。
  • Header keep-alive allows the sender to hint about how the connection may be used to set a timeout and a maximum amount of requests(only for http pipeline)
    timeout - An integer that is the time in seconds that the host will allow an idle connection to remain open before it is closed. A connection is idle if no data is sent or received by a host
    click to see http header Keep-Alive
  • nginx可设置 keepalive_timeout ,另外还有个nginx自己的keepalive_time
    click to see nginx keepalive_timeout

-16. Netty Q&A

1)Netty future/promise V.S. CompletableFuture

Netty有自己的future/promise 抽象, 功能上和Java的CompletableFuture重叠,初用Netty心生疑惑,为啥Netty要自己搞一套抽象? 不用纠结, 把它们当做一回事就行。

本质上都是对异步结果的抽象, 只不过是两批人实现了两套代码。另外,CompletableFuture是Java8才有的,Netty 连Java6都可以支持。总体上,社区会让Netty的抽象逐渐向JDKCompletableFuture 靠拢

2)DuplexChannel

duplex翻译为双向的;如java doc所说:DuplexChannel that has two sides that can be shutdown independently

-15. ByteBuffer的类型

ByteBuffer常见三个子类:

  • HeapByteBuffer
  • DirectByteBufffer
  • MappedByteBuffer

后二者容易搞混.
Direct ByteBuffers (those allocated using ByteBuffer.allocateDirect) are different to MappedByteBuffers in that they represent different sections of memory and are allocated differently. Direct ByteBuffers are a way to access a block of memory allocated outside of the JVM generally allocated with a malloc call (although most implementations will probably use an efficient slab allocator). I.e. it’s just a pointer to a block of memory.

A MappedByteBuffer represents a section of memory allocated using mmap call, which is used to perform memory mapped I/O. Therefore MappedByteBuffers won’t register their use of memory in the same way a Direct ByteBuffer will.

So while both are “direct” in that they represent memory outside of the JVM their purposes are different.

翻译一下:
DirectByteBuffer: 通过sys call (malloc)分配的堆外内存,注意是在真的分配了一块内存, 然后JVM拿到了这块内存的指针. 框架可能出于GC的考虑将一些数据放在堆外(大,但变化少的数据)

MappedByteBuffer:通过 mmap获取了一块内存的引用,但没有真的分配内存. rocketmq 借助mmap实现了zerocopy

两者都是堆外,但行为和目的都不同.

-14. IO多路复用的本质

-14.1 五种IO模型
  • 同步阻塞IO
  • 同步非阻塞IO
  • IO多路复用 【多路复用和同步非阻塞IO 是两种IO类型,不要混在一起
  • 异步阻塞IO 【实际根本没有异步阻塞IO的说法】
  • 异步非阻塞IO 【信号驱动的方式,使用较少】

十分简练的介绍五种IO模型的文章

-14.2 多路复用

IO多路复用, 换句话说, 多路channel(连接)复用同一个IO监听等待, or , 多个socket在同一个selector上监听, 当selector有变化(有数据)的时候就通知用户进程。好处就是单个进程可以处理多个socket.

select/poll/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接. 也就是说, IO多路复用解决的是 吞吐的问题.

每个socket 设置为 non-blocking,但 整个用户process是阻塞的,只不过process是被select函数阻塞, 而不是被socket IO 阻塞

在这里插入图片描述
流程:

(1)当用户进程调用了select,那么整个进程会被阻塞;
(2)而同时,内核会“监视”所有select负责的socket
(3) 当任何一个socket中的数据准备好了,select就会返回;
(4) 这个时候用户进程再调用read/accept/write操作,做一些数据从内核拷贝到用户进程这样的事情

I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,
而这些文件描述符(套接字描述符 socket)其中的任意一个进入读就绪状态,
select()函数就可以返回

事实上,I/O 多路复用有时候性能比同步阻塞IO还更差一些。因为这里需要使用两个系统调用(selectrecvfrom),而同步阻塞IO只调用了一个系统调用(recvfrom)。但是,用select的优势在于它可以同时处理多个连接。所以,如果处理的连接数不是很高的话,可能延迟还更大.

-13.RPC的调用方式

  • sync
    • 客户端发起rpc请求后当前线程阻塞,直到服务端返回结果/超时. 虽说 Sync 是同步调用,但是客户端线程和服务端线程并不是同一个线程,实际在 RPC 框架内部还是异步处理的
  • async
    • 算是sync的基础,async会返回Future ,客户端可自行决定何时阻塞地get
  • callback
    • 客户端发起调用时,将Callback传递给 RPC 框架,无须同步等待返回结果,直接返回。当获取到服务端响应结果或者超时异常后,再执行用户注册的 Callback
  • oneway
    • 客户端发起请求之后直接返回,忽略返回结果

-12. rpc的线程模型

首先要明确 I/O 线程和业务线程的区别。
以 Dubbo 框架为例,Dubbo 使用 Netty 作为底层的网络通信框架,采用了我们熟悉的主从 Reactor 线程模型,其中 BossWorker 线程池就可以看作 I/O 线程

  • I/O 线程可以理解为主要负责处理网络数据,例如事件轮询、编解码、数据传输等。如果业务逻辑能够立即完成,也可以使用 I/O 线程进行处理,这样可以省去线程上下文切换的开销。
  • 如果业务逻辑耗时较多,例如包含查询数据库、复杂规则计算等耗时逻辑,那么 I/O 必须将这些请求分发到业务线程池中进行处理,以免阻塞 I/O 线程.

在这里插入图片描述

-11. write through/write back

write through/write back硬盘阵列卡Cache的两种使用方式, 也称为透写和回写。

  • 当选用write through方式时,系统的写磁盘操作并不利用阵列卡的Cache,而是直接与磁盘进行数据的交互。
  • write Back则利用阵列Cache作为系统与磁盘间的二传手,系统先将数据交给Cache,然后再由Cache将数据传给磁盘.

生产环境中的配置要根据具体的业务类型及环境进行配置,比如:如果有外置UPS电源,选Write Back,如果没有外置电源,并且对数据安全性要求很高,不要求太高性能,就选Write Through

-10. dmz

隔离区部署: 隔离区,既能连外网,又能连内网,也就是DMZ。两个防火墙之间的空间被称为DMZ。

百度百科

-9 java.net.SocketTimeoutException: Read timed out 和 ConnectionTimeout

A connection timeout occurs only upon starting the TCP connection. This usually happens if the remote machine does not answer. This means that the server has been shut down, you used the wrong IP/DNS name or the network connection to the server is down.

A socket timeout is dedicated to monitor the continuous incoming data flow. If the data flow is interrupted for the specified timeout the connection is regarded as stalled/broken. Of course this only works with connections where data is received all the time.

-8 mmp 和 zero copy

for details
以“从磁盘读取文件后发送到网络”这个场景为例:

  • 普通file.read + socket.send 需要4次应用进程空间/内核空间上下文的切换,4次copy=2次DMA拷贝 + 2次CPU拷贝
  • mmap内存映射,也是zero copy,需要4次应用进程空间/内核空间上下文切换, 3次copy=2次DMA拷贝+1次CPU拷贝
  • file.sendFile 是zero copy的一种,2次应用进程空间/内核空间的切换,2次DMA拷贝,没有CPU拷贝
  • mmap 适合小数据量读写,sendfile 适合大文件传输(?)
  • kafka大量使用sendfile ,rocketmq则用 mmap

P.S. mmap是把磁盘文件和内存映射起来
在这里插入图片描述

-7 HTTP协议

-7.1 host字段

一直以为这个字段没啥用,因为Host的字段的作用在于指明http报文的方向,访问的地点,但是实际报文转发都是由底层目的端口IP决定了.

实际上,不同的域名通过A记录或者CNAME方式可以连接都同一个IP下,同一个IP也可以设置多个不同站点,那我访问不同的域名都转发到同一IP,怎么区分这些不同的站点呢,就是用的Host字段,如果服务器后台解析出Host但是服务器上找不到相应的站点,那么这个连接很可能会被丢弃,从而报错.

另外, Nginx可以利用HOST来设置访问策略.

参考:简书链接

-7.2 http only

典型用途:防止使用js 读取cookie中的内容,帮助抵御 xss 攻击。它由服务端在返回头中添加。

-6 什么是智能路由

智能路由的工作内容 :比如一个APP端,到底发送到哪个IP呢?一般是DNS解析的一个过程。但是利用HTTP-DNS 技术可以另辟蹊径,请求发到云平台的一个服务器(不需要DNS,直接用IP干),由云平台判断后,返回一个最合适的(丢包最少、
时间最短的IP)

-5 长连接和短连接

写代码以来,经常听到 长连接&短连接, 然后还和TCP /HTTP搅和在一起,不知所云. 这里简要阐释下.

参考:

HTTP 1.1

  • 默认是长连(persistant connection),长连不是一直连,只是翻译成“长”而已。可以通过 Connection + KeepAlive两个头来控制

-4 三次握手/四次回收

简要说:

  • 为啥三次握手? 是为了 证明对端没问题;
  • 为啥四次挥手? 为了关闭双工.

参考: https://zhuanlan.zhihu.com/p/53374516

-3. 什么是连接

是个写代码的都经常说"连接", 可到底啥是连接(TCP connection)呢?

"连接"不是个 物理动作,而是连接双方的状态

  • 从服务器角度讲,新建一个连接代表着新建一个客户端的记录(地址:端口号),所有来自这里的数据都交给创建连接的应用去处理。
  • 从客户端角度讲,新建一个连接代表着新建一个服务器地址记录(地址:端口号),所有从这个连接发出的数据,都只能发给连接指定的地址。
  • TCP是双工的,所以连接建立后,两端都是客户端,也都是服务器

参考(建议常看看):

  • https://www.zhihu.com/question/38483035 (自古知乎多大神啊)

-2、文本协议和二进制协议

我一直觉得计算机领域的很多概念其实本质好理解,但是被人活生生地搞得费解。

比如我们经常说,HTTP1.1 是基于文本的协议,类似的基于文本的协议还有

  • 用于邮件的SMTP协议
  • telnet 协议
  • 即使是数据库,底层是TCP,应用层也是基于文本的SQL协议

文本也是 基于二进制来传输的,其实网络传输的时候,都是以二进制的形式。之所以我们强调基于文本,是因为我们可以把 8 个二进制一组拿来解析,然后对应到码表,得到文本。

其他的,比如图片、视频、文件等,在网络传输前被编码成了一个个的字节。虽然也是8 个二进制一组,但是解析的时候,一般多个字节算是一个基本单位,具体则看编码方式。

基于二进制(字节)的协议有:

  • HTTP2协议
  • 传输文件的FTP (数据传输是二进制,命令传输是文本)

所以,将文本协议和二进制协议,硬生生地拆开理解,有点钻牛角尖

-1、文本文件和二进制文件

跟上面的“文本协议、二进制协议”类似,其实在计算机的世界里,所有的信息都是 01 序列。存储在计算机上的信息在物理上都是 二进制的, 即使我们常说的文本文件也是 二进制。因此,文本文件和二进制文件的差异并不是 物理上的,而是逻辑上的。

把文本文件当做二进制文件的一种,就知道了:计算机上其实没有所谓的文本,硬生生地区分是钻牛角尖(也是忽悠初学者)。

0、序列化协议和 通信协议

比如:你将文件拷到了光盘,这需要序列化;我从光盘读取数据,需要反序列化。

我们商量好,你通过顺丰把光盘给我,这就是通信协议。除了顺丰,你还可以亲自拿给我,也就是说协议可以有好多种。

最常见的通信协议:Dubbo HTTP WebSocket Hession ,etc
最常见的序列化协议:Kyro PB Hession .
是的,有的产品,通信协议和序列化协议名字相同,比如 Hession

1、一些特殊地址

  • 127.0.0.1:回环地址。该地址指主机本身,主要预留测试本机的TCP/IP协议是否正常。只要使用这个地址发送数据,则数据包不会出现在网络传输过程中。
  • 10.x.x.x、172.16.x.x~172.31.x.x、192.168.x.x:这些地址被用做内网中。用做私网地址,这些地址不与外网相连。
  • 255.255.255.255:广播地址
  • 0.0.0.0:这个IP地址在IP数据报中只能用作源IP地址,这发生在当设备启动时但又不知道自己的IP地址情况下。

IPV4中,0.0.0.0地址被用于表示一个无效的,未知的或者不可用的目标。

  • 在服务器中,0.0.0.0指的是本机上的所有IPV4地址,如果一个主机有两个IP地址,192.168.1.110.1.2.1,并且该主机上的一个服务监听的地址是0.0.0.0,那么通过两个ip地址都能够访问该服务。
  • 在路由中,0.0.0.0表示的是默认路由,即当路由表中没有找到完全匹配的路由的时候所对应的路由。

0.0.0.0的用途:

  • DHCP分配前,表示本机。
  • 用做默认路由,表示任意主机。
  • 用做服务端,表示本机的任意IPV4地址。

localhost:
只是一个域名,可以代表任何IP地址。默认是127.0.0.1 ,在/etc/hosts文件下。

在实际应用中,一般我们在服务端绑定端口的时候可以选择绑定到0.0.0.0,这样我的服务访问方就可以通过我的多个ip地址访问我的服务。

比如我有一台服务器,一个外网A,一个内网B,如果我绑定的端口指定了0.0.0.0,那么通过内网地址或外网地址都可以访问我的应用。

2、keep-alive

Http中的keep-alive 头:
比如有个需求,定时5S去百度拉取数据入库,如果没有禁用keep-alive ,连接会保持住。假如不是使用同一个client,即5S生成一个连接,时间一长,机器就会连接过多,句柄不够用。
解决办法:

  • 复用一个client
  • 或 禁用 client

https://www.cnblogs.com/jiangz/p/7102349.html

如果是 1天只有几次,那直接禁用keep-alive完事。

3、三次握手、四次挥手

在这里插入图片描述
在这里插入图片描述
a) 为什么需要三次握手?
在不可靠的网络条件下实现可靠的TCP。至少三次才能让连接发起方和接收方都确信对方准备好了的

b) 为什么四次挥手
为了保证等数据完成的被接收完再关闭连接。 既然提到需要保证数据完整的传输完,那就需要保证双方都达到关闭连接的条件才能断开

c) time_wait 只会出现在主动关闭方,close_wait 会出现在被动关闭方

d) time_wait大量出现有何原因、危害、处理手段

  • 原因1:大量的短连接存在 【接入层常有这个问题】

在HTTP/1.0协议中默认使用短连接【术语叫 shortlived connection】。

也就是说,浏览器和服务器每进行一次HTTP操作,就会建立一次连接,任务结束后就会断开连接,而断开连接这个请求是由server去发起的,主动关闭连接请求一端才会有TIME_WAIT状态连接。

  • 原因2.HTTP请求头里connection值被设置为close

    如果HTTP请求中,connection的值被设置成close,那就相当于告诉server:server执行完HTTP请求后去主动关闭连接。

  • 危害:对CPU和内存的危害几乎没有;不过当同一客户端向服务器建立了大量连接之后,会耗尽可用的五元组(也就是客户端的端口,一个连接会对应一个客户端的端口)

    假设每秒建立了1000个短连接,TIME_WAIT的时间是1分钟,则1分钟内需要建立6W个短连接,Linux默认的本地端口范围配置是:net.ipv4.ip_local_port_range = 32768 ,新的请求由于没有本地端口就不能建立了

  • 处理1: HTTP请求头里connection的值设置为:keep-alive。将短连接改成长连接。

    长连接比短连接从根本上减少了server去主动关闭连接的次数,减少了 TIME_WAIT 状态连接的产生。

  • 处理2:在利用nginx做反向代理时,如果要设置成长连接,则需要设置成:
    i.从client到nginx的连接是长连接。
    ii.从nginx到server的连接是长连接。

  • 处理3: 【服务器层面】

    i) 允许将TIME_WAIT状态的socket重新用于新的TCP连接

    这样的好处就是如果出现大量TIME_WAIT状态的连接,也能够将这些连接占用的端口重新用于新的TCP连接

    net.ipv4.tcp_tw_reuse=1 (打开)

    ii) 快速回收TIME_WAIT状态的socket ,net.ipv4.tcp_tw_recycle = 1 【慎用? 不要打开tcp_tw_recycle

    iii) 将MSL值缩减 【慎用】

    linux中MSL的值默认为60s,我们可以通过缩减MSL值来使得主动关闭连接一端由TIME_WAIT状态到关闭状态的时间减少。

    但是这样做会导致延迟报文无法清除以及主动关闭连接一端不能收到重传来的FIN请求,也会影响很多基于TCP的应用的连接复用和调优。

5、close_wait大量出现有何原因、危害、处理手段

  • 原因:close_wait一般应该很短暂,close_wait过多说明【被动关闭方】状态没很快变为Last_ACK,即没有很快发送FIN包,而FIN包的底层就是socket.close()。因此,close_wait可能是socket忙于读写没有及时close()。

    如果是应用连mysql数据库也可能存在事务开启后没有正确rollback或commit,超时后mysql主动关闭连接,应用不能close,就一直保持在了close_wait状态

  • 危害:影响服务器性能,同样可能导致套接字数量达到服务器上限

  • 处理:改代码或配置

  • 尤其注意的是:CLOSE_WAIT 是可能一直存在的。click here to see details

    CLOSE_WAIT - Indicates that the server has received the first FIN signal from the client and the 
    connection is in the process of being closed. This means the socket is waiting for the application to 
    execute close(). A socket can be in CLOSE_WAIT state indefinitely until the application closes it. Faulty 
    scenarios would be like a file descriptor leak: server not executing close() on sockets leading to pile up 
    of CLOSE_WAIT sockets.
    

参考(分享好的网络编程文章)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值