注意:该SDK是本人为北京思源科安信息技术有限公司虹膜识别设备KAIris100开发的基于Apache mina框架的Socket通信协议编解码器,虽非官方产品,却填补官方空白。
同系列文章:
依赖关系:
- MinaKAIrisCodec.jar
- mina-core-2.0.9.jar
- slf4j-api-1.7.13.jar
- slf4j-simple-1.7.13.jar
编解码器源代码出售:
价格:壹仟元人民币
微信号:splashcn
SDK及测试程序下载:
MinaKAIrisClientDemo-Java-20160104.zip
注意:演示程序由于使用了JavaFX技术,需要JDK8运行环境
源代码
消息对象:KAIrisMessage.java
/* ---------------------------------------------------------- * 文件名称:KAIrisMessage.java * * 作者:秦建辉 * * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * NetBeans 8.1 * JDK 8u66 * * 版本历史: * V1.0 2015年12月28日 * 思源科安 KAIris100 Socket 通信消息对象 ------------------------------------------------------------ */ package Com.FirstSolver.KAIris; import java.io.Serializable; public class KAIrisMessage implements Serializable { // 包头 private final String mHeader; // 包体,包体可以为null private final String mBody; // 构造函数 public KAIrisMessage(String header, String body) { mHeader = header; mBody = body; } // 获取包头 public String getHeader() { return mHeader; } // 获取包体 public String getBody() { return mBody; } // 获取版本 public String getVersion() { return mHeader.substring(0,2).trim(); } // 获取命令 public String getCommand() { return mHeader.substring(12,16).trim(); } // 获取多包标识 public String getFlowMark() { return mHeader.substring(16,17).trim(); } // 获取错误代码 public String getErrorCode() { return mHeader.substring(17,21).trim(); } }
客户端消息处理器:FXMLDocumentController.java
/* ---------------------------------------------------------- * 文件名称:FXMLDocumentController.java * * 作者:秦建辉 * * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * NetBeans 8.1 * JDK 8u66 * * 版本历史: * V1.0 2015年12月28日 * 思源科安 KAIris100 Socket 通信客户端消息处理器 ------------------------------------------------------------ */ package Splash; import Com.FirstSolver.KAIris.KAIrisMessage; import Com.FirstSolver.KAIris.KAIrisProtocolCodecFactory; import java.net.InetSocketAddress; import java.net.URL; import java.util.ResourceBundle; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.service.IoConnector; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.nio.NioSocketConnector; public class FXMLDocumentController extends IoHandlerAdapter implements Initializable { // 线程池 public ExecutorService mPool; private FXMLDocumentController mController; @FXML private TextField textFieldServerIP; @FXML private TextField textFieldServerPort; @FXML private TextField textFieldQueryCommand; @FXML private TextArea textAreaRecords; @FXML private void handleButtonExecuteCommand(ActionEvent event) throws Exception { // 加入线程池队列 mPool.execute(new PoolHandler(textFieldServerIP.getText(), Integer.parseInt(textFieldServerPort.getText()), textFieldQueryCommand.getText())); } @FXML private void handleButtonClearAction(ActionEvent event) { textAreaRecords.clear(); } // 接收消息处理器,其中message为KAIrisMessage对象实例 @Override public void messageReceived(IoSession session, Object message) throws Exception { if (message instanceof KAIrisMessage) { // 处理消息 KAIrisMessage Source = (KAIrisMessage)message; // 显示包头 textAreaRecords.appendText("包头:\r\n"); textAreaRecords.appendText(Source.getHeader() + "\r\n"); // 显示包体 textAreaRecords.appendText("包体:\r\n"); textAreaRecords.appendText(Source.getBody() + "\r\n"); } // 采用短连接,消息处理完后就断开连接 session.close(true); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { textAreaRecords.appendText("异常:\r\n"); textAreaRecords.appendText(cause.getMessage() + "\r\n"); session.close(true); } @Override public void initialize(URL url, ResourceBundle rb) { mController = this; // 创建一个单一线程的线程池 mPool = Executors.newSingleThreadExecutor(); } private class PoolHandler implements Runnable { private final String mHost; private final int mPort; private final String mCommand; public PoolHandler(String host, int port, String command) { mHost = host; mPort = port; mCommand = command; } @Override public void run() { IoConnector TcpClient = new NioSocketConnector(); TcpClient.getFilterChain().addLast("codec", new ProtocolCodecFilter(new KAIrisProtocolCodecFactory())); TcpClient.setHandler(mController); ConnectFuture ConnFuture = TcpClient.connect(new InetSocketAddress(mHost, mPort)); try { ConnFuture.await(30 * 1000); ConnFuture.getSession().write(mCommand); ConnFuture.getSession().getCloseFuture().await(60 * 1000); } catch (InterruptedException ex) { Alert alert = new Alert(Alert.AlertType.WARNING, ex.getMessage(), ButtonType.OK); alert.setTitle("MinaKAIrisClientDemo"); alert.setHeaderText("错误"); alert.showAndWait(); } TcpClient.dispose(true); } } }
客户端UI:FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.text.*?> <?import javafx.scene.effect.*?> <?import javafx.geometry.*?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" minWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Splash.FXMLDocumentController"> <children> <GridPane minWidth="600.0"> <columnConstraints> <ColumnConstraints /> </columnConstraints> <rowConstraints> <RowConstraints /> <RowConstraints /> <RowConstraints /> <RowConstraints /> </rowConstraints> <children> <GridPane GridPane.hgrow="ALWAYS" GridPane.rowIndex="0"> <columnConstraints> <ColumnConstraints /> <ColumnConstraints hgrow="ALWAYS" /> </columnConstraints> <rowConstraints> <RowConstraints /> <RowConstraints /> </rowConstraints> <children> <Label text="设备地址" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="0"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <Label text="设备端口" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <TextField fx:id="textFieldServerIP" text="192.168.135.246" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="0" GridPane.vgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextField> <TextField fx:id="textFieldServerPort" text="15001" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextField> </children> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </GridPane> <GridPane GridPane.hgrow="ALWAYS" GridPane.rowIndex="1"> <columnConstraints> <ColumnConstraints hgrow="ALWAYS" /> </columnConstraints> <rowConstraints> <RowConstraints /> <RowConstraints /> </rowConstraints> <children> <Label text="查询命令:" GridPane.rowIndex="0"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <TextField fx:id="textFieldQueryCommand" text="11 21100000000" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextField> </children> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </GridPane> <GridPane GridPane.rowIndex="2"> <columnConstraints> <ColumnConstraints /> <ColumnConstraints /> </columnConstraints> <rowConstraints> <RowConstraints /> </rowConstraints> <children> <Button fx:id="buttonClear" minHeight="40.0" minWidth="80.0" onAction="#handleButtonClearAction" text="清空" GridPane.columnIndex="0" GridPane.hgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Button> <Button fx:id="buttonExecuteCommand" minHeight="40.0" minWidth="80.0" onAction="#handleButtonExecuteCommand" text="执行命令" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.hgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Button> </children> </GridPane> <TextArea fx:id="textAreaRecords" editable="false" minHeight="400.0" minWidth="600.0" wrapText="true" GridPane.hgrow="ALWAYS" GridPane.rowIndex="3" GridPane.vgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextArea> </children> </GridPane> </children> </AnchorPane>