假设我们要实现一个需求 客户端每隔两秒向服务端发送一次信息,服务端接收打印
首先我们需要一个服务端一个客户端
服务端SocketServer
服务端监听8000端口.循环接收新的客户端连接请求.同时打印客户端发送来的消息
public class SocketServer {
public static void main(String[] args) throws Exception {
//创建socket服务监听8000端口
ServerSocket serverSocket = new ServerSocket(8000);
while(true) {
//服务端阻塞等待客户端连接
Socket socket = serverSocket.accept();
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
//直接打印接收到客户端发送的消息
System.out.println(new String(bytes, 0, len, "utf-8"));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端SocketClient每隔两秒会发送一条消息至服务端
public class SocketClient {
public static void main(String[] args) throws Exception {
Socket socket = null;
OutputStream outputStream = null;
try {
//创建客户端连接,并指定地址和端口
socket = new Socket("127.0.0.1", 8000);
while (true) {
outputStream = socket.getOutputStream();
//每两秒发送一次信息
outputStream.write((new Date() + ": 客户端1发送hello world").getBytes());
Thread.sleep(2000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
先启动服务端,再启动客户端1 结果如下
此时我们修改客户端发送内容改为""客户端2发送hello world""然后启动新的客户端
此时结果并没有改变 依然是只有客户端1的消息
接下来我们停止客户端1 服务端接收到客户端2的消息.证明之前客户端被阻塞了
我们接着对代码进行修改.服务端添加多线程,支持多个客户端连接
客户端不变,服务端修改如下
public class SocketServer {
public static void main(String[] args) throws Exception {
//创建socket服务监听8000端口
ServerSocket serverSocket = new ServerSocket(8000);
while(true) {
//服务端阻塞等待客户端连接
Socket socket = serverSocket.accept();
//新的线程处理新的连接
new Thread(()->{
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
//直接打印接收到客户端发送的消息
System.out.println(new String(bytes, 0, len, "utf-8"));
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
同样启动服务端,和客户端,然后重复上面实验的操作,启动客户端1客户端2.
发现服务端同时可以接收客户端1,客户端2的消息.服务端支持多个客户端连接.
上面的IO 编程模型在客户端较少的情况下运行良好,但是对于客户端比较多的业务来说,单机服务端可能需要支撑成千上万的连接,IO 模型可能就不太合适了
上面的demo从服务端来看,每新增一个客户端,就会产生一个新的线程,如果有成千上万个客户端,就会有成千上万个线程,这就会有以下问题
- 线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起
- 线程切换效率低下:单机 CPU 核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。
- 除了以上两个问题,IO 编程中,我们看到数据读写是以字节流为单位。
所以1.4以后 jdk提出了NIO编程