博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
详解-斗鱼弹幕API-接入(斗鱼弹幕服务器第三方接入协议)
阅读量:6986 次
发布时间:2019-06-27

本文共 6682 字,大约阅读时间需要 22 分钟。

  hot3.png

本文基于"斗鱼弹幕服务器第三方接入协议V1.6.2"编写

基础准备

接入方式:Socket

API服务地址:openbarrage.douyutv.com:8601

斗鱼私有协议说明

如上图所示,每次发送的消息或者接收到的消息都会由 消息长度 + 消息长度 + 消息类型 + 真实消息内容 + 结尾标识 组成

消息 = 消息长度(4) + 消息长度(4) + 消息类型(4) + 真实消息内容(?) + 结尾标识长度(1)

其中这里要特别说明三个点

一、消息长度的算法,消息长度 = 消息长度(4) + 消息类型(4) + 真实消息内容长度 + 结尾标识长度(1)

二、虽然消息里有 两个消息长度字段,但是如上面的算法所示,计算消息长度是 只需要加 一个 消息长度(4) 字段的长度即可。

三、斗鱼要求的消息长度都为 4 字节小端整数,java中都是大端整数,所以需要通过特别方法转换,我下面都给处理对应的工具代码

int contenLeng = 4 + 4 + content.length() + 1; //消息长度算法

下面开始实际进行接入,先上代码

 

示例代码

public static void main(String[] args) throws IOException, InterruptedException {        Socket socket = new Socket("openbarrage.douyutv.com", 8601);        //发送登录请求(登入9999房间)        String loginCMD = "type@=loginreq/roomid@=9999/";        send(loginCMD, socket);        //读取登录请求消息        byte[] bytes = read(socket);        String msg = new String(Arrays.copyOfRange(bytes, 0, bytes.length));        System.out.println(msg);        //加入弹幕分组开始接收弹幕        String joinGroupCMD =  "type@=joingroup/rid@=9999/gid@=-9999/";        send(joinGroupCMD, socket);        //循环读取弹幕消息开始        while (true){            byte[] msgBytes = read(socket);            String s = new String(Arrays.copyOfRange(msgBytes, 0, msgBytes.length));            System.out.println(s);            Thread.sleep(1);        }        //关闭链接        //socket.close();    }

如上面的代码所示,根据斗鱼的弹幕协议的要求,每次想接收弹幕必须

1、进行房间的登录

2、加入任意分组(全量弹幕分组:-9999)

然后即可可进行弹幕消息的接收。

其中 登录 的 API 为 type@=loginreq/roomid@=9999/

加入分组的 API 为 type@=joingroup/rid@=9999/gid@=-9999/

rid 表示房间ID,一般直接用房间号即可

当然根据要求 每隔 45秒 还得发送一次心跳消息进行心跳保持,我这并没有实现,请注意自己补充

 

 

全部示例代码

import com.yycdev.douyu.sdk.exceptions.DouYuSDKException;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.util.Arrays;public class Test1 {    public static void main(String[] args) throws IOException, InterruptedException {        Socket socket = new Socket("openbarrage.douyutv.com", 8601);        //发送登录请求(登入9999房间)        String loginCMD = "type@=loginreq/roomid@=9999/";        send(loginCMD, socket);        //读取登录请求消息        byte[] bytes = read(socket);        String msg = new String(Arrays.copyOfRange(bytes, 0, bytes.length));        System.out.println(msg);        //加入弹幕分组开始接收弹幕        String joinGroupCMD =  "type@=joingroup/rid@=9999/gid@=-9999/";        send(joinGroupCMD, socket);        //循环读取弹幕消息开始        while (true){            byte[] msgBytes = read(socket);            String s = new String(Arrays.copyOfRange(msgBytes, 0, msgBytes.length));            System.out.println(s);            Thread.sleep(1);        }        //关闭链接        //socket.close();    }    /**     * 发送消息     *     * @param content     */    public static void send(String content, Socket socket) {        try {            //计算消息长度 = 消息长度(4) + 消息类型(4) + 真实消息内容长度 + 结尾标识长度(1)            int contenLeng = 4 + 4 + content.length() + 1;            //小端模式转换init (长度1)            byte[] contenLeng1 = intToBytesLittle(contenLeng);            //小端模式转换init (长度2)            byte[] contenLeng2 = intToBytesLittle(contenLeng);            //小端模式转换init (消息类型) (689:客户端发送给弹幕服务器的文本格式数据)            byte[] msgType = intToBytesLittle(689);            //标识数据结尾            int end = 0;            ByteArrayOutputStream byteArray = new ByteArrayOutputStream();            //写入长度1            byteArray.write(contenLeng1);            //写入长度2(与长度1相同)            byteArray.write(contenLeng2);            //写入消息类型            byteArray.write(msgType);            //写入消息内容            byteArray.write(content.getBytes("ISO-8859-1"));            //写入数据结尾标识            byteArray.write(end);            //发送数据            OutputStream out = socket.getOutputStream();            out.write(byteArray.toByteArray());            out.flush();        } catch (IOException e) {            throw new DouYuSDKException(e);        }    }    /**     * 读取消息     *     * @return     */    public static byte[] read(Socket socket) {        try {            InputStream inputStream = socket.getInputStream();            //下条信息的长度            int contentLen = 0;            //读取前4个字节,得到数据长度            byte[] bytes1 = readStream(inputStream,0,4);            contentLen = bytesToIntLittle(bytes1, 0); //用小端模式转换byte数组为            //System.out.println("数据长度1:" + contentLen);            //继续读取4个字节,得到第二个 数据长度            byte[] bytes2 = readStream(inputStream,0,4);            int contentLen2 = bytesToIntLittle(bytes2, 0);            //System.out.println("数据长度2:" + contentLen2);            //再次读取4个字节,得到消息类型            byte[] bytes3 = readStream(inputStream,0,4);            //将小端整数转换为大端整数            int msgType = bytesToIntLittle(bytes3, 0);            //System.out.println("消息类型:" + msgType);            //            contentLen = contentLen - 8;            //继续读取真正的消息内容            int len = 0;        //本次读取数据长度            int readLen = 0;    //已读数据长度            byte[] bytes = new byte[contentLen];            ByteArrayOutputStream byteArray = new ByteArrayOutputStream();            while ((len = inputStream.read(bytes, 0, contentLen - readLen)) != -1) {                byteArray.write(bytes, 0, len);                readLen += len;                if (readLen == contentLen) {                    break;                }            }            return byteArray.toByteArray();        } catch (IOException e) {            throw new DouYuSDKException(e);        }    }    /**     * 计算消息体长度     */    private static int calcMessageLength(String content) {        return 4 + 4 + (content == null ? 0 : content.length()) + 1;    }    /**     * 以小端模式将int转成byte[]     *     * @param value     * @return     */    public static byte[] intToBytesLittle(int value) {        byte[] src = new byte[4];        src[3] = (byte) ((value >> 24) & 0xFF);        src[2] = (byte) ((value >> 16) & 0xFF);        src[1] = (byte) ((value >> 8) & 0xFF);        src[0] = (byte) (value & 0xFF);        return src;    }    /**     * 以小端模式将byte[]转成int     */    public static int bytesToIntLittle(byte[] src, int offset) {        int value;        value = (int) ((src[offset] & 0xFF)                | ((src[offset + 1] & 0xFF) << 8)                | ((src[offset + 2] & 0xFF) << 16)                | ((src[offset + 3] & 0xFF) << 24));        return value;    }    /**     * 从流中读取数据     * @param inputStream     * @param off     * @param len     * @return     * @throws IOException     */    public static byte[] readStream(InputStream inputStream, int off, int len) throws IOException {        byte[] bytes = new byte[len];        inputStream.read(bytes, 0, 4);        return bytes;    }}

 

对了顺便推广一下我已经封装好的斗鱼弹幕SDK,欢迎各位直接对接使用

gitee:

github:

72bbffc86a0453184b07fc44700c85d572a.jpg

 

转载于:https://my.oschina.net/fdblog/blog/1926640

你可能感兴趣的文章
关于kafka生产者相关监控指标的理解(未解决)
查看>>
Ubuntu中搭建Hadoop2.5.2完全分布式系统(一)
查看>>
C++ new delete(二)
查看>>
css写出三角形(兼容IE)
查看>>
Ibatis.net 属性字段中使用 IN 查询条件
查看>>
Tiled 瓦片地图
查看>>
Qt字符串与整形转换
查看>>
A Course on Borel Sets Exercise 1.3.6 ii
查看>>
数据结构-栈
查看>>
信息安全系统设计基础实验四:外设驱动程序设计 20145222黄亚奇 20145213祁玮
查看>>
病毒分析基础(一)
查看>>
【百度地图API】如何在地图上添加标注?——另有:坐标拾取工具+打车费用接口介绍...
查看>>
django基础知识~RBAC实验部分代码记录
查看>>
php自己总结的一些经典的实例
查看>>
Todolist总结
查看>>
c++二叉树
查看>>
socket编程 (PHP实现)
查看>>
15 函数回调 模块
查看>>
rsync远程数据同步工具的使用
查看>>
Hibernate 二级缓存
查看>>