From 1fb7180327a56a3588d22500b89543e8ad39e378 Mon Sep 17 00:00:00 2001 From: qmstyle Date: Sat, 22 Feb 2025 15:38:53 +0800 Subject: [PATCH] =?UTF-8?q?2025=E5=B9=B42=E6=9C=8822=E6=97=A515:38:46?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 18 +- src/main/java/com/zhangmeng/Constant.java | 9 + .../java/com/zhangmeng/TcpApplication.java | 34 ++-- .../callBack/HandlerApiCallBack.java | 18 ++ .../controller/TcpSocketController.java | 34 ++++ .../com/zhangmeng/handler/ClientHandler.java | 73 ++++++-- .../com/zhangmeng/handler/HandlerApi.java | 14 ++ .../com/zhangmeng/service/Connection.java | 28 +++ .../service/impl/ConnectionImpl.java | 166 ++++++++++++++++++ .../zhangmeng/service/impl/ServerImpl.java | 24 ++- src/main/resources/application.yml | 2 + src/test/java/com/zhangmeng/AppTest.java | 81 ++++++--- 12 files changed, 445 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/zhangmeng/Constant.java create mode 100644 src/main/java/com/zhangmeng/callBack/HandlerApiCallBack.java create mode 100644 src/main/java/com/zhangmeng/controller/TcpSocketController.java create mode 100644 src/main/java/com/zhangmeng/handler/HandlerApi.java create mode 100644 src/main/java/com/zhangmeng/service/Connection.java create mode 100644 src/main/java/com/zhangmeng/service/impl/ConnectionImpl.java create mode 100644 src/main/resources/application.yml diff --git a/pom.xml b/pom.xml index 5ed1bec..b172fed 100644 --- a/pom.xml +++ b/pom.xml @@ -7,16 +7,28 @@ 1.0-SNAPSHOT jar + + org.springframework.boot + spring-boot-starter-parent + 2.5.3 + + + Tcp-Server http://maven.apache.org UTF-8 - 21 + 1.8 + + org.springframework.boot + spring-boot-starter-web + + cn.hutool hutool-all @@ -36,8 +48,8 @@ org.apache.maven.plugins maven-compiler-plugin - 21 - 21 + 1.8 + 1.8 diff --git a/src/main/java/com/zhangmeng/Constant.java b/src/main/java/com/zhangmeng/Constant.java new file mode 100644 index 0000000..0d7359f --- /dev/null +++ b/src/main/java/com/zhangmeng/Constant.java @@ -0,0 +1,9 @@ +package com.zhangmeng; + +/** + * @author zm + * @date 2025/2/22 11:12 + * @version: 1.0 + */ +public class Constant { +} diff --git a/src/main/java/com/zhangmeng/TcpApplication.java b/src/main/java/com/zhangmeng/TcpApplication.java index 4772d21..28f9dcb 100644 --- a/src/main/java/com/zhangmeng/TcpApplication.java +++ b/src/main/java/com/zhangmeng/TcpApplication.java @@ -1,24 +1,30 @@ package com.zhangmeng; import com.zhangmeng.service.impl.ServerImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Hello world! - * */ -public class TcpApplication -{ - public static void main( String[] args ) - { - - ServerImpl.Config config = new ServerImpl.Config(); - config.setName("SimpleServer"); - config.setIPVersion("IPv4"); - config.setIP("127.0.0.1"); - config.setPort(8888); - ServerImpl server = new ServerImpl(); - server.setConfig(config); - server.Start(); +@SpringBootApplication +public class TcpApplication { + public static void main(String[] args) { + new TcpServer().start(); + SpringApplication.run(TcpApplication.class, args); + } + public static class TcpServer extends Thread { + @Override + public void run() { + ServerImpl.Config config = new ServerImpl.Config(); + config.setName("SimpleServer"); + config.setIPVersion("IPv4"); + config.setIP("127.0.0.1"); + config.setPort(9999); + ServerImpl server = new ServerImpl(); + server.setConfig(config); + server.Start(); + } } } diff --git a/src/main/java/com/zhangmeng/callBack/HandlerApiCallBack.java b/src/main/java/com/zhangmeng/callBack/HandlerApiCallBack.java new file mode 100644 index 0000000..22f44db --- /dev/null +++ b/src/main/java/com/zhangmeng/callBack/HandlerApiCallBack.java @@ -0,0 +1,18 @@ +package com.zhangmeng.callBack; + +import com.zhangmeng.handler.HandlerApi; + +import java.net.Socket; + +/** + * @author zm + * @date 2025/2/22 11:54 + * @version: 1.0 + */ +public class HandlerApiCallBack implements HandlerApi { + + @Override + public void handle(Socket socket, byte[] data) { + System.out.println("HandlerApiCallBack handle data:" + new String(data)); + } +} diff --git a/src/main/java/com/zhangmeng/controller/TcpSocketController.java b/src/main/java/com/zhangmeng/controller/TcpSocketController.java new file mode 100644 index 0000000..daf485a --- /dev/null +++ b/src/main/java/com/zhangmeng/controller/TcpSocketController.java @@ -0,0 +1,34 @@ +package com.zhangmeng.controller; + +import com.zhangmeng.service.impl.ServerImpl; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.Socket; + +/** + * @author zm + * @date 2025/2/22 11:11 + * @version: 1.0 + */ +@RestController +@RequestMapping("/tcpSocket") +public class TcpSocketController { + + @RequestMapping("/send") + public void send(String message,String key){ + Socket socket = ServerImpl.socketList.get(key); + if(socket!= null){ + try { + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); + writer.write(message); + writer.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/main/java/com/zhangmeng/handler/ClientHandler.java b/src/main/java/com/zhangmeng/handler/ClientHandler.java index 3e7d6a0..48b2f7b 100644 --- a/src/main/java/com/zhangmeng/handler/ClientHandler.java +++ b/src/main/java/com/zhangmeng/handler/ClientHandler.java @@ -1,6 +1,8 @@ package com.zhangmeng.handler; import cn.hutool.core.io.BufferUtil; +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; import java.io.*; import java.net.Socket; @@ -10,14 +12,18 @@ import java.net.Socket; * @date 2025/2/21 15:40 * @version: 1.0 */ -public class ClientHandler implements Runnable { +public class ClientHandler extends Thread { + + private final Log log = LogFactory.get(); private Socket socket; - // private BufferedReader reader; -// private BufferedWriter writer; + private BufferedReader reader; + private BufferedWriter writer; private OutputStream outputStream; private InputStream inputStream; + public boolean canRun = true; + public void close() { try { outputStream.close(); @@ -30,21 +36,21 @@ public class ClientHandler implements Runnable { @Override public void run() { - while (true) { - try { - byte[] bytes = new byte[1024]; - int len = inputStream.read(bytes); - if (len == -1) { - break; - } - String message = new String(bytes, 0, len); - System.out.println("receive message: " + message); - - - } catch (IOException e) { - throw new RuntimeException(e); + try { + while (true) { + // main 线程负责读取客户端发来的信息 + String str = reader.readLine(); + log.info("客户端说:" + str); + // main 线程负责读取客户端发来的信息 + writer.write("服务器收到消息:" + "\n"); + writer.flush(); } + + } catch (IOException e) { + close(); + //throw new RuntimeException(e); } + } public Socket getSocket() { @@ -60,8 +66,43 @@ public class ClientHandler implements Runnable { try { this.inputStream = socket.getInputStream(); this.outputStream = socket.getOutputStream(); + this.reader = new BufferedReader(new InputStreamReader(inputStream)); +// this.reader = new BufferedReader(new InputStreamReader(System.in)); + this.writer = new BufferedWriter(new OutputStreamWriter(outputStream)); } catch (IOException e) { throw new RuntimeException(e); } } + + public BufferedReader getReader() { + return reader; + } + + public void setReader(BufferedReader reader) { + this.reader = reader; + } + + public BufferedWriter getWriter() { + return writer; + } + + public void setWriter(BufferedWriter writer) { + this.writer = writer; + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } } diff --git a/src/main/java/com/zhangmeng/handler/HandlerApi.java b/src/main/java/com/zhangmeng/handler/HandlerApi.java new file mode 100644 index 0000000..01a3481 --- /dev/null +++ b/src/main/java/com/zhangmeng/handler/HandlerApi.java @@ -0,0 +1,14 @@ +package com.zhangmeng.handler; + +import java.net.Socket; + +/** + * @author zm + * @date 2025/2/22 11:53 + * @version: 1.0 + */ +public interface HandlerApi { + + void handle(Socket socket,byte[] data); + +} diff --git a/src/main/java/com/zhangmeng/service/Connection.java b/src/main/java/com/zhangmeng/service/Connection.java new file mode 100644 index 0000000..7071982 --- /dev/null +++ b/src/main/java/com/zhangmeng/service/Connection.java @@ -0,0 +1,28 @@ +package com.zhangmeng.service; + +import java.net.InetAddress; +import java.net.Socket; + +/** + * @author zm + * @date 2025/2/22 11:41 + * @version: 1.0 + */ +public interface Connection { + + + //启动连接,让当前连接开始工作 + public void Start(); + + //停止连接,结束当前连接状态M + public void Stop(); + + //从当前连接获取原始的socket TCPConn + public Socket GetTCPConnection(); + + //获取当前连接ID + public int GetConnID(); + + //获取远程客户端地址信息 + public InetAddress RemoteAddr(); +} diff --git a/src/main/java/com/zhangmeng/service/impl/ConnectionImpl.java b/src/main/java/com/zhangmeng/service/impl/ConnectionImpl.java new file mode 100644 index 0000000..4e6b2ef --- /dev/null +++ b/src/main/java/com/zhangmeng/service/impl/ConnectionImpl.java @@ -0,0 +1,166 @@ +package com.zhangmeng.service.impl; + +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; +import com.zhangmeng.handler.HandlerApi; +import com.zhangmeng.service.Connection; + +import java.io.*; +import java.net.InetAddress; +import java.net.Socket; + +/** + * @author zm + * @date 2025/2/22 11:41 + * @version: 1.0 + */ +public class ConnectionImpl implements Connection { + + private final Log log = LogFactory.get(); + + //当前连接的socket TCP套接字 + private Socket Conn; + //当前连接的ID 也可以称作为SessionID,ID全局唯一 + private int ConnID; + //当前连接的关闭状态 + private boolean isClosed; + + //该连接的处理方法api + private HandlerApi handleAPI; + + //告知该链接已经退出/停止的channel + boolean ExitBuffChan; + + private BufferedReader reader; + private BufferedWriter writer; + private OutputStream outputStream; + private InputStream inputStream; + + + //创建连接的方法 + public ConnectionImpl(Socket conn, int connID, HandlerApi callback_api) { + this.Conn = conn; + this.ConnID = connID; + this.isClosed = false; + this.handleAPI = callback_api; + this.ExitBuffChan = false; + + try { + this.inputStream = conn.getInputStream(); + this.outputStream = conn.getOutputStream(); + this.reader = new BufferedReader(new InputStreamReader(inputStream)); +// this.reader = new BufferedReader(new InputStreamReader(System.in)); + this.writer = new BufferedWriter(new OutputStreamWriter(outputStream)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void close() { + try { + reader.close(); + writer.close(); + outputStream.close(); + inputStream.close(); + Conn.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + //处理conn读数据的Goroutine + public void StartReader() { + log.info("Reader Goroutine is running"); + boolean exit = true; + while (exit) { + //读取我们最大的数据到buf中 + try { + String str = reader.readLine(); + //调用当前链接业务(这里执行的是当前conn的绑定的handle方法) + this.handleAPI.handle(this.Conn, str.getBytes()); +// log.info("recv buf : " + str); + writer.write(str + "\n"); + writer.flush(); + + } catch (IOException e) { +// throw new RuntimeException(e); + log.error("recv buf err ", e.getMessage()); + //退出循环 + exit = false; + this.ExitBuffChan = true; + this.Stop(); + } + } + + } + + + @Override + public void Start() { + log.info("Start ConnectionImpl .............................................."); + StartReader(); + } + + @Override + public void Stop() { + log.info("Stop ConnectionImpl .............................................."); + //关闭当前连接 + this.close(); + } + + @Override + public Socket GetTCPConnection() { + return null; + } + + @Override + public int GetConnID() { + return 0; + } + + @Override + public InetAddress RemoteAddr() { + return null; + } + + + public Socket getConn() { + return Conn; + } + + public void setConn(Socket conn) { + Conn = conn; + } + + public int getConnID() { + return ConnID; + } + + public void setConnID(int connID) { + ConnID = connID; + } + + public boolean isClosed() { + return isClosed; + } + + public void setClosed(boolean closed) { + isClosed = closed; + } + + public HandlerApi getHandleAPI() { + return handleAPI; + } + + public void setHandleAPI(HandlerApi handleAPI) { + this.handleAPI = handleAPI; + } + + public boolean isExitBuffChan() { + return ExitBuffChan; + } + + public void setExitBuffChan(boolean exitBuffChan) { + ExitBuffChan = exitBuffChan; + } +} diff --git a/src/main/java/com/zhangmeng/service/impl/ServerImpl.java b/src/main/java/com/zhangmeng/service/impl/ServerImpl.java index 59d8a24..4a1f043 100644 --- a/src/main/java/com/zhangmeng/service/impl/ServerImpl.java +++ b/src/main/java/com/zhangmeng/service/impl/ServerImpl.java @@ -9,7 +9,9 @@ import cn.hutool.log.StaticLog; import cn.hutool.socket.aio.AioServer; import cn.hutool.socket.aio.AioSession; import cn.hutool.socket.aio.SimpleIoAction; +import com.zhangmeng.callBack.HandlerApiCallBack; import com.zhangmeng.handler.ClientHandler; +import com.zhangmeng.service.Connection; import com.zhangmeng.service.Server; import java.io.*; @@ -18,6 +20,11 @@ import java.net.Socket; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * @author zm @@ -32,20 +39,33 @@ public class ServerImpl implements Server { private ServerSocket serverSocket; + private BufferedReader in; + + public static Map socketList = new HashMap<>(); + @Override public void Start() { log.info("[START] Server listenner at IP: {}, Port {}, is starting", config.getIP(), config.getPort()); try { serverSocket = new ServerSocket(config.getPort()); + int cid = 0; + while (true) { Socket accept = serverSocket.accept(); + String key = accept.getInetAddress().getHostAddress() + ":" + accept.getPort(); + socketList.put(key, accept); + log.info("key=====================================: " + key); + //new ClientHandler(accept).start(); log.info("[ACCEPT] Accept a client at IP: {}, Port {}", accept.getInetAddress().getHostAddress(), accept.getPort()); - new Thread(new ClientHandler(accept)).start(); + Connection conn = new ConnectionImpl(accept,cid,new HandlerApiCallBack()); + conn.Start(); + cid++; } } catch (IOException e) { - throw new RuntimeException(e); +// throw new RuntimeException(e); + log.error(e.getMessage()); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..47fbb02 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8080 \ No newline at end of file diff --git a/src/test/java/com/zhangmeng/AppTest.java b/src/test/java/com/zhangmeng/AppTest.java index be597b1..d52ddae 100644 --- a/src/test/java/com/zhangmeng/AppTest.java +++ b/src/test/java/com/zhangmeng/AppTest.java @@ -1,9 +1,9 @@ package com.zhangmeng; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; +import java.net.InetAddress; import java.net.Socket; +import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Scanner; @@ -14,25 +14,64 @@ import java.util.Scanner; public class AppTest { public static void main(String[] args) throws IOException { - Scanner scanner = new Scanner(System.in); - System.out.println("等待连接服务端!"); - Socket socket = new Socket("127.0.0.1", 8888); - System.out.println("连接服务端成功!"); - while (true) { - // 给服务端发信息 - System.out.print("请输入:"); - String s = scanner.next(); - if ("out".equals(s)) { - break; + Socket socket = null; + BufferedReader in = null; + BufferedWriter out = null; + BufferedReader br = null; + try { + //创建 Socket 对象,指定服务器端的 IP 与端口 + socket = new Socket(InetAddress.getLocalHost(), 9999); + //获取 scoket 的输入输出流接收和发送信息 + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + out = new BufferedWriter(new + OutputStreamWriter(socket.getOutputStream())); + br = new BufferedReader(new InputStreamReader(System.in)); + while (true) { + //发送信息 + String str = br.readLine(); + out.write(str + "\n"); + out.flush(); + //如果输入的信息为“end”则终止连接 + if (str.equals("end")) { + break; + } + //否则,接收并输出服务器端信息 + System.out.println("服务器端说:" + in.readLine()); + } + } catch (UnknownHostException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if(out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(br != null) { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(socket != null) { + try { + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } } - OutputStream outputStream = socket.getOutputStream(); - outputStream.write(s.getBytes(StandardCharsets.UTF_8)); - byte[] bytes = new byte[1024]; - - // 读一下服务端发来的信息 - InputStream inputStream = socket.getInputStream(); - int read = inputStream.read(bytes); - System.out.println("服务端:" + new String(bytes, 0, read, Charset.defaultCharset())); } }