首先在项目启动的时候开启 socket 服务,我这是使用的springboot
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
@Component
@Order(value = 2)
public class SocketServiceRun implements CommandLineRunner {
private final static Logger logger = LoggerFactory.getLogger(SocketServiceRun.class);
private static final int PORT = 99999;
@Override
public void run(String... args) throws Exception {
try {
//建立服务器连接,设定客户连接请求队列的长度 ↓↓↓↓
ServerSocket server = new ServerSocket(PORT,50);
logger.info("Socket 服务已开启,等待连接:"+ PORT);
while (true) {
// 等待客户连接
Socket socket = server.accept();
//连接后30秒断开连接
//socket.setSoTimeout(30000);
// 每个客户端都给单独开一个线程
new Thread(new ServerThread(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
线程实现类
这个地方有很多人直接使用 InputStream 来进行读流 ,会遇到的问题就是:不知道是否全部读取完毕,所以需要在参数中添加特殊符号进行分割,也就是大部分博客中解决粘包问题的方案,我这边直接使用 DataInputStream 来进行读取,有提供 available() 判断是否是一个完整的请求,这样就很好解决粘包问题了
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ServerThread implements Runnable {
private final static Logger logger = LoggerFactory.getLogger(ServerThread.class);
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
// 任务是为一个用户提供服务
@Override
public void run() {
try {
//封装输入流(接收客户端的流)
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// 读取客户端传过来信息的DataInputStream
DataInputStream dis = new DataInputStream(bis);
// 向客户端发送信息的DataOutputStream
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
/*int count = in.available(); // 获取整个请求字节长度
byte[] bytes = new byte[count];
dis.read(bytes);
在进行网络操作时往往出错,因为你调用available()方法时,对方发送的数据可能还没有到达,你得到的count是0。
需要改成这样:
int count = 0;
while (count == 0) {
count = dis.available();
}*/
byte[] bytes = new byte[1]; // 一次性读取一个字节
byte[] newBytes = new byte[0];
String message = "";
while (dis.read(bytes) != -1) {
newBytes = StringUtil.byteMerger(newBytes, bytes);
if (dis.available() == 0) { // read(bytes) 之后 dis 中没有字节了 ,表示一个请求全部读取完毕了
message = new String(newBytes, "GBK"); // 客户端传过来的是 ascii 码
// message = StringUtil.bytesToHexString(bytes) + ""; // 客户端传过来的是 hex(十六进制) 格式数据
// message = new String(newBytes); //客户端传过来的是 文本格式
logger.info("接收到客户端数据:" + message);
// 以下进行业务操作
/*XXXServiceImpl service = SpringUtils.getBean("XXXServiceImpl");
String result = service.addData(message.trim()); // 除去首尾空格
// 清空这次请求的数据 方便下次接收
newBytes = new byte[0];
message = new String();
out.write(result.getBytes());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
下面是 StringUtil 工具类
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by AnZhi_Liu on 2021/1/15 0015 16:00
*/
public class StringUtil {
/**
* 去除字符串中的空格 、回车 、换行符、制表符
*
* @param str
* @return
*/
public static String replaceBlank(String str) {
String dest = "";
if (str != null) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(str);
dest = m.replaceAll("");
}
return dest;
}
/**
* 判断Object对象为空或空字符串
*
* @param obj
* @return
*/
public static Boolean isObjectNotEmpty(Object obj) {
String str = ObjectUtils.toString(obj, "");
Boolean flag = StringUtils.isNotBlank(str);
return flag;
}
/**
* 判断Object对象为空或空字符串
*
* @param obj
* @return
*/
public static Boolean isObjectEmpty(Object obj) {
String str = ObjectUtils.toString(obj, "");
return !StringUtils.isNotBlank(str);
}
/**
* byte[]数组转换为16进制的字符串
*
* @param bytes 要转换的字节数组
* @return 转换后的结果
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
/**
* 16进制的字符串转成字节数组
*
* @param hexString 16进制格式的字符串
* @return 转换后的字节数组
**/
public static byte[] toByteArray(String hexString) {
hexString = hexString.replaceAll("", "");
final byte[] byteArray = new byte[hexString.length() / 2];
int k = 0;
for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
byteArray[i] = (byte) (high << 4 | low);
k += 2;
}
return byteArray;
}
/**
* 字符串转换为 ASCLL
*
* @param value
* @return
*/
public static String stringToAscii(String value) {
StringBuffer sbu = new StringBuffer();
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (i != chars.length - 1) {
sbu.append((int) chars[i]).append(",");
} else {
sbu.append((int) chars[i]);
}
}
return sbu.toString();
}
/**
* ASCLL 转换为字符串
*
* @param value
* @return
*/
public static String asciiToString(String value) {
StringBuffer sbu = new StringBuffer();
String[] chars = value.split(",");
for (int i = 0; i < chars.length; i++) {
sbu.append((char) Integer.parseInt(chars[i]));
}
return sbu.toString();
}
/**
* 16进制字符串 转换成为string类型字符串
*
* @param s
* @return
*/
public static String hexStringToString(String s) {
if (s == null || s.equals("")) {
return null;
}
s = s.replace(" ", "");
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
try {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
s = new String(baKeyword, "UTF-8");
new String();
} catch (Exception e1) {
e1.printStackTrace();
}
return s;
}
/**
* 字符串转换成为16进制(无需Unicode编码)
*
* @param str
* @return
*/
public static String str2HexStr(String str) {
char[] chars = "0123456789ABCDEF".toCharArray();
StringBuilder sb = new StringBuilder("");
byte[] bs = str.getBytes();
int bit;
for (int i = 0; i < bs.length; i++) {
bit = (bs[i] & 0x0f0) >> 4;
sb.append(chars[bit]);
bit = bs[i] & 0x0f;
sb.append(chars[bit]);
// sb.append(' ');
}
return sb.toString().trim();
}
/**
* 合并两个byte数组
*
* @param byte_1
* @param byte_2
* @return
*/
public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
byte[] byte_3 = new byte[byte_1.length + byte_2.length];
System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
return byte_3;
}
}