问几个有关 NIO 的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Joker123456789
V2EX    Java

问几个有关 NIO 的问题

  •  
  •   Joker123456789 2021-04-25 14:23:29 +08:00 4404 次点击
    这是一个创建于 1631 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本人对 NIO 的理解程度有限,网上的资料又不够详细,很多东西都搜不到,所以在此问问各位大神,如果兴趣的话还望指教。 谢谢啦。

    客户端发起一个 http 请求到服务端

    1. 此时 selector 会把 read 状态的 channel 给获取到 并进入迭代, 这个 channel 里包含本次请求的所有报文吗? 注意是本次请求。

    2. 会不会因为网络原因或者其他常见原因 导致数据有断层,比如客户端发送了 1234,但是channel 里是 12 34.从而导致读 channel 的时候在断层处 返回 0,而导致读取停止?

    分片传输

    假如有这样一个 http 报文

    POST /demo HTTP/1.1 content-type:application/json content-length:1000 12345678910qwertyuioasdfghjkl 

    我以分两片为例子。

    分片传输是将报文分为这样的两份( A )?

    第一片 POST /demo HTTP/1.1 content-type:application/json content-length:50 12345678910qwer 第二片 POST /demo HTTP/1.1 content-type:application/json content-length:50 tyuioasdfghjkl 

    还是这样的两份( B )?

    第一片 POST /demo HTTP/1.1 content-type:application/json content-length:100 12345678910 第二片 qwertyuioasdfghjkl 

    如果是 B 的分法,那么 NIO 在收到第二片之后,丢给协议层,这个数据里没有任何特征,协议层是怎么判断出这个报文属于什么协议,从而给对应的协议解析器来进行解析的呢?

    NIO 有没有什么高效的办法来 判断本次请求的协议类型,除了分析报文里的特征

    我现在是根据报文里的特征来分析的,感觉不太对劲。

    24 条回复    2021-04-27 09:35:05 +08:00
    BBCCBB
        1
    BBCCBB  
       2021-04-25 14:36:26 +08:00
    1. 不一定包含, 大概率都是只有一部分, 有数据就会通知你. 你需要读出来自己缓存起来. 可以看看 Netty 的 ByteToMessageDecoder.

    2. 数据包中间穿插了其他的包.. 这个只要在发送的时候中间没穿插其他的包的写入, 一般是不会发生的. 要是会出现这种情况, 那互联网就没法玩了..
    BBCCBB
        2
    BBCCBB  
       2021-04-25 14:38:38 +08:00
    收到的报文是 B 这种.. 你一个完整的包没解析出来的时候, 需要缓存已经读出的数据. 后续的包来的时候, 你需要根据前面缓存的数据来判断属于什么协议..

    还是建议看 Netty. ByteToMessageDecoder 和他的 Codec 那一套东西.
    Ariver
        3
    Ariver  
       2021-04-25 14:39:04 +08:00
    取决于你在哪个层次上写代码。
    以下回答认为你是基于 Netty 来实现你的业务逻辑。
    1.使用 Netty 提供的 handler 你不需要考虑这个问题,可以认为自己拿到了完整的请求。
    2.有可能会发生,那么异常会在你处理这个请求之前就出现,可以认为你的业务代码没有处理。
    收到了一部分。
    分片
    第二种
    确认你工作在哪个 level 非常重要。如果你在写网卡驱动,那么你需要确保数据包的收发,如果你在写一个 http server,那么你收到的当然是 http 的请求。监听的端口收到的请求不对是没有办法正确处理的。比如你发一个请求到 22 端口一般来说是收不到返回的。对吧,除非有人部署了一个 http server 在 22 端口。
    ----
    hmmm
    所以你要实现的类似于 80 端口有一个 web server 同时想要 ssh ?
    Jirajine
        4
    Jirajine  
       2021-04-25 14:39:50 +08:00
    不了解 NIO,但是
    >怎么判断出这个报文属于什么协议
    这个需求看起来很奇怪,你要实现 socket mux 么? NIO 是个 IO/网络库吧,正常来说不需要判断啊,数据直接给上层,上层按照自己的协议解析。

    如果确实要实现 socket mux,那么应该进行 连接追踪,即请求第一次到达并 dispatch 到相应的后端后记录来源 socket,后续来自相同 socket 的数据 dispatch 到相同的后端。
    BBCCBB
        5
    BBCCBB  
       2021-04-25 14:40:04 +08:00
    说错了, 没主要看你这个分片传输的含义, 失误

    分片传输这个看请求了几次... 单次就是 B, 多次的话就类似 A..
    BBCCBB
        6
    BBCCBB  
       2021-04-25 14:40:57 +08:00
    你这分片是说一个文件分多个 chunk 上传的意思?
    GuuJiang
        7
    GuuJiang  
       2021-04-25 14:43:53 +08:00
    恭喜你终于开始有点要逐步转到正确方向的迹象了,我来依次回答下你的每个问题,希望你哪天能正确认识到你在原来那个帖子里犯的错误是多么的基础和低级,并且向所有指出你问题的人一一道个歉
    1. 不保证
    2. 会
    随时记住一点:TCP 是流式协议

    关于分片的问题,任何分法都是有可能的,随时记住一点:TCP 是流式协议、TCP 是流式协议、TCP 是流式协议,对上层协议一无所知

    关于协议解析的问题,在你选择了监听某个端口之前,这个端口期望收到的协议是已经提前确定了的,换句话说你需要自己负责按照预先的期望去解析协议,并不存在你想象中的“根据收到的内容自动判断协议”这种东西
    leopod1995
        8
    leopod1995  
       2021-04-25 14:46:44 +08:00
    tcp 分包传输 每个包都是带协议头的 协议层会根据包头来进行数据重组
    cheng6563
        9
    cheng6563  
       2021-04-25 14:46:54 +08:00
    某些多协议同端口的服务,就是报文里的特征来猜的,没其他办法。
    GuuJiang
        10
    GuuJiang  
       2021-04-25 14:54:25 +08:00
    我补充一下,确实存在同一个端口同时支持多种协议的情况,但这个和提问者想象的那个不是一回事,可以认为这个分发工作仍然是处在协议处理层,相当于一个复合的协议,具体实现时类似状态机,总之只需要记住一点,IO 部分是不关心上层协议的
    ZhaoHuiLiu
        11
    ZhaoHuiLiu  
       2021-04-25 15:27:21 +08:00
    HTTP 是无状态请求的,你两次请求,可能不在一个服务器,你得有一台共用的文件服务器。

    分片请求,你得写入一些信息,比如请求的是二进制文件。
    你得给这个文件写入一个头部信息,这个头部信息包含:文件名、用户名、文件总大小、已写入大小,请求次数等等固定大小头部信息。

    用 fs 打开文件,读取头信息,再写入数据,再更新头信息。
    borisz
        12
    borisz  
       2021-04-25 15:28:42 +08:00
    多协议同端口,一般会使用一个魔数来区分协议的具体版本.

    read 如果是标准实现的话, 0 表示正确结束, -1 表示读取到一半出现错误.
    ZhaoHuiLiu
        13
    ZhaoHuiLiu  
       2021-04-25 15:28:57 +08:00
    HTTP 多次请求,你要完成数据合并,你得写入一个文件,并且这个文件要记录一些头部信息,当请求完成了,你再读取这个文件进行操作。
    Joker123456789
        14
    Joker123456789  
    OP
       2021-04-25 15:35:05 +08:00
    @BBCCBB
    @GuuJiang

    好的,非常感谢。 看了你们的回答,让我茅塞顿开。
    anexplore
        15
    anexplore  
       2021-04-25 15:38:51 +08:00   1
    1 、并不是;你可能需要接收 N 个 read 事件才能把一个请求的数据都读取完毕
    2 、客户端发送的什么你收到的就是什么,不会凭空添加未知数据;
    还是用 netty 吧
    dqzcwxb
        16
    dqzcwxb  
       2021-04-25 17:40:00 +08:00
    越看越像是粘包这个老生常谈的引战问题
    pabupa
        17
    pabupa  
       2021-04-25 17:45:10 +08:00
    你用了 tcp,就不要考虑这些问题。请您相信它,好吗?
    monkeyWie
        18
    monkeyWie  
       2021-04-25 17:58:16 +08:00
    建议手写一个 http paser,这样你应该就懂了
    queuey
        19
    queuey  
       2021-04-25 18:00:57 +08:00   4
    看到 NIO,我以为是蔚来
    mauve
        20
    mauve  
    PRO
       2021-04-25 18:32:41 +08:00
    @queuey 我也
    cqsc
        21
    cqsc  
       2021-04-25 21:30:18 +08:00
    TCP 协议是面向字节流的 同时为了提高效率可能会将多个数据包合并一起发送 或者在接收时多个数据包被拆分成若干小包 这个就需要你自己的在设计应用层协议的时候考虑到如何处理了 确保能够读取到完整的应用层报文
    kongch
        22
    kongch  
       2021-04-26 10:18:24 +08:00
    先从概念看:tcp 是流,属于传输层; http 是应用层,所以答案肯定是 B 。
    再用反证法:如果用 A 的模式,你看看你猜测的两个包传输了多少重复内容,计算机先驱们不会有这么低级的错误。
    再通过实践:用 wireshark 抓个包就能知道肯定不会是 A 了。
    4kingRAS
        23
    4kingRAS  
       2021-04-26 17:30:56 +08:00
    协议层不会分“包”的,netty 会设置 delimiter,比如\r\n 。 每次你发的“包”会按照\r\n 来分,所以即使这个请求没有一起到达也没事。
    Chinsung
        24
    Chinsung  
       2021-04-27 09:35:05 +08:00
    Netty 中有一个 Http 消息聚合 handler,HttpObjectAggregator,作用就是将过长的 post 请求在多包多次到达的情况将一个长 http 请求聚合成一个完整的请求。
    不只是 NIO,其实你这种场景在 BIO 也会出现,本质上是协议解析的问题,网络在发送请求的时候,对于客户端读取方,不论是 BIO 还是 NIO,在 read 的时候都会出现单次 read 只 read 到了一部分报文。
    C 里面这种写法会更多,大部分协议或者自定义协议,都一定要有报文头标识和报文结束标识,一般是找几个字节的不可见字符这种,然后自己搞个缓冲区,取出一段一段报文去处理。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5756 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 01:47 PVG 09:47 LAX 18:47 JFK 21:47
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86