mina请求第三方服务无响应问题解决

本文介绍在使用Mina框架进行TCP通信时遇到的粘包问题及解决方法。通过对编码器和解码器的LineDelimiter进行调整,解决了与第三方服务数据交互中的粘包问题,确保了数据的正确接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在项目中需要与第三方服务对接,通过tcp协议发送和接收数据。因为觉得Apache的开源框架mina比较方便,所以在项目中直接使用了。主要的业务逻辑是先建立连接,然后在连接上进行数据的交互,等整个业务流程结束,主动断开连接。但是在实际对接第三方服务时,发现虽然可以成功和服务器建立连接,但是mina发送请求参数后,服务器返回的数据mina一直接收不到,而且也和对方技术确认过,数据确实已经返回了。在尝试修改编码格式(utf8、gbk等)和使用不同的ProtocolCodecFilter之后,发现并不是这些原因导致。

那么为什么mina接收不到第三方服务器返回的数据呢,后来百度了很多关于tcp相关的基本资料,因为本人对tcp相关的知识掌握不多。在查询资料时了解到,tcp交互中有可能出现丢包、粘包等情况,详细内容可以自行百度。问题就出在这个粘包的处理上。mina封装的方法有对粘包问题的处理。默认TextLineCodecFactory这个工厂在发送和接收请求时,构造方法中会实例化两个对象,一个是TextLineEncoder编码器,另一个是TextLineDecoder解码器,分别负责发送数据和接收数据的编码解码。默认的构造器为:

/**
     * Creates a new instance with the specified {@link Charset}.  The
     * encoder uses a UNIX {@link LineDelimiter} and the decoder uses
     * the AUTO {@link LineDelimiter}.
     *
     * @param charset
     *  The charset to use in the encoding and decoding
     */
    public TextLineCodecFactory(Charset charset) {
        encoder = new TextLineEncoder(charset, LineDelimiter.UNIX);
        decoder = new TextLineDecoder(charset, LineDelimiter.AUTO);
    }

我们可以看到编码器和解码器中都有LineDelimiter,意思是分隔符。这两个作为分隔符的常量分别是:

/**
     * The line delimiter constant of UNIX (<tt>"\n"</tt>)
     */
    public static final LineDelimiter UNIX = new LineDelimiter("\n");
/**
     * A special line delimiter which is used for auto-detection of
     * EOL in {@link TextLineDecoder}.  If this delimiter is used,
     * {@link TextLineDecoder} will consider both  <tt>'\r'</tt> and
     * <tt>'\n'</tt> as a delimiter.
     */
    public static final LineDelimiter AUTO = new LineDelimiter("");

所以这里编码器在每一行的最后加上“\n”字符,标记行的结尾。解码器使用的标记我们可以看注释,它可以对应“\r”和“\n”,这样在解析的时候就可以区分一次数据交互的末尾,解决粘包的问题;

和我对接的第三方服务是用c++语言编写的,他们在接收和发送tcp数据时,也使用了这种方法,只不过他们定义的数据结尾是“****”,所以只要调用TextLineCodecFactory的(Charset charset, String encodingDelimiter, String decodingDelimiter)这个构造函数,将对方指定的“****”当作decodingDelimiter,就可以接收数据了,主要代码如下:

           //创建客户端连接
            NioSocketConnector connector = new NioSocketConnector();
            connector.getSessionConfig().setReceiveBufferSize(10240);   // 设置接收缓冲区的大小
            connector.getSessionConfig().setSendBufferSize(10240);// 设置输出缓冲区的大小
            //创建接收数据的过滤器
            DefaultIoFilterChainBuilder chain = connector.getFilterChain();
            //设置此过滤器为一行一行的读取数据
            // 创建接受数据的过滤器
            //此处的解码分隔符使用“****”是为了和服务器通信时知晓接收到的数据的终点,来让解码器解析
            TextLineCodecFactory textLineCodecFactory = new TextLineCodecFactory(Charset.forName("GBK"),LineDelimiter.UNIX.getValue(),"****");
            textLineCodecFactory.setDecoderMaxLineLength(10240);//设置行解码器长度
            textLineCodecFactory.setEncoderMaxLineLength(10240);
            // 设定这个过滤器将一行一行的读取数据
            connector.getFilterChain().addLast("codec1", new ProtocolCodecFilter(textLineCodecFactory));

这样,我们就可以使用mina接收第三方服务返回的数据了,另外需要注意对方的数据编码格式,我这边需要使用“GBK”才能成功接收数据,否则在解析中文字符时会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值