2023年5月6日15:40:08

master
zhangmeng 2023-05-06 15:40:25 +08:00
parent a27cd57cbf
commit 414a9c632c
11 changed files with 604 additions and 50 deletions

View File

@ -0,0 +1,118 @@
package com.zhangmeng.tools.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import cn.hutool.socket.aio.AioClient;
import cn.hutool.socket.aio.AioSession;
import cn.hutool.socket.aio.SimpleIoAction;
import com.zhangmeng.tools.utils.AlertUtils;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* @author :
* @version : 1.0
* @date : 2023-05-06 10:38
*/
public class AioClientSocketController {
@FXML
public TextField ip_address;
@FXML
public TextArea content;
@FXML
public Button connection;
@FXML
public TextField input;
@FXML
public Button send;
@FXML
public TextField port;
@FXML
public Button disconn;
private AioClient client;
private AioSession aioSession;
private void appendMsg(String msg) {
content.appendText(System.lineSeparator());
content.appendText(msg);
}
@FXML
public void initialize() {
ip_address.setText("localhost");
port.setText("8083");
connection.setOnAction(event -> {
content.setText(null);
if (ip_address.getText().length() == 0 ){
AlertUtils.alert_warning("ip不能为空");
return;
}
if (port.getText().length() == 0 ){
AlertUtils.alert_warning("端口不能为空");
return;
}
client = new AioClient(new InetSocketAddress(ip_address.getText(), Integer.parseInt(port.getText())), new SimpleIoAction() {
@Override
public void doAction(AioSession session, ByteBuffer data) {
appendMsg("========>客户端接收" + new Date() + "=======>:" + StrUtil.utf8Str(data));
if (data.hasRemaining()) {
} else {
session.read();
}
}
@Override
public void accept(AioSession session) {
aioSession = session;
appendMsg("客户端链接成功!" + session.getRemoteAddress().toString());
}
@Override
public void failed(Throwable exc, AioSession session) {
exc.printStackTrace();
super.failed(exc, session);
}
});
client.read();
});
send.setOnAction(event -> {
send();
});
disconn.setOnAction(event -> {
client.close();
});
}
private void send() {
if (input.getText().length() == 0) {
AlertUtils.alert_warning("发送的内容不能为空");
return;
}
String msg = input.getText();
client.write(ByteBuffer.wrap(msg.getBytes()));
appendMsg("========>客户端发送" + new Date() + "=======>:" + msg );
}
}

View File

@ -0,0 +1,128 @@
package com.zhangmeng.tools.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import cn.hutool.socket.aio.AioClient;
import cn.hutool.socket.aio.AioServer;
import cn.hutool.socket.aio.AioSession;
import cn.hutool.socket.aio.SimpleIoAction;
import com.zhangmeng.tools.utils.AlertUtils;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* @author :
* @version : 1.0
* @date : 2023-05-06 10:38
*/
@Slf4j
public class AioServerSocketController {
@FXML
public TextArea content;
@FXML
public TextField input;
@FXML
public Button send;
@FXML
public TextField port;
public Button start_server;
public Button close_server;
private AioServer aioServer;
private AioSession aioSession;
private void appendMsg(String msg) {
content.appendText(System.lineSeparator());
content.appendText(msg);
}
@FXML
public void initialize() {
port.setText("8083");
start_server.setOnAction(event -> {
content.setText(null);
if (port.getText().length() == 0) {
AlertUtils.alert_warning("端口不能为空");
return;
}
new Thread(() -> {
aioServer = new AioServer(Integer.parseInt(port.getText())) {
@Override
public void start(boolean sync) {
log.debug("Aio Server started, waiting for accept.");
appendMsg("服务启动成功============================================================================================");
// 接收客户端连接
accept();
// if (sync) {
// ThreadUtil.sync(this);
// }
}
};
aioServer.setIoAction(new SimpleIoAction() {
@Override
public void accept(AioSession session) {
aioSession = session;
String msg = "【客户端】:{} 连接。" + session.getRemoteAddress();
appendMsg(msg);
session.write(BufferUtil.createUtf8("=== Welcome to Hutool socket server. ==="));
}
@Override
public void failed(Throwable exc, AioSession session) {
exc.printStackTrace();
super.failed(exc, session);
}
@Override
public void doAction(AioSession session, ByteBuffer data) {
appendMsg("========>服务端接收" + new Date() + "=======>:" + StrUtil.utf8Str(data));
if (data.hasRemaining()) {
session.read();
}
}
}).start(true);
}).start();
});
send.setOnAction(event -> {
send();
});
close_server.setOnAction(event -> {
if (aioServer.isOpen()) {
aioServer.close();
appendMsg("服务关闭成功============================================================================================");
}
});
}
private void send() {
if (input.getText().length() == 0) {
AlertUtils.alert_warning("发送的内容不能为空");
return;
}
String msg = input.getText();
aioSession.write(ByteBuffer.wrap(msg.getBytes()));
appendMsg("========>服务端发送" + new Date() + "=======>:" + msg );
}
}

View File

@ -546,4 +546,16 @@ public class HomeController implements Serializable {
public void batch_update_file_name_menu_item(ActionEvent event) {
load_small_tools(14);
}
public void socket_client_aio_menu_item(ActionEvent event) {
load_server_tools(4);
}
public void socket_server_aio_menu_item(ActionEvent event) {
load_server_tools(5);
}
public void socket_server_nio_menu_item(ActionEvent event) {
load_server_tools(6);
}
}

View File

@ -0,0 +1,129 @@
package com.zhangmeng.tools.controller;
import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.socket.aio.AioServer;
import cn.hutool.socket.aio.AioSession;
import cn.hutool.socket.aio.SimpleIoAction;
import cn.hutool.socket.nio.NioServer;
import com.zhangmeng.tools.utils.AlertUtils;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;
/**
* @author :
* @version : 1.0
* @date : 2023-05-06 15:18
*/
@Slf4j
public class NioServerSocketController {
@FXML
public TextArea content;
@FXML
public TextField input;
@FXML
public Button send;
@FXML
public TextField port;
public Button start_server;
public Button close_server;
private NioServer nioServer;
private SocketChannel channel;
private void appendMsg(String msg) {
content.appendText(System.lineSeparator());
content.appendText(msg);
}
@FXML
public void initialize() {
port.setText("8083");
start_server.setOnAction(event -> {
content.setText(null);
if (port.getText().length() == 0) {
AlertUtils.alert_warning("端口不能为空");
return;
}
new Thread(() -> {
nioServer = new NioServer(Integer.parseInt(port.getText()));
nioServer.setChannelHandler((sc) -> {
channel = sc;
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
try {
//从channel读数据到缓冲区
int readBytes = sc.read(readBuffer);
if (readBytes > 0) {
//Flips this buffer. The limit is set to the current position and then
// the position is set to zero就是表示要从起始位置开始读取数据
readBuffer.flip();
//eturns the number of elements between the current position and the limit.
// 要读取的字节长度
byte[] bytes = new byte[readBuffer.remaining()];
//将缓冲区的数据读到bytes数组
readBuffer.get(bytes);
String body = StrUtil.utf8Str(bytes);
appendMsg("========>服务端接收" + new Date() + "=======>:" + body);
doWrite(sc, body);
} else if (readBytes < 0) {
IoUtil.close(sc);
}
} catch (IOException e) {
throw new IORuntimeException(e);
}
});
nioServer.listen();
}).start();
});
send.setOnAction(event -> {
send();
});
close_server.setOnAction(event -> {
nioServer.close();
appendMsg("服务关闭成功============================================================================================");
});
}
public static void doWrite(SocketChannel channel, String response) throws IOException {
response = "收到消息:" + response;
//将缓冲数据写入渠道,返回给客户端
channel.write(BufferUtil.createUtf8(response));
}
private void send() {
if (input.getText().length() == 0) {
AlertUtils.alert_warning("发送的内容不能为空");
return;
}
String msg = input.getText();
try {
channel.write(ByteBuffer.wrap(msg.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
appendMsg("========>服务端发送" + new Date() + "=======>:" + msg);
}
}

View File

@ -43,6 +43,10 @@ public class ServerToolsController {
private AnchorPane ftpServer;
private AnchorPane sshClient;
private AnchorPane socketServer;
private AnchorPane socket_client_aio;
private AnchorPane socket_server_aio;
private AnchorPane socket_server_nio;
public static final String color_cell = "#f4f4f4";
@ -276,10 +280,75 @@ public class ServerToolsController {
}
socketServer(flag);
}
if (newValue.getIndex() == 4){
if (socket_client_aio != null){
flag = true;
}
socket_client_aio(flag);
}
if (newValue.getIndex() == 5){
if (socket_server_aio != null){
flag = true;
}
socket_server_aio(flag);
}
if (newValue.getIndex() == 5){
if (socket_server_nio != null){
flag = true;
}
socket_server_nio(flag);
}
}
});
}
private void socket_server_nio(boolean flag) {
listView.getSelectionModel().select(6);
if (!flag){
try {
root = FXMLLoader.load(ResourcesUtils.getResource("socket-server-nio"));
} catch (IOException e) {
e.printStackTrace();
}
socket_server_nio = root;
}else {
root = socket_server_nio;
}
common_method();
}
private void socket_server_aio(boolean flag) {
listView.getSelectionModel().select(5);
if (!flag){
try {
root = FXMLLoader.load(ResourcesUtils.getResource("socket-server-aio"));
} catch (IOException e) {
e.printStackTrace();
}
socket_server_aio = root;
}else {
root = socket_server_aio;
}
common_method();
}
private void socket_client_aio(boolean flag) {
listView.getSelectionModel().select(4);
if (!flag){
try {
root = FXMLLoader.load(ResourcesUtils.getResource("socket-client-aio"));
} catch (IOException e) {
e.printStackTrace();
}
socket_client_aio = root;
}else {
root = socket_client_aio;
}
common_method();
}
private void socketServer(boolean flag){
listView.getSelectionModel().select(3);
if (!flag){
@ -288,9 +357,9 @@ public class ServerToolsController {
} catch (IOException e) {
e.printStackTrace();
}
ftpServer = root;
socketServer = root;
}else {
root = ftpServer;
root = socketServer;
}
common_method();
}
@ -352,6 +421,9 @@ public class ServerToolsController {
case Ftp_Server -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
case SSH_Client -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
case Socket_Server -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
case Socket_client_aio -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
case Socket_server_aio -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
case Socket_server_nio -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
};
}
@ -524,4 +596,13 @@ public class ServerToolsController {
public void maven_jar_install_menu_item(ActionEvent event) {
load_small_tools(10);
}
public void socket_client_aio_menu_item(ActionEvent event) {
boolean flag = false;
}
public void socket_server_aio_menu_item(ActionEvent event) {
boolean flag = false;
}
}

View File

@ -26,6 +26,7 @@
package com.zhangmeng.tools.utils;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
@ -288,7 +289,10 @@ public class ResourcesUtils {
Http_Server("Http Server工具", 0),
Ftp_Server("Ftp Server工具", 1),
SSH_Client("ssh 连接工具", 2),
Socket_Server("socket Server",3);
Socket_Server("socket Server", 3),
Socket_client_aio("aio socket client",4),
Socket_server_aio("aio socket server",5),
Socket_server_nio("aio socket server",6),
;
ServerTools(String title, int index) {

View File

@ -81,6 +81,9 @@
<MenuItem mnemonicParsing="false" text="ftp-server 请求工具" onAction="#ftp_server_menu_item"/>
<MenuItem mnemonicParsing="false" text="ssh-client 请求工具" onAction="#ssh_client_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-server 服务工具" onAction="#socket_server_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-client-aio 客户端工具" onAction="#socket_client_aio_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-server-aio 服务端工具" onAction="#socket_server_aio_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-server-nio 服务端工具" onAction="#socket_server_nio_menu_item"/>
</items>
</Menu>
</menus>

View File

@ -74,6 +74,8 @@
<MenuItem mnemonicParsing="false" text="ftp-server 请求工具" onAction="#ftp_server_menu_item"/>
<MenuItem mnemonicParsing="false" text="ssh-client 连接工具" onAction="#ssh_client_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-server 服务工具" onAction="#socket_server_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-client-aio 客户端工具" onAction="#socket_client_aio_menu_item"/>
<MenuItem mnemonicParsing="false" text="socket-server-aio 服务端工具" onAction="#socket_server_aio_menu_item"/>
</items>
</Menu>
</menus>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.AioClientSocketController">
<children>
<Label layoutX="91.0" layoutY="95.0" text="ip地址:" />
<TextField fx:id="ip_address" layoutX="157.0" layoutY="91.0" prefHeight="25.0" prefWidth="317.0" />
<TextField fx:id="port" layoutX="659.0" layoutY="91.0" />
<Label layoutX="606.0" layoutY="95.0" text="端口:" />
<Label layoutX="91.0" layoutY="163.0" text="内容:" />
<TextArea fx:id="content" layoutX="157.0" layoutY="172.0" prefHeight="264.0" prefWidth="988.0" AnchorPane.bottomAnchor="213.0" AnchorPane.leftAnchor="157.0" AnchorPane.rightAnchor="55.0" AnchorPane.topAnchor="172.0" />
<Button fx:id="connection" layoutX="864.0" layoutY="91.0" mnemonicParsing="false" text="连接" />
<Label layoutX="89.0" layoutY="469.0" text="输入:" AnchorPane.bottomAnchor="163.0" />
<TextField fx:id="input" layoutX="155.0" layoutY="465.0" prefHeight="25.0" prefWidth="667.0" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="send" layoutX="849.0" layoutY="465.0" mnemonicParsing="false" text="发送" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="disconn" layoutX="955.0" layoutY="91.0" mnemonicParsing="false" text="断开连接" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
</AnchorPane>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.AioServerSocketController">
<children>
<TextField fx:id="port" layoutX="157.0" layoutY="91.0" />
<Label layoutX="89.0" layoutY="95.0" text="端口:" />
<Label layoutX="91.0" layoutY="163.0" text="内容:" />
<TextArea fx:id="content" layoutX="157.0" layoutY="172.0" prefHeight="264.0" prefWidth="988.0" AnchorPane.bottomAnchor="213.0" AnchorPane.leftAnchor="157.0" AnchorPane.rightAnchor="55.0" AnchorPane.topAnchor="172.0" />
<Button fx:id="start_server" layoutX="358.0" layoutY="91.0" mnemonicParsing="false" text="启动服务" />
<Label layoutX="89.0" layoutY="469.0" text="输入:" AnchorPane.bottomAnchor="163.0" />
<TextField fx:id="input" layoutX="155.0" layoutY="465.0" prefHeight="25.0" prefWidth="667.0" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="send" layoutX="849.0" layoutY="465.0" mnemonicParsing="false" text="发送" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="close_server" layoutX="457.0" layoutY="91.0" mnemonicParsing="false" text="关闭服务" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
</AnchorPane>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.NioServerSocketController">
<children>
<TextField fx:id="port" layoutX="157.0" layoutY="91.0" />
<Label layoutX="89.0" layoutY="95.0" text="端口:" />
<Label layoutX="91.0" layoutY="163.0" text="内容:" />
<TextArea fx:id="content" layoutX="157.0" layoutY="172.0" prefHeight="264.0" prefWidth="988.0" AnchorPane.bottomAnchor="213.0" AnchorPane.leftAnchor="157.0" AnchorPane.rightAnchor="55.0" AnchorPane.topAnchor="172.0" />
<Button fx:id="start_server" layoutX="358.0" layoutY="91.0" mnemonicParsing="false" text="启动服务" />
<Label layoutX="89.0" layoutY="469.0" text="输入:" AnchorPane.bottomAnchor="163.0" />
<TextField fx:id="input" layoutX="155.0" layoutY="465.0" prefHeight="25.0" prefWidth="667.0" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="send" layoutX="849.0" layoutY="465.0" mnemonicParsing="false" text="发送" AnchorPane.bottomAnchor="159.0" />
<Button fx:id="close_server" layoutX="457.0" layoutY="91.0" mnemonicParsing="false" text="关闭服务" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
</AnchorPane>