国家 住房城乡建设信用 网站,外贸推广哪家好,软件开发定制外包服务商,做网站制作步骤前言 无论是软件还是硬件的本质都是要解决IO问题#xff08;输入、输出#xff09;#xff0c;再说回网络编程本质上都是基于TCP/UP的开发#xff0c;socket是在此基础上做的扩展与封装#xff0c;而Netty又是对socket做的封装。本文旨在通过相关案例对socket进行探讨。 一…前言 无论是软件还是硬件的本质都是要解决IO问题输入、输出再说回网络编程本质上都是基于TCP/UP的开发socket是在此基础上做的扩展与封装而Netty又是对socket做的封装。本文旨在通过相关案例对socket进行探讨。 一、基本知识
交互方式
连接三次握手1.客户-服务 请求2.服务-客户同意3.客户-服务连接断开四次握手1.客户-服务请求断开2.服务-客户接受请求3.服务-客户断开 4.客户-服务断开完成
Java类 ServerSocket 服务类 accept(() 开启连接 close() 停止服务 Socket 客户端类 getInputStream() 输入内存流接收 getOutputStream() 输出内存流发布 二、基于线程阻塞式socketBIO开发示例
实现
Server代码 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;public class SockerServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket new ServerSocket(1200);while (true){Socket socket serverSocket.accept();System.out.println(有新的客户端连接了:socket.getInetAddress());new Thread(new ClientHandler(socket)).start();}}
}class ClientHandler implements Runnable {private Socket socket;public ClientHandler(Socket socket) {this.socket socket;}Overridepublic void run() {try {BufferedReader inStreamReader new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter outStreamWriter new PrintWriter(socket.getOutputStream(), true);outStreamWriter.println(请输入内容);String message;while ((message inStreamReader.readLine()) ! null) {System.out.println(收到客户端消息: message);if (bye.equalsIgnoreCase(message)) {outStreamWriter.println(服务器连接已关闭再见);break; // 结束连接}// 回显客户端消息outStreamWriter.println(服务器回显 message);}} catch (IOException e) {throw new RuntimeException(e);}}
}
Client 代码
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;public class SocketClient {public static void main(String[] args) throws Exception {Socket socket new Socket(127.0.0.1,1200);BufferedReader in new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out new PrintWriter(socket.getOutputStream(), true);BufferedReader console new BufferedReader(new InputStreamReader(System.in));System.out.println(已连接到服务器!);System.out.println(in.readLine()); // 读取服务器欢迎消息String userInput;System.out.println(请输入消息输入 exit 断开连接);while ((userInput console.readLine()) ! null) {out.println(userInput); // 发送消息给服务器String serverResponse in.readLine(); // 接收服务器响应System.out.println(serverResponse);if (exit.equalsIgnoreCase(userInput)) {System.out.println(连接已关闭。);break;}}}
}效果 缺点 虽然这个已经实现通信由于它是基于线程控制通信的换言之每个客户端连接后都会创建一个线程客户端数量与线程增长成正比就意味着会吃更多的内存这显然是不合理的。如果你足够细心会有一些程序要隔一段时间需要重新启动一下否则会卡死这或许是设计之初犯类似的错误这就是BIO的致命缺点 三、基于单线程socket(NIO)
前言 基于上面的问题我们通过改造实现非隔断性Socket实现而非多线程方式这可以极大的提高交互效率与并发问题。 实现
服务端 import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NioServer {public static void main(String[] args) throws IOException {// 打开服务端Socket通道ServerSocketChannel serverSocketChannel ServerSocketChannel.open();// 绑定端口1200serverSocketChannel.socket().bind(new java.net.InetSocketAddress(1200));// 设置为非阻塞模式serverSocketChannel.configureBlocking(false);// 创建Selector选择器Selector selector Selector.open();// 将ServerSocketChannel注册到Selector监听连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println(系统运行中.......);while (true){// 阻塞直到有事件发生selector.select();// 获取所有发生的事件键SetSelectionKey selectionKeys selector.selectedKeys();IteratorSelectionKey iterator selectionKeys.iterator();while (iterator.hasNext()){SelectionKey key iterator.next();if (key.isAcceptable()){ // 如果是客户端连接事件// 处理客户端连接ServerSocketChannel server (ServerSocketChannel) key.channel(); // 获取触发事件的通道SocketChannel sc server.accept(); // 接受客户端连接sc.configureBlocking(false); // 设置为非阻塞模式sc.register(selector, SelectionKey.OP_READ); // 注册读取事件System.out.println(有新的客户端连接了:sc.getRemoteAddress());}else if (key.isReadable()){ // 如果是客户端读取事件// 处理客户端读取请求SocketChannel sc (SocketChannel) key.channel(); // 获取触发事件的通道ByteBuffer buffer ByteBuffer.allocate(1024); // 创建缓冲区int len sc.read(buffer); // 读取数据if (len 0){ // 如果有数据String msg new String(buffer.array(), 0, len); // 解析消息System.out.println(收到客户端sc.getRemoteAddress()的消息:msg);// 将收到的消息回传给客户端ByteBuffer outBuffer ByteBuffer.wrap(msg.getBytes()); // 包装响应数据sc.write(outBuffer); // 发送响应}else if (len -1){ // 如果客户端断开连接System.out.println(客户端sc.getRemoteAddress()断开了连接);sc.close(); // 关闭通道}}iterator.remove(); // 移除当前事件键}}}
}客户端
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;public class NioClient {public static void main(String[] args) throws Exception{// 打开SocketChannel并连接到服务器SocketChannel socketChannel SocketChannel.open();socketChannel.connect(new InetSocketAddress(localhost, 1200));// 创建控制台输入流用于读取用户输入BufferedReader console new BufferedReader(new InputStreamReader(System.in));System.out.println(已连接到服务器!);// 初始化PrintWriter对象用于向服务器发送数据PrintWriter writer new PrintWriter(socketChannel.socket().getOutputStream(), true);String message;// 循环读取用户输入并发送给服务器while ((message console.readLine()) ! null) {if (exit.equalsIgnoreCase(message)) {System.out.println(即将退出连接...);break;}// 向服务器发送消息writer.println(message);// 读取服务器返回的响应数据BufferedReader serverResponse new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));String response;// 打印服务器返回的每一行数据while ((response serverResponse.readLine()) ! null) {System.out.println(服务器响应: response);}}// 关闭SocketChannel连接socketChannel.close();System.out.println(客户端已退出);}
}效果 缺点 综上所述NIO虽好上面的代码仅做到了实现但是进行性能调优、异常处理等等需要更写更多的代码作为程序员目的是用好轮子而非造轮子那么Netty这个网络通信工具以它的高性能、高并发、易配置的特点脱颖而出 下篇我将进一步进行介绍。 下一篇《Spring Boot 从Socket 到Netty网络编程下Netty基本开发与改进【心跳、粘包与拆包、闲置连接】》