目录
前言:
基础实现代码:
描述:
优化代码多线程处理客户端连接和消息接收:
描述:
再次优化异步实现:
以下是使用 CompletableFuture 实现异步处理客户端请求的示例代码:
描述:
进一步优化的代码:Netty来实现Socket服务器
描述:
用SSL/TLS来加密通信,提高安全性
描述:
优化方案梳理:
⛺摸鱼一下, 你路上捡到一百块,很开心,然后你发现后面还有一百块,还有一叠一百块,还有一箱一百块.....
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
private static final int PORT = 8888;
public static void main(String[] args) {
try {
// 创建ServerSocket对象,监听指定端口
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server started, waiting for client...");
// 等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("Client connected: " + socket.getInetAddress().getHostAddress());
// 创建输入流,用于接收客户端发送的消息
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 循环读取客户端发送的消息
String message;
while ((message = reader.readLine()) != null) {
System.out.println("Received message: " + message);
}
// 关闭输入流和socket连接
reader.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
private static final int PORT = 8888;
public static void main(String[] args) {
try {
// 创建ServerSocket对象,监听指定端口
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server started, waiting for client...");
// 循环等待客户端连接
while (true) {
// 等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("Client connected: " + socket.getInetAddress().getHostAddress());
// 创建新线程处理客户端连接和消息接收
Thread thread = new Thread(new SocketHandler(socket));
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class SocketHandler implements Runnable {
private Socket socket;
public SocketHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 创���输入流,用于接收客户端发送的消息
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 循环读取客户端发送的消息
String message;
while ((message = reader.readLine()) != null) {
System.out.println("Received message: " + message);
}
// 关闭输入流和socket连接
reader.close();
socket.close();
System.out.println("Client disconnected: " + socket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代码创建了一个新的线程来处理每个客户端连接和消息接收。当有新的客户端连接时,程序会创建一个新的SocketHandler对象,并将其作为参数传递给新线程的构造函数。在SocketHandler的run方法中,程序会创建输入流,循环读取客户端发送的消息,并在接收到消息后打印出消息内容。当客户端关闭连接时,程序会关闭输入流和socket连接,并打印出客户端的IP地址。
这种方式可以提高并发性能,同时也可以避免阻塞主线程。
使用 NIO。Java NIO(New IO)是一种基于缓冲区、非阻塞 IO 的 IO API,可以提高服务器的并发处理能力和性能。
使用 Netty。Netty 是一个基于 NIO 的客户端-服务器框架,可以大大简化网络编程的开发过程,并提供高性能和可靠性。
使用异步编程。例如使用 CompletableFuture 或 FutureTask 来实现异步处理客户端请求,避免阻塞主线程。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TCPServer {
private static final int PORT = 8080; // 服务器监听端口号
private static final int THREAD_POOL_SIZE = 10; // 线程池大小,可根据实际情况调整
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server started. Listening for connections...");
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected from " + clientSocket.getInetAddress() + ":" + clientSocket.getPort());
CompletableFuture.runAsync(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Received message from " + clientSocket.getInetAddress() + ":" + clientSocket.getPort() + " : " + line);
// 在这里对收到的消息进行处理
// ...
writer.println("Server received message: " + line);
if ("bye".equals(line)) {
break;
}
}
clientSocket.close();
System.out.println("Client disconnected from " + clientSocket.getInetAddress() + ":" + clientSocket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}, executorService);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class SocketServer {
private static final int PORT = 8888;
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new SocketHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(PORT).sync();
System.out.println("Server started, waiting for client...");
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
private static class SocketHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
String message = buf.toString(CharsetUtil.UTF_8);
System.out.println("Received message: " + message);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.security.Security;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
public class SocketServer {
private static final int PORT = 8888;
private static final String KEYSTORE_PATH = "/path/to/keystore";
private static final String KEYSTORE_PASSWORD = "password";
public static void main(String[] args) {
try {
// 加载keystore文件
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(SocketServer.class.getResourceAsStream(KEYSTORE_PATH), KEYSTORE_PASSWORD.toCharArray());
// 创建KeyManagerFactory对象,用于管理keystore中的密钥
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, KEYSTORE_PASSWORD.toCharArray());
// 创建SSLContext对象,用于创建SSLServerSocketFactory
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
// 创建SSLServerSocketFactory对象,用于创建SSLServerSocket
SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(PORT);
// 设置SSLServerSocket的一些属性
sslServerSocket.setNeedClientAuth(false);
sslServerSocket.setEnabledProtocols(new String[] { "TLSv1.2" });
sslServerSocket.setEnabledCipherSuites(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" });
System.out.println("Server started, waiting for client...");
// 循环等待客户端连接
while (true) {
// 等待客户端连接
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
System.out.println("Client connected: " + sslSocket.getInetAddress().getHostAddress());
// 创建新线程处理客户端连接和消息接收
Thread thread = new Thread(new SocketHandler(sslSocket));
thread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class SocketHandler implements Runnable {
private SSLSocket sslSocket;
public SocketHandler(SSLSocket sslSocket) {
this.sslSocket = sslSocket;
}
@Override
public void run() {
try {
// 创建输入流,用于接收客户端发送的消息
BufferedReader reader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
// 循环读取客户端发送的消息
String message;
while ((message = reader.readLine()) != null) {
System.out.println("Received message: " + message);
}
// 关闭输入流和socket连接
reader.close();
sslSocket.close();
System.out.println("Client disconnected: " + sslSocket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}