代理服务器开发之java nio串包

TCP串包

前言

最近在开发http代理服务器,部署到环境上。发现丢包很严重,偶尔能够github但是访问炒鸡慢,后来发现是被长城拦截了。用sockes5,则百度访问超时,谷歌正常。可我就想用http代理搞一个。于是写了一个客户端和服务端。
客户端包括:http隧道代理服务器+websocket客户端
服务端包括:websocket服务端+http隧道客户端。以及另外一个http隧道服务端。
在开发过程中,websocket在65535以内的数据报文中表现不错,性能比node.js写的快了很多倍。但是超过65535后(访问流),经常出现fin和rsv不一致问题。

排查

websocket支持流传输,遇到了一个问题,包发着发着就解析错误了。要么fin不为1,要么rsv不为0。要么就特别长。

在这里插入图片描述

在这里插入图片描述

刚开始以为是client解析错误,然后debug,发现第一个错误的包和client抓包的字节对应的上。那么这就排除了客户端的问题。

在这里插入图片描述

在这里插入图片描述

那么现在就开始抓服务端的包,既然是fin和rsv的问题,那就在发送报文的时候打印即可。在这里打印的时候发现报文没问题。

在这里插入图片描述

然后想着那就抓完整的报文,就添加了如下配置。

<!-- INFO级别日志 -->
<RollingFile name="info_appender" immediateFlush="true"
             fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/info/info - %d{yyyy-MM-dd HH_mm_ss}-%i.log">
             <!--fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/info/info - %d{yyyy-MM-dd HH_mm_ss}.log.gz">-->
    <PatternLayout>
        <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
    </PatternLayout>
    <Policies><!-- 每个日志文件最大2MB ; -->
        <SizeBasedTriggeringPolicy size="10MB" />

        <!-- 如果启用此配置,则日志会按文件名生成新压缩文件, 即如果filePattern配置的日期格式为 %d{yyyy-MM-dd HH}
            ,则每小时生成一个压缩文件, 如果filePattern配置的日期格式为 %d{yyyy-MM-dd} ,则天生成一个压缩文件 -->
        <TimeBasedTriggeringPolicy interval="1"
                                   modulate="true" />

    </Policies>
    <Filters>
        <ThresholdFilter level="warn" onMatch="DENY"
                         onMismatch="NEUTRAL" />
        <ThresholdFilter level="info" onMatch="ACCEPT"
                         onMismatch="DENY" />
    </Filters>
</RollingFile>

根据抓包的最后一个成功的包的二进制数据在日志里面查询,发现有匹配。然后重复多个成功的报文也有匹配,抓失败的也有匹配。

在这里插入图片描述

在这里插入图片描述

结果发现都有一个共同点,报文都在协议报文中间,而不是在末尾。怀疑串包了。

然后发现有一个zerowindow错误,就是说缓冲区打满了。然后查看seqid和ack发现也的确如此。

原因

当同时有多个线程往缓冲区刷数据的时候,数据量小的话,还好。不会出现缓冲区打满。当前项目低于65535传输量的网页,是能够正常打开的。查看流传输的时候数据量大量膨胀,导致写缓冲区打满了。然后这个时候A线程写数据,会抢占一个文件锁,写数据。倘若缓冲区打满了,则切换上下文,释放锁。这个时候B线程来刷数据了,抢占写锁了,刚好写缓冲区缓存释放了,就会出现串包现象。

解决办法:

websocket终端有2个地方刷数据

  • http隧道代理客户端

    • 在这里插入图片描述
  • 另外一个是websocket服务端,会在接收到websocket客户端心跳数据以及客户端http隧道代理关闭事件。

    • 在这里插入图片描述

      • 在这里插入图片描述
    • 以及心跳数据在这里插入图片描述

这里将写buff丢到阻塞队列里面,然后异步线程循环读取数据进行写入。

如果刷入数据失败,则说明缓冲打满,则注册写事件,并阻塞。等待写事件到达唤醒,然后接着写入。

在这里插入图片描述
数据写入完毕,则删除该buffer。当阻塞队列为空,则删除写事件。

最终显示

速度相比较node.js写的socks5代理提升了几倍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值