依赖
用的是netty实现的,通过上位机开放出来的ip和端口采集欧姆龙PLC的数据,该案例只包括连接PLC加握手:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.20.Final</version>
</dependency>
FinsTCP协议配置FinsClientConfig
import com.global.common.hex.HexStringUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* Fins协议配置
*
* @author Administrator
* @since 1.0.0
*/
public class FinsClientConfig {
public static ChannelFuture channelFuture;
public static void finsStart(String ip, int port) throws Exception {
NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//创建bootstrap对象,配置参数
Bootstrap bootstrap = new Bootstrap();
//设置线程组
bootstrap.group(eventExecutors)
//设置客户端的通道实现类型
.channel(NioSocketChannel.class)
//使用匿名内部类初始化通道
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//添加客户端通道的处理器
ch.pipeline().addLast(new MyClientHandler());
}
});
System.out.println("客户端准备就绪,随时可以起飞~");
//连接服务端
channelFuture = bootstrap.connect(ip, port).sync();
//对通道关闭进行监听
channelFuture.channel().closeFuture().sync();
} finally {
//关闭线程组
eventExecutors.shutdownGracefully();
}
}
/**
* 发送数据
*
* @param msg 数据
*/
public static void send(String msg) {
channelFuture.channel().writeAndFlush(Unpooled.wrappedBuffer(HexStringUtil.hexToByteArray(msg)));
}
}
Handler类MyClientHandler
import cn.hutool.core.util.HexUtil;
import com.global.common.hex.HexStringUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
* 业务处理
*
* @author Administrator
* @since 1.0.0
*/
public class MyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 握手
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//握手
ctx.writeAndFlush(Unpooled.wrappedBuffer(HexStringUtil.hexToByteArray("46494E530000000C00000000000000000000000D")));
}
/**
* 消息处理
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收服务端发送过来的消息
ByteBuf byteBuf = (ByteBuf) msg;
byte[] bytes = ByteBufUtil.getBytes(byteBuf);
System.err.println(HexUtil.encodeHexStr(bytes));
}
}
下面这个方法可以自己去写一个,比如hutool的HexUtil工具类里就有我这边自己写
/**
* 16进制字符串转化为byte数组
*
* @param inHex 要转16进制字节流数组的16进制字符
* @return 16进制字节流
*/
public static byte[] hexToByteArray(String inHex) {
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1) {
// 奇数
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
// 偶数
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = hexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}
private static byte hexToByte(String inHex) {
return (byte) Integer.parseInt(inHex, 16);
}
总结:
FinsTCP协议走的还是网络通讯,那还是TCP/IP通讯,只是第一次发送必须是握手报文,然后发送读取数据报文
Java的网络通讯框架我这边比较常用的就是 t-io 以及netty
案例源码:
指令的说明介绍请看这个大佬的: