【Netty学习】 阻塞式IO
Netty学习第一弹,先从简单的阻塞式IO说起。
本文主要介绍传统阻塞式socket通信,代码可分为Server端 和 Client端
Server端代码
package socket;
public class ServerBoot {
private static final int PORT = 8080;
public static void main(String[] args) {
Server server = new Server(PORT);
server.start();
}
}
package socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private ServerSocket serverSocket;
public Server(int port) {
try {
//创建一个ServerSocket
this.serverSocket = new ServerSocket(port);
System.out.println("服务端启动成功,端口:" + port);
}catch (IOException e){
System.out.println("服务端启动失败");
}
}
public void start(){
//启动一个线程监听消息
new Thread(()->{
dostart();
}).start();
}
private void dostart(){
while (true){
try {
//收到来自客户端的socket消息,将其交给ClientHandler处理
Socket client = serverSocket.accept();
new ClientHandler(client).start();
} catch (IOException e) {
System.out.println("服务端异常");
e.printStackTrace();
}
}
}
}
package socket;
import java.io.InputStream;
import java.net.Socket;
//处理客户端
public class ClientHandler {
public static final int MAX_DATA_LEN = 1024;
private final Socket socket;
public ClientHandler(Socket client) {
this.socket = client;
}
public void start(){
System.out.println("新客户端接入:");
new Thread(()->{
doStart();
}).start();
}
private void doStart(){
try {
InputStream inputStream = socket.getInputStream();
while (true){
byte[] data = new byte[MAX_DATA_LEN];
int len;
//读取消息
while ((len = inputStream.read(data)) != -1){
String message = new String(data, 0, len);
System.out.println("客户端传来消息:" + message);
//消息写回客户端
socket.getOutputStream().write(data);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client
代码
public class Client {
private static final String HOST = "127.0.0.1";
private static final int PORT = 8080;
private static final int SLEEP_TIME = 1000;
public static void main(String[] args) throws IOException {
final Socket socket = new Socket(HOST,PORT);
new Thread(()->{
System.out.printf("客户端启动成功\n");
while (true){
try {
String message = "hello world";
System.out.println("客户端发送数据:" + message);
socket.getOutputStream().write(message.getBytes());
Sleep();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private static void Sleep(){
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
阻塞式的通信很简单。
1、在服务端创建一个ServerSocket监听客户端消息
2、一旦收到消息,创建ClientHandler,将来自client的socket交给clientHandler处理
3、ClientHandler会创建一个线程去处理消息,保证serverSocket.accept() 不会被阻塞。
总之就是,客户端发送一个请求,建立Socket长连接, 服务端创建一个线程去处理该请求。
在并发量高的情况下,比如同时有50000个来自客户端的长连接请求,那么服务端就要创建50000个线程来维持这些连接。看似很美好,实则是
真的太占用内存了
,远远不能满足高并发的需求。
其实仔细想想,维持这么多的连接是很浪费资源的,说的俗一点,就是**“占着茅坑不拉屎”**。某些socket资源被客户端占用了,但是并没有进行消息传递,而是处于空闲状态。
有兴趣的童鞋可以试一下以下代码,打开你的任务管理器,观察下你的机器内存使用情况。
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class Client {
private static final String HOST = "127.0.0.1";
private static final int PORT = 8080;
private static final int SLEEP_TIME = 1000;
public static void main(String[] args) throws IOException {
final Socket socket = new Socket(HOST,PORT);
for(int i = 0; i < 100000; i++){
new Thread(()->{
System.out.printf("客户端启动成功\n");
while (true){
try {
String message = "hello world";
System.out.println("客户端发送数据:" + message);
socket.getOutputStream().write(message.getBytes());
Sleep();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
System.out.println(i);
}
// new Thread(()->{
// try {
// InputStream inputStream = socket.getInputStream();
// while (true){
// byte[] data = new byte[1024];
// int len;
// while ((len = inputStream.read(data)) != -1){
// String message = new String(data, 0, len);
// System.out.println("服务端传来消息:" + message);
// }
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
// }).start();
}
private static void Sleep(){
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
版权声明:本文为e31006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。