解决
- 怎么解决,就是 日志别输出到 cmd 就行了。就行了。就行了。
sh
复制代码
java -jar demo.jar > output.log 2>&1 &
- 最近写东西,遇到了 程序偶尔卡死的情况。是java -jar 启动的。
- 具体卡死为:http请求超级卡顿 或 偶尔反应好多个请求,或 tcp Server 粘包,无法收取消息。
- 直到:我晃了晃 cmd 窗口,最大化,最小化,程序竟然动了,日志又输出了。
- 终于终于明白了,Window cmd 即要保证正常输出,又要保证性能不卡死你的程序
- 那你的程序又输出了很多很多日志,那cmd窗口怎么办呢,只有卡死你的程序了。
怀疑流程
- 因为遇到的是 http请求 和 tcp server 或同时能用,同时不能用,或只能用一个。
- 怀疑1:是 bio tcp server出现了问题,用了 nio 还一样,疯了。
- 怀疑2:spring boot 或 spring框架的问题 或 开线程等等问题,最终各种启动 config配置类,配置bean。在 main方法。使用postConstruct 等等等
- 最后还是没找到问题
java
复制代码
//ApplicationContext context
//@PostConstruct
//@Async
@EventListener(ApplicationReadyEvent.class)
/*
@Component
public class TcpServerListener implements ApplicationListener<WebServerInitializedEvent> {
@Autowired
private UpdateServer updateServer;
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
//int serverPort = event.getWebServer().getPort();
// 在此处添加代码以创建和启动 TCP 服务器
updateServer.startServer(8082);
}
}
*/
BIO
java
复制代码
//@Component
public class UpdateServer {
/*@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@EventListener(ApplicationReadyEvent.class)
public void startServerSocket() throws IOException {
// 创建ServerSocket并绑定端口
ServerSocket serverSocket = new ServerSocket(8080);
// 启动一个新线程来接受客户端连接
new Thread(() -> {
while (true) {
try {
// 接受客户端连接
Socket clientSocket = serverSocket.accept();
// 处理客户端请求,可以在这里实现自己的逻辑
// 关闭客户端连接
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}*/
/*
@Component
public class TcpServerListener implements ApplicationListener<WebServerInitializedEvent> {
@Autowired
private UpdateServer updateServer;
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
//int serverPort = event.getWebServer().getPort();
// 在此处添加代码以创建和启动 TCP 服务器
updateServer.startServer(8082);
}
}
*/
/**
* TCP升级网关
*/
//@Resource
//private TcpUpdateMapper tcpUpdateMapper;
/**
* Redis
*/
//@Resource
//private RedisUtil redisUtil;
//new Thread(() -> { }).start();
//@PostConstruct
//@Async
/*public void startServer() throws Exception {
//开启TCP Server
ServerSocket serverSocket = new ServerSocket(8082);
log.info("服务端打开了 Server started on port {}", 8082);
while (true) {
//等待连接
Socket socket = serverSocket.accept();
//获取 输入流
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
log.info("服务端收到了连接:Accepted connection from client: {}", socket.getInetAddress());
//读取的字节数
byte[] buffer = new byte[380];//1024
//真正读取到了多少个
int bytesRead;
//循环进行读取
while ((bytesRead = inputStream.read(buffer)) != -1) {
//处理二进制数据
processBinaryData(buffer, bytesRead, socket, outputStream);
}//循环读取,正常每次都会读取完毕
inputStream.close();
outputStream.close();
socket.close();
}//死循环接收连接
}//初始化方法结束*/
//关闭输入流
//socket.shutdownInput();
//关闭输出流,关闭 Socket
//socket.shutdownOutput();
//关闭Socket
//socket.close();
NIO
java
复制代码
@Configuration
public class TcpServerConfig {
/**
* TCP升级网关
*/
@Resource
private TcpUpdateMapper tcpUpdateMapper;
/**
* Redis
*/
@Resource
private StringRedisTemplate stringRedisTemplate;
@Value("${tcp.ip}")
private String tcpIp;
//ApplicationContext context
//@PostConstruct
//@Async
@EventListener(ApplicationReadyEvent.class)
public void startServer() {// throws IOException
//异步执行
//ThreadUtil.execAsync(() -> {
try {
//打开选择器
Selector selector = Selector.open();
//打开通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//非阻塞
serverSocketChannel.configureBlocking(false);
//本机IP
serverSocketChannel.bind(new InetSocketAddress(tcpIp, 8082));
//进行注册
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
log.info("===============Server started on port 8082===================");
while (true) {
//打开通道
int readyChannels = selector.select();
//校验下
if (readyChannels == 0) {
continue;
}
//获取所有的key
Set<SelectionKey> selectedKeys = selector.selectedKeys();
//取得迭代器
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
//如果存在
while (keyIterator.hasNext()) {
//获取这个key
SelectionKey key = keyIterator.next();
//如果是个连接
if (key.isAcceptable()) {
//打开这个通道
SocketChannel clientSocketChannel = serverSocketChannel.accept();
//非阻塞的
clientSocketChannel.configureBlocking(false);
//注册为可读
clientSocketChannel.register(selector, SelectionKey.OP_READ);
log.info("收到连接:Accepted connection from: {}", clientSocketChannel.getRemoteAddress());
} else if (key.isReadable()) {
//如果是可读,获取通道
SocketChannel clientSocketChannel = (SocketChannel) key.channel();
//读取数量
ByteBuffer buffer = ByteBuffer.allocate(38);//1024
//真实读取到了多少个
int bytesRead = -1;
try {
//这里报错了,增加防护,如果防护,这个nio就断了
bytesRead = clientSocketChannel.read(buffer);
} catch (Exception e) {
log.info("未读取到");
e.printStackTrace();
}
//未读取到 关闭
if (bytesRead == -1) {
clientSocketChannel.close();
} else if (bytesRead > 0) {
//读取到了
buffer.flip();
//读到这个字节里
byte[] data = new byte[bytesRead];
buffer.get(data);
//处理逻辑
processBinaryData(data, bytesRead, clientSocketChannel);
//String message = new String(data).trim();
//System.out.println("Received message: " + message);
//清理
buffer.clear();
}//读到了
}//是可读的
//移除key
keyIterator.remove();
}//如果存在
}//死循环
} catch (Exception e) {
e.printStackTrace();
}
//}, "MyTcpServerThread").start();
}
java
复制代码
//有错误,往外层抛
private void sendUpdateMessage(SocketChannel clientSocketChannel) {
//去空格
redisData = redisData.replace(" ", "");
//转为byte
byte[] binaryData = hexStringToBytes(redisData);
//申请字节
ByteBuffer buffer = ByteBuffer.allocate(binaryData.length);
//写入
buffer.put(binaryData);
buffer.flip();
//循环写入
while (buffer.hasRemaining()) {
try {
clientSocketChannel.write(buffer);
log.info("发送了一次升级的消息");
} catch (IOException e) {
log.info("发送升级失败");
e.printStackTrace();
}
}
}