V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
haosamax
V2EX  ›  Java

[Socket 小白求助]socket read 服务器返回 unknown length

  •  
  •   haosamax · 2021-02-01 09:48:59 +08:00 · 1406 次点击
    这是一个创建于 1151 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以前基本不写 Socket,都是调包侠。现在这个项目 socket 通讯,约定前六位是后面数据包长度(不够左补 0),后面是数据包,像这样:000length|xxxxxxxxxxxxxxxxxxxxx,求教,socket.read 怎么读,我是先读 6 位,算出 length,再读 length 吗?

    14 条回复    2021-02-01 14:50:49 +08:00
    Edsie
        1
    Edsie  
       2021-02-01 09:55:41 +08:00
    char[6]读取前 6 个,解析出 length,再读后面的
    haosamax
        2
    haosamax  
    OP
       2021-02-01 09:59:44 +08:00
    @Edsie send 的时候要发送两次吗,第一次发送,读 length,第二次发送读后面的
    ScepterZ
        3
    ScepterZ  
       2021-02-01 10:04:45 +08:00
    @haosamax 发送随便怎么发都行,反正是流
    haosamax
        4
    haosamax  
    OP
       2021-02-01 10:11:38 +08:00
    @ScepterZ 这个后面 xxx 部分是 json 字符串比较烦,其他的都是传的 k-v,我们约定只对 v 编码传输,指定长度、填充字符、填充位置,这样我可以 read(b),b 可以指定已知长度根据接口文档。像这种不知道长度的比如 json,或者 xxx 含有循环体,我看别人写的都是创建两个 socket,发送两次,第一次获取 length,第二次获取读后面的,两次建立连接,这不影响性能吗
    LGA1150
        5
    LGA1150  
       2021-02-01 10:35:17 +08:00 via Android
    @Edsie 一个 char 占两字节
    Kamiyu0087
        6
    Kamiyu0087  
       2021-02-01 10:42:46 +08:00
    先问问前六位表示数据包长度指的是 6 个 bit 还是 6 个 byte?
    如果是 byte,很好奇要传啥数据需要定那么大的长度?
    如果是 bit,那第一个字节的最后两个 bit 是空置还是直接跟上后续数据包的数据?
    zlwen
        7
    zlwen  
       2021-02-01 10:46:00 +08:00
    用 netty
    haosamax
        8
    haosamax  
    OP
       2021-02-01 10:51:33 +08:00
    @Kamiyu0087 6byte 。十进制的,最多 byte[999999],还行吧
    @zlwen 计划下个版本就接入 netty
    haosamax
        9
    haosamax  
    OP
       2021-02-01 10:52:45 +08:00
    @haosamax 这个半吊子自定义协议,循环体处理就这
    Kamiyu0087
        10
    Kamiyu0087  
       2021-02-01 11:00:01 +08:00
    @haosamax 那 3 个字节就够了啊,为啥要 6 个字节
    不会是每个字节就 0 ~ 9,然后转字符串拼接吧? - -!
    haosamax
        11
    haosamax  
    OP
       2021-02-01 11:03:14 +08:00
    @Kamiyu0087 sry,我搞错了,是 6 个字节,不是 999999...。为什么这么大,我也不知道,平台约定的
    haosamax
        12
    haosamax  
    OP
       2021-02-01 11:19:45 +08:00
    @Kamiyu0087 还是指定长度 6 位的字符串拉😂
    LGA1150
        13
    LGA1150  
       2021-02-01 12:49:53 +08:00
    #11 #12 长度到底是 ASCII 还是二进制?
    如果是 ASCII,读到 byte[]里,转 String 再转 int
    byte[] buf = new byte[6];
    inputStream.read(buf);
    int length = Integer.parseInt(new String(buf));
    如果是二进制,读到 byte[]里,转 BigInteger 再转 long
    byte[] buf = new byte[7]; // 多分配一个字节保证转换为正数
    inputStream.read(buf, 1, 6);
    long length = new BigInteger(buf).longValue();
    Edsie
        14
    Edsie  
       2021-02-01 14:50:49 +08:00
    盲猜是六个字符,最好确认一下

    send 的时候也不需要发两次,基于流的 IO 没道理发两次。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2702 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:34 · PVG 23:34 · LAX 08:34 · JFK 11:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.