一、socket简介
-
socket定义:
socket套接字是两台主机之间进行网络通信的基础,是实现TCP/IP网络通信的最基本的操作单元。
-
socket网络通信流程描述
-
服务器首先创建ServerSocket套接字绑定端口,并实时监听客户端连接。
-
客户端创建Socket套接字绑定服务器ip和端口号,绑定成功后即可利用socket获取的输出流发送信息。
-
服务端监听到客户端的连接并且收到发送的信息,通过输出流响应客户端。
流程图
-
-
代码实现
服务器代码:
public class Server {
public static void main(String[] args) throws IOException {
//1. 创建线程池,当客户端连接时,使用一个线程与客户端通信
ExecutorService executorService = Executors.newCachedThreadPool();
//2. 创建ServerSocket对象,绑定本地端口
ServerSocket serverSocket = new ServerSocket(9988);
while (true) {
//3. 循环监听客户端
Socket socket = serverSocket.accept();
//4. 当监听到客户端连接时,开启新的线程处理当前连接
executorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("==========>>>线程ID:" + Thread.currentThread().getId()
+ "; 线程名称:" + Thread.currentThread().getName());
InputStream inputStream = socket.getInputStream();
//取出socket字节流中数据通用的方式
int count = 0;
while (count == 0){
count = inputStream.available();
}
//取出连接中输入流,获取消息
byte[] bytes = new byte[count];
inputStream.read(bytes);
System.out.println("客户端消息:" + new String(bytes, 0, count, StandardCharsets.UTF_8));
//连接中取出输出流,响应消息
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,client...".getBytes());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//关闭连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
}
客户端代码:
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
//1. 创建socket对象,绑定服务器的ip和端口
Socket socket = new Socket("127.0.0.1", 9988);
//2. 从连接中获取输出流,发送消息
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,server...I'm client01".getBytes());
//3. 从连接中取出输入流,接收消息
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println("服务器发送消息:" + new String(bytes, 0, len));
//4. 关闭连接
socket.close();
}
}
测试结果:
#二、 I/O模型
1、I/O模型分类
-
java支持三种模型:BIO(同步并阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)
-
阻塞和非阻塞
- 当前线程访问io资源时,若资源未准备就绪:
- 阻塞:当前线程会一直等待资源就绪。
- 非阻塞:当前线程不会等待,可以去访问别的资源。
- 当前线程访问io资源时,若资源未准备就绪:
-
同步和异步
- 当前线程访问io资源时,若资源未准备就绪:
- 同步:当前线程会等待资源就绪,获取结果。
- 异步:当前线程会继续执行其他逻辑,等待资源就绪后的回调。
- 当前线程访问io资源时,若资源未准备就绪:
2、BIO
- 定义:
- 传统的socket编程就是bio
- 使用方式
- 一个线程对应一个连接处理
- 缺点:
- 每个请求都需要创建独立线程,处理客户端的读写等业务处理
- 并发连接数比较大时,会创建很多线程,系统资源消耗大
- 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费
3、NIO
- 同步非阻塞,一个线程 可以处理多个socket连接请求,客户端发送的请求都会注册到多路复用器(Selector)上,多路复用器轮询到连接有I/O请求就进行处理
4、AIO
- 异步非阻塞,AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的 特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长 的应用
总结
- BIO(同步并阻塞) 方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高。JDK1.4以前的唯一选择,但程序简单易理解
- NIO(同步非阻塞) 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕 系统,服务器间通讯等。编程比较复杂,JDK1.4 开始支持
- AIO(异步非阻塞) 方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分 调用 OS 参与并发操作, 编程比较复杂,JDK7 开始支持。
,但程序简单易理解
2. NIO(同步非阻塞) 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕 系统,服务器间通讯等。编程比较复杂,JDK1.4 开始支持
3. AIO(异步非阻塞) 方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分 调用 OS 参与并发操作, 编程比较复杂,JDK7 开始支持。