2025年2月22日15:38:46
parent
6b872416ae
commit
1fb7180327
18
pom.xml
18
pom.xml
|
|
@ -7,16 +7,28 @@
|
|||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<name>Tcp-Server</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>21</java.version>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
|
@ -36,8 +48,8 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>21</source>
|
||||
<target>21</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.zhangmeng;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/2/22 11:12
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class Constant {
|
||||
}
|
||||
|
|
@ -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 )
|
||||
{
|
||||
@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(8888);
|
||||
config.setPort(9999);
|
||||
ServerImpl server = new ServerImpl();
|
||||
server.setConfig(config);
|
||||
server.Start();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
while (true) {
|
||||
// main 线程负责读取客户端发来的信息
|
||||
String str = reader.readLine();
|
||||
log.info("客户端说:" + str);
|
||||
// main 线程负责读取客户端发来的信息
|
||||
writer.write("服务器收到消息:" + "\n");
|
||||
writer.flush();
|
||||
}
|
||||
String message = new String(bytes, 0, len);
|
||||
System.out.println("receive message: " + message);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Socket> 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
server:
|
||||
port: 8080
|
||||
|
|
@ -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("连接服务端成功!");
|
||||
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) {
|
||||
// 给服务端发信息
|
||||
System.out.print("请输入:");
|
||||
String s = scanner.next();
|
||||
if ("out".equals(s)) {
|
||||
//发送信息
|
||||
String str = br.readLine();
|
||||
out.write(str + "\n");
|
||||
out.flush();
|
||||
//如果输入的信息为“end”则终止连接
|
||||
if (str.equals("end")) {
|
||||
break;
|
||||
}
|
||||
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()));
|
||||
//否则,接收并输出服务器端信息
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue