1.Socket
1.1
无论你是发邮件,浏览网页,还是看视频~实际底层都是使用的TCP/IP,而TCP/IP的编程抽象就是Socket!
Socket的原意是插口,想表达的意思是插口与插槽的关系!"send socket"插到"receive socket"里,建立了链接,然后就可以通信了!
- 服务端Socket会bind到指定的端口上,Listen客户端的"插入"
- 客户端Socket会Connect到服务端
- 当服务端Accept到客户端连接后
- 就可以进行发送与接收消息了
- 通信完成后即可Close
1.2
- BIO:阻塞IO
- NIO:非阻塞IO
- 同步IO
- 异步I
- 同步阻塞IO
- 同步非阻塞IO
- 异步阻塞IO
- 异步非阻塞IO
1.3 什么是阻塞IO,非阻塞IO,同步IO,异步IO?
- 一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作
- 阻塞IO和非阻塞IO的区别在于第一步:发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO;如果不阻塞,那么就是非阻塞IO
- 同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO;如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO
比如:- 你拨号---客户端连接服务器
- 电话通了---连接建立
- 你说:“我家网断了,帮我修下”---发送消息
- 说完你就在那里等,那么就是阻塞IO
- 如果正好你有事,你放下带电话,然后处理其他事情了,过一会你来问下,修好了没---那就是非阻塞IO
- 如果客服说:“马上帮你处理,你稍等”---同步IO
- 如果客服说:“马上帮你处理,好了通知你”,然后挂了电话---异步IO
1.4 BIO优缺点
- 优点
- 模型简单
- 编码简单
- 缺点
- 性能瓶颈低
优缺点很明显。这里主要说下缺点:主要瓶颈在线程上。每个连接都会建立一个线程。虽然线程消耗比进程小,但是一台机器实际上能建立的有效线程有限,以Java来说,1.5以后,一个线程大致消耗1M内存!且随着线程数量的增加,CPU切换线程上下文的消耗也随之增加,在高过某个阀值后,继续增加线程,性能不增反降!而同样因为一个连接就新建一个线程,所以编码模型很简单!
就性能瓶颈这一点,就确定了BIO并不适合进行高性能服务器的开发!像Tomcat这样的Web服务器,从7开始就从BIO改成了NIO,来提高服务器性能!
1.5 NIO优缺点
- 优点
- 性能瓶颈高
- 缺点
- 模型复杂
- 编码复杂
- 需处理半包问题
NIO的优缺点和BIO就完全相反了!性能高,不用一个连接就建一个线程,可以一个线程处理所有的连接!相应的,编码就复杂很多,从上面的代码就可以明显体会到了。还有一个问题,由于是非阻塞的,应用无法知道什么时候消息读完了,就存在了半包问题!
1.6 半包问题
我们知道TCP/IP在发送消息的时候,可能会拆包(如上图1)!这就导致接收端无法知道什么时候收到的数据是一个完整的数据。例如:发送端分别发送了ABC,DEF,GHI三条信息,发送时被拆成了AB,CDRFG,H,I这四个包进行发送,接受端如何将其进行还原呢?在BIO模型中,当读不到数据后会阻塞,而NIO中不会!所以需要自行进行处理!例如,以换行符作为判断依据,或者定长消息发生,或者自定义协议!
NIO虽然性能高,但是编码复杂,且需要处理半包问题!为了方便的进行NIO开发,就有了Reactor模型!