需求:公司的物联网设备要实现远程交互,只支持TCPSocket协议,估写此文章以做记录
不了解网络协议的可以先看一下这篇文章:
1.准备工作
1.安装配置好Java环境,这边是jdk1.8
2.下载一个网络调试助手做测试
2.服务端代码编写
package com.lianxian.web.core.config;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: QiuHong
* @Date: 2023/11/15 13:29
* @className: lianxian
* @Description:
* @Version: 1.0
*/
@Component
public class TcpSocketServer {
// 这个集合保存目前在线的socket
public static List<Socket> onLineSocketList = new ArrayList<>();
private int serverPort = 18081;
public void server() {
try {
// 创建TCP服务器并绑定到指定端口
ServerSocket serverSocket = new ServerSocket(serverPort);
System.out.println("---服务器已启动,等待客户端连接---");
// 创建线程池,处理消息管道中的任务
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
32, // 核心线程数 io密集型 一般是物理设备的线程数*2
32, // 最大线程数
0, // 临时线程存活时间
TimeUnit.SECONDS, // 单位s
new ArrayBlockingQueue<>(8), // 缓存客户端请求数
Executors.defaultThreadFactory(), // 创建工厂(这里是默认工厂)
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略(这里是直接拒绝)
);
while (true) {
// 等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("clientSocket" + socket);
System.out.println("客户端连接成功");
// 同步目前在线的socket
onLineSocketList.add(socket);
// 通过线程池将任务分发给其他线程
threadPoolExecutor.execute(new TcpSocketServerRunnable(socket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.服务器逻辑处理
package com.lianxian.web.core.config;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* @Author: QiuHong
* @Date: 2024/1/17 13:40
* @className: lianxian
* @Description: tcpSocket处理消息的线程
* @Version: 1.0
*/
public class TcpSocketServerRunnable implements Runnable {
private Socket socket;
public TcpSocketServerRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 创建输入流和输出流
//要和客户端的输入输出流保持一致
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
while (true) {
try {
// 读取客户端发送的数据
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
String message = new String(bytes, 0, read, StandardCharsets.UTF_8);
System.out.println(socket + "---serverMessage" + message);
// 将消息分发到所有在线socket通道
sendMessageAll(message);
} catch (IOException e) {
// 客户端下线抛出异常
// 同步在线列表,关闭输入流,关闭输出流,关闭socket,停止等待消息
TcpSocketServer.onLineSocketList.remove(socket);
inputStream.close();
outputStream.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将消息分发到所有在线socket通道
*
* @param message
* @throws IOException
*/
private void sendMessageAll(String message) throws IOException {
for (Socket onLineSocket : TcpSocketServer.onLineSocketList) {
OutputStream outputStream = onLineSocket.getOutputStream();
outputStream.write(message.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
}
}
4.客户端代码编写
package com.lianxian.web.core.config;
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* @Author: QiuHong
* @Date: 2024/1/17 14:07
* @className: lianxian
* @Description:
* @Version: 1.0
*/
public class TcpSocketClient {
public static void creatTcpSocketClient(String message) {
try {
// 创建socket对象,与服务器建立连接
Socket socket = new Socket("192.168.1.110", 18081);
// 创建独立线程,接收消息
new Thread(new TcpSocketClientRunnable(socket)).start();
// 获取字节输出流
OutputStream outputStream = socket.getOutputStream();
// 这里由于业务需求写完数据直接断开连接了,
// 如果是需要不断地写入可以写死循环,让线程等待消息
// 写数据
while (true){
outputStream.write(message.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
// outputStream.close();
// socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.客户端逻辑处理
package com.lianxian.web.core.config;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* @Author: QiuHong
* @Date: 2024/1/17 13:40
* @className: lianxian
* @Description: tcpSocket处理消息的线程
* @Version: 1.0
*/
public class TcpSocketClientRunnable implements Runnable {
private Socket socket;
public TcpSocketClientRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 获取输入流
InputStream inputStream = socket.getInputStream();
while (true) {
try {
// 读取客户端发送的数据
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
String message = new String(bytes, 0, read, StandardCharsets.UTF_8);
System.out.println(socket + "---serverMessage" + message);
} catch (IOException e) {
// 下线抛出异常
// 关闭输入流,关闭socket,停止等待消息
inputStream.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}