一、思路
1. 監聽端口:在服務器端創建一個ServerSocket對象,去監聽某個端口
2. 創建連接:通過serverSocket.accept() 創建一個Socket對象,等待客戶端連接,當有客戶端連接到這個端口,Socket對象就創建成功
3. 接收消息:client.getInputStream() 阻塞式接收客戶端往這個端口發送的消息
二、簡單代碼實現
public static void main(String[] args) throws IOException { int port = 8234; // 1. 創建ServerSocket對象,去監聽端口號 try (ServerSocket serverSocket = new ServerSocket(port)) { System.out.println("啟動程序監聽8234端口..."); Socket client = null; Boolean flag = true; while (flag) { // 2. 創建Socket對象去等待客戶端連接 client = serverSocket.accept(); System.out.println("客戶端" + client.getInetAddress().getHostAddress() + "連接到服務器..."); // 3. 當客戶端連接上之后,創建一個線程去處理這個客戶端發送的數據,然后等待下一個客戶端的連接 new Thread(new ProcessDataThread(client)).start(); } client.close(); System.out.println("服務器關閉"); } }
public class ProcessDataThread implements Runnable { private Socket client; public ProcessDataThread(Socket socket) { this.client = socket; } @Override public void run() { try { // 1. 獲取客戶端發送過來的消息,此時是通過二進制流獲取,也可以用InputStreamReader通過字符串接收 try (InputStream in = client.getInputStream()) { byte[] buffer = new byte[1024]; while ((in.read(buffer)) != -1) { try { // 2. 處理數據,如果處理發生異常,不影響下次接收數據 } catch (Exception ex) { System.out.println("處理數據發生異常:" + ex); } } } } catch (Exception ex) { System.out.println("客戶端連接發生異常:" + ex); } } }
三、NIO優化,但強烈不建議使用Java原生的NIO
1. 單線程
2. 多線程優化,對應上面的代碼
3. 線程池優化
對於每一個請求,單獨開一個線程進行相應的邏輯處理,如果客戶端的數據傳遞是斷斷續續的,相應的線程需要I/O等待(有阻塞),並進行上線文切換(耗資源)
4. 使用NIO的Selector機制,提升程序並發效率
a. Channel用於連接和傳輸
b. Buffer 用於存儲
c. 用於管理請求
四、Netty優化
1. Netty是對NIO的進一步封裝
2. Netty代碼
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency>
public class NettyServer { public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup boos = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); serverBootstrap .group(boos, worker) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println(msg); } }); } }) .bind(8000); } }
public class NettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(new StringEncoder()); } }); Channel channel = bootstrap.connect("127.0.0.1", 8000).channel(); while (true) { channel.writeAndFlush(new Date() + ": hello world!"); Thread.sleep(2000); } } }
參考:
https://blog.csdn.net/qq_36278071/article/details/79151422
https://www.cnblogs.com/snailclimb/p/9086334.html