java netty 服务端向客户端发送16进制数据,客户端无法接收-已解决

2 篇文章 0 订阅
2 篇文章 0 订阅

项目中需要通过netty与C语言建立连接,双方是通过16进制进行数据传输

 

本案例主要介绍如何在JavaNetty与C Sokcet进行字符串通信,Java服务端,C客户端。

重点提示:网络通信中都是byte字节,两边通信一定要统一编码,尽量避免乱码与接收不到的问题。

1.设置ChildChannelInitializer.java中initChannel(SocketChannel ch)

 

public class ChildChannelInitializer extends ChannelInitializer<SocketChannel> {
	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		System.out.println("==================netty报告==================");
		System.out.println("信息:有一客户端链接到本服务端");
		System.out.println("IP:" + ch.localAddress().getHostName());
		System.out.println("Port:" + ch.localAddress().getPort());
		System.out.println("==================netty报告完毕==================");
		
		ChannelPipeline  pipeline  =  ch.pipeline();
		// 在管道中添加我们自己的接收数据实现方法
		/*pipeline.addLast(new MsgEncoder());
		pipeline.addLast(new MsgDecoder());*/
		//注意 我这里并没有设置管道的编码/解码
		
		pipeline.addLast("handler", serverHandler);
	}
	...
}

 

 

 

 

 

2.在ServerHandler.java中接收C语言客户端发来的16进制字符串

 

public class ServerHandler extends ChannelHandlerAdapter{

	public void channelRead(ChannelHandlerContext channel, Object msg) throws Exception {
		try {
			ByteBuf buf = (ByteBuf)msg;
			byte [] bytes = new byte[buf.readableBytes()];
			buf.readBytes(bytes);//复制内容到字节数组bytes 
			String receiveStr = ConvertCode.receiveHexToString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
			//返回16进制到客户端
			writeToClient(receiveStr,channel,"测试");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			log.error("异常:",e);
		}
	}
	/**
	 * 公用回写数据到客户端的方法
	 * @param 需要回写的字符串
	 * @param channel
	 * @param mark 用于打印/log的输出
	 * <br>//channel.writeAndFlush(msg);//不行
	 * <br>//channel.writeAndFlush(receiveStr.getBytes());//不行
	 * <br>在netty里,进出的都是ByteBuf,楼主应确定服务端是否有对应的编码器,将字符串转化为ByteBuf
	 */
	private void writeToClient(final String receiveStr, ChannelHandlerContext channel, final String mark) {
		try {
			ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
			bufff.writeBytes(ConvertCode.hexString2Bytes(receiveStr));//对接需要16进制
			channel.writeAndFlush(bufff).addListener(new ChannelFutureListener() {
			    @Override
			    public void operationComplete(ChannelFuture future) throws Exception {
			    	StringBuilder sb = new StringBuilder("");
			    	if(!StringUtils.isEmpty(mark)){
			    		sb.append("【").append(mark).append("】");
			    	}
			        if (future.isSuccess()) {
			            	System.out.println(sb.toString()+"回写成功"+receiveStr);
			            	log.info(sb.toString()+"回写成功"+receiveStr);
			        } else {
			        	System.out.println(sb.toString()+"回写失败"+receiveStr);
			        	log.error(sb.toString()+"回写失败"+receiveStr);
			        }
			    }
			});
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("调用通用writeToClient()异常"+e.getMessage());
			log.error("调用通用writeToClient()异常:",e);
		}
	}
	
	...
}	


3.编写ConvertCode.java:在第2里面用到了ConvertCode.receiveHexToString(bytes)和ConvertCode.hexString2Bytes(receiveStr)

 

 

package com.vk.updoc.netty2;

public class ConvertCode {
	 /** 
     * @Title:bytes2HexString 
     * @Description:字节数组转16进制字符串 
     * @param b 
     *            字节数组 
     * @return 16进制字符串 
     * @throws 
     */  
    public static String bytes2HexString(byte[] b) {  
        StringBuffer result = new StringBuffer();  
        String hex;  
        for (int i = 0; i < b.length; i++) {  
            hex = Integer.toHexString(b[i] & 0xFF);  
            if (hex.length() == 1) {  
                hex = '0' + hex;  
            }  
            result.append(hex.toUpperCase());  
        }  
        return result.toString();  
    }  
    /** 
     * @Title:hexString2Bytes 
     * @Description:16进制字符串转字节数组 
     * @param src  16进制字符串 
     * @return 字节数组 
     */  
    public static byte[] hexString2Bytes(String src) {  
        int l = src.length() / 2;  
        byte[] ret = new byte[l];  
        for (int i = 0; i < l; i++) {  
            ret[i] = (byte) Integer  
                    .valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();  
        }  
        return ret;  
    }
    /** 
     * @Title:string2HexString 
     * @Description:字符串转16进制字符串 
     * @param strPart  字符串 
     * @return 16进制字符串 
     */  
    public static String string2HexString(String strPart) {  
        StringBuffer hexString = new StringBuffer();  
        for (int i = 0; i < strPart.length(); i++) {  
            int ch = (int) strPart.charAt(i);  
            String strHex = Integer.toHexString(ch);  
            hexString.append(strHex);  
        }  
        return hexString.toString();  
    }  
    /** 
     * @Title:hexString2String 
     * @Description:16进制字符串转字符串 
     * @param src 
     *            16进制字符串 
     * @return 字节数组 
     * @throws 
     */  
    public static String hexString2String(String src) {  
        String temp = "";  
        for (int i = 0; i < src.length() / 2; i++) {
        	//System.out.println(Integer.valueOf(src.substring(i * 2, i * 2 + 2),16).byteValue());
            temp = temp+ (char)Integer.valueOf(src.substring(i * 2, i * 2 + 2),16).byteValue();  
        }  
        return temp;  
    }  
      
    /** 
     * @Title:char2Byte 
     * @Description:字符转成字节数据char-->integer-->byte 
     * @param src 
     * @return 
     * @throws 
     */  
    public static Byte char2Byte(Character src) {  
        return Integer.valueOf((int)src).byteValue();  
    }  
      
        /** 
     * @Title:intToHexString 
     * @Description:10进制数字转成16进制 
     * @param a 转化数据 
     * @param len 占用字节数 
     * @return 
     * @throws 
     */  
    public static String intToHexString(int a,int len){  
        len<<=1;  
        String hexString = Integer.toHexString(a);  
        int b = len -hexString.length();  
        if(b>0){  
            for(int i=0;i<b;i++)  {  
                hexString = "0" + hexString;  
            }  
        }  
        return hexString;  
    }  
      
    
    /**
     * 将16进制的2个字符串进行异或运算
     * http://blog.csdn.net/acrambler/article/details/45743157	
     * @param strHex_X
     * @param strHex_Y
     * 注意:此方法是针对一个十六进制字符串一字节之间的异或运算,如对十五字节的十六进制字符串异或运算:1312f70f900168d900007df57b4884
		先进行拆分:13 12 f7 0f 90 01 68 d9 00 00 7d f5 7b 48 84
		13 xor 12-->1
		1 xor f7-->f6
		f6 xor 0f-->f9
		....
		62 xor 84-->e6
		即,得到的一字节校验码为:e6
     * @return
     */
    public static String xor(String strHex_X,String strHex_Y){   
        //将x、y转成二进制形式   
        String anotherBinary=Integer.toBinaryString(Integer.valueOf(strHex_X,16));   
        String thisBinary=Integer.toBinaryString(Integer.valueOf(strHex_Y,16));   
        String result = "";   
        //判断是否为8位二进制,否则左补零   
        if(anotherBinary.length() != 8){   
        	for (int i = anotherBinary.length(); i <8; i++) {   
                anotherBinary = "0"+anotherBinary;   
            }   
        }   
        if(thisBinary.length() != 8){   
        	for (int i = thisBinary.length(); i <8; i++) {   
                thisBinary = "0"+thisBinary;   
            }   
        }   
        //异或运算   
        for(int i=0;i<anotherBinary.length();i++){   
        	//如果相同位置数相同,则补0,否则补1   
            if(thisBinary.charAt(i)==anotherBinary.charAt(i))   
                result+="0";   
            else{   
                result+="1";
            }   
        }  
        return Integer.toHexString(Integer.parseInt(result, 2));   
    }  
    
    
    /**
     *  Convert byte[] to hex string.这里我们可以将byte转换成int
	 * @param src byte[] data   
	 * @return hex string   
	 */   
    public static String bytes2Str(byte[] src){   
        StringBuilder stringBuilder = new StringBuilder("");   
        if (src == null || src.length <= 0) {   
            return null;   
        }   
        for (int i = 0; i < src.length; i++) {   
            int v = src[i] & 0xFF;   
            String hv = Integer.toHexString(v);   
            if (hv.length() < 2) {   
                stringBuilder.append(0);   
            }   
            stringBuilder.append(hv);   
        }   
        return stringBuilder.toString();   
    }
    /**
 	 * @param msg
 	 * @return 接收字节数据并转为16进制字符串
 	 */
 	public static String receiveHexToString(byte[] by) {
 		try {
 			/*io.netty.buffer.WrappedByteBuf buf = (WrappedByteBuf)msg;
 			ByteBufInputStream is = new ByteBufInputStream(buf);
 			byte[] by = input2byte(is);*/
 			String str = bytes2Str(by);
 			str = str.toLowerCase();
 			return str;
 		} catch (Exception ex) {
 			ex.printStackTrace();
 			System.out.println("接收字节数据并转为16进制字符串异常");
 		}
 		return null;
 	}
 	
 	/**
 	 * "7dd",4,'0'==>"07dd"
 	 * @param input 需要补位的字符串
 	 * @param size 补位后的最终长度
 	 * @param symbol 按symol补充 如'0'
 	 * @return
 	 * N_TimeCheck中用到了
 	 */
 	public static String fill(String input, int size, char symbol) {
		while (input.length() < size) {
			input = symbol + input;
		}
		return input;
	}
    public static void main(String args[]) {  
    	String productNo = "3030303032383838";
    	System.out.println(hexString2String(productNo));
    	productNo = "04050103000001070302050304";
    	System.out.println(hexString2String(productNo));
    }  
    //用Java语言实现对十六进制字符串异或运算http://blog.csdn.net/acrambler/article/details/45743157	
}

 

 

客户端测试工具我使用的:TCPUDP Socket调试工具 V2.3 绿色免费版

 

 

  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
首先,我们需要在Spring Boot项目中引入Netty的依赖: ``` <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.22.Final</version> </dependency> ``` 然后,我们需要编写一个Netty客户端类,用于连接服务器并发送16进制数据: ```java public class NettyClient { private final String host; private final int port; private Channel channel; public NettyClient(String host, int port) { this.host = host; this.port = port; } public void connect() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HexEncoder()); pipeline.addLast(new NettyClientHandler()); } }); ChannelFuture future = bootstrap.connect(host, port).sync(); channel = future.channel(); channel.closeFuture().sync(); } finally { group.shutdownGracefully(); } } public void sendHexData(String hexData) { if (channel == null || !channel.isActive()) { throw new IllegalStateException("Connection is not active"); } channel.writeAndFlush(Unpooled.copiedBuffer(hexData, CharsetUtil.US_ASCII)); } } ``` 在上面的代码中,我们使用了HexEncoder类来将字符串转换为16进制数据,然后将它们发送到服务器。我们还使用了NettyClientHandler类来处理从服务器接收到的响应。 最后,我们可以在Spring Boot应用程序中使用这个Netty客户端类来发送16进制数据: ```java @RestController @RequestMapping("/api") public class NettyController { @GetMapping("/sendHexData") public String sendHexData(@RequestParam String hexData) throws Exception { NettyClient client = new NettyClient("localhost", 8080); client.connect(); client.sendHexData(hexData); return "OK"; } } ``` 在上面的代码中,我们可以使用sendHexData方法来发送16进制数据到服务器。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yqwang_cn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值