简明扼要的说下, 就两个线程,一个 负责收数据,一个负责发心跳包。

步骤如下,

进程1,调用 发包函数,发送连接请求,然后再发送 获取弹幕类型请求,就一直循环接收数据。

进程2,循环函数,每隔45秒向服务器发一次心跳包。

因为斗鱼自己定义了 包头,,所以来在发包之前,先发送包数据。12个字节,

消息头部:消息长度 4字节 +消息类型4字节+加密字段2字节(默认为0)+保留字段2字节(默认为0)

然后就要把要发的内容 加上 “\0”,utf-8 编码后就能发送了

完整的 消息是:包头 + 内容 +”\0”;

上Python代码:

main.py

import socket
import time
import threading
import multiprocessing
from barrage_func import * #  导入自定义方法

SERVER_DOMAIN = "openbarrage.douyutv.com"  # 弹幕服务器 域名
SERVER_PORT = 8601;  # 弹幕服务器 端口
ROOM_ID = 288016;   #房间IDglobal FIX_TAIL #拼接处理后被丢弃的数据,防止弹幕丢失
FIX_TAIL = ""
global gl_client #全局socket
gl_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)def init_socket():global gl_clienthost_ip = socket.gethostbyname(SERVER_DOMAIN)gl_client.connect((host_ip, SERVER_PORT))
def sendDate(client,data):data = data + '\0'   #斗鱼独创序列化文本数据,结尾必须为'\0'data_length = length = len(data)+8  #斗鱼协议在尾部加了 消长度4字节,消息类型2字节(689),加密字段1字节,保留字段1字节,code = 689  # 消息类型# 消息头部:消息长度+消息类型+加密字段(默认为0)+保留字段(默认为0)head = data_length.to_bytes(4, 'little') + data_length.to_bytes(4, 'little') + code.to_bytes(2,'little')+ (0).to_bytes(2,'little')# head = int.to_bytes(data_length, 4, 'little') + int.to_bytes(data_length, 4, 'little') + int.to_bytes(code, 4,'little')client.sendall(head) # 发送头部部分msg = (data).encode('utf-8')  # 使用utf-8编码 数据部分client.sendall(bytes(msg))   # 发送数据部分def getdanmu(client):login = 'type@=loginreq/roomid@=%s/' % ROOM_IDsendDate(client,login)joingroup = 'type@=joingroup/rid@=%s/gid@=-9999/' % ROOM_IDsendDate(client,joingroup)while True:try:part_body = client.recv(1024,socket.MSG_WAITALL)if not part_body:   #如果 服务器发送终止连接b'',则终止会话breakmsg_str = part_body.decode(encoding="utf-8", errors="ignore")get_type(msg_str)except Exception as e:print("getdanmu未知错误: %s" % e)continuedef get_type(msg_str):global FIX_TAILmsg_str = FIX_TAIL + msg_strmsg_arr = msg_str.split("type@=")FIX_TAIL = msg_arr.pop()for value in msg_arr:type_temp = value.split("/")if len(type_temp) >= 2:type_name = type_temp[0]if type_name == "chatmsg":chatmsg =BRRAGE_FUC.get_chatmsg(value)  #获取弹幕类print("["+chatmsg.nn+"]: "+chatmsg.txt)# passelif type_name == "dgb":dgb = BRRAGE_FUC.get_Dbg(value)  #获取礼物类print("感谢[{}] ,赠送的 {} 个 '{}'".format(dgb.nn,int(dgb.gfcnt) * int(dgb.hits),dgb.gfid))# passelif type_name == "uenter":uenter=BRRAGE_FUC.get_uenter(value)  #获取进入房间类print("欢迎 ["+ uenter.nn+"] " + "进入直播间")# passelif type_name == "spbc":spbc = BRRAGE_FUC.get_spbc(value)  # 获取房间广播类print("{} 房间,[{}]赠送给[{}] {} 个 '{}'".format(spbc.drid,spbc.sn,spbc.dn,spbc.gc, spbc.gn))def keep_alive(client):''' 客户端每隔 45 秒发送心跳信息给弹幕服务器 '''while True:alive_msg = "type@=mrkl/"  #新版本# alive_msg = "type@=keeplive/tick@=%s/" % int(time.time())  #旧版本
        sendDate(client,alive_msg)time.sleep(20)if __name__ == '__main__':init_socket()p1 = multiprocessing.Process(target=getdanmu, args=(gl_client,))p2 = multiprocessing.Process(target=keep_alive, args=(gl_client,))p1.start()p2.start()

这里引用了 2个文件,

1个是定义了4个类发言弹幕Brrage_Msg(),赠送礼物Brrage_Dgb(),用户进入房间Brrage_Enter(),广播消息Brrage_Spbc ()

1 个是 写了静态方法BRRAGE_FUC 对上面的类进行 赋值

barrage_func.py

import time
from barrage_info import *
class BRRAGE_FUC(object):'''  常被调用的静态方法  '''#提取发言弹幕
    @staticmethoddef get_chatmsg(msg):brrage_msg =Brrage_Msg()#获取当时时间 eg: '2019-02-16 18:50:02'brrage_msg.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())key_value_list =  msg.split("/")for key_value_temp in key_value_list:key_value=key_value_temp.split("@=",1)if len(key_value)==2:if key_value[0]=="rid":brrage_msg.rid =str(key_value[1])elif key_value[0]=="uid":brrage_msg.uid =str(key_value[1])elif key_value[0]=="nn":brrage_msg.nn =str(key_value[1])elif key_value[0]=="txt":brrage_msg.txt=str(key_value[1])elif key_value[0]=="cid":brrage_msg.cid =str(key_value[1])elif key_value[0]=="nl":brrage_msg.nl =str(key_value[1])elif key_value[0]=="level":brrage_msg.level =str(key_value[1])elif key_value[0]=="bnn":brrage_msg.bnn =str(key_value[1])elif key_value[0]=="bl":brrage_msg.bl =str(key_value[1])elif key_value[0]=="brid":brrage_msg.brid =str(key_value[1])return brrage_msg#提取送礼物弹幕
    @staticmethoddef get_Dbg(msg):brrage_dgb = Brrage_Dgb()# 获取当时时间 eg: '2019-02-16 18:50:02'brrage_dgb.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())key_value_list = msg.split("/")for key_value_temp in key_value_list:key_value = key_value_temp.split("@=",1)if len(key_value) == 2:if key_value[0] == "rid":brrage_dgb.rid = key_value[1]elif key_value[0] == "uid":brrage_dgb.uid = key_value[1]elif key_value[0] == "nn":brrage_dgb.nn = key_value[1]elif key_value[0] == "sn":brrage_dgb.sn = key_value[1]elif key_value[0] == "gfid":brrage_dgb.gfid = key_value[1]elif key_value[0] == "gfcnt":brrage_dgb.gfcnt = key_value[1]elif key_value[0] == "hits":brrage_dgb.hits = key_value[1]return brrage_dgb#提取用户进房通知弹幕
    @staticmethoddef get_uenter(msg):brrage_enter = Brrage_Enter()key_value_list = msg.split("/")for key_value_temp in key_value_list:key_value = key_value_temp.split("@=",1)if len(key_value) == 2:if key_value[0] == "rid":brrage_enter.rid = key_value[1]if key_value[0] == "uid":brrage_enter.uid = key_value[1]if key_value[0] == "nn":brrage_enter.nn = key_value[1]if key_value[0] == "nl":brrage_enter.nl = key_value[1]return brrage_enter#飞机、火箭 广播消息
    @staticmethoddef get_spbc(msg):brrage_spbc = Brrage_Spbc()key_value_list = msg.split("/")for key_value_temp in key_value_list:key_value = key_value_temp.split("@=",1)if len(key_value) == 2:if key_value[0] == "rid":brrage_spbc.id = key_value[1]if key_value[0] == "drid":brrage_spbc.drid = key_value[1]if key_value[0] == "uid":brrage_spbc.uid = key_value[1]if key_value[0] == "sn":brrage_spbc.sn = key_value[1]if key_value[0] == "dn":brrage_spbc.dn = key_value[1]if key_value[0] == "gn":brrage_spbc.gn = key_value[1]if key_value[0] == "gc":brrage_spbc.gc = key_value[1]if key_value[0] == "gb":brrage_spbc.gb = key_value[1]if key_value[0] == "gfid":brrage_spbc.gfid = key_value[1]return brrage_spbc

barrage_info.py

class Brrage_Base(object):rid = "0"  # 房间号uid = "0"  # 用户idnn = "nn"  # 用户昵称time = "0000-00-00 00:00:00"  # 时间class Brrage_Msg(Brrage_Base):"""表示为“弹幕”消息,type固定为 chatmsg"""def __init__(self):self.txt="txt"  #弹幕文本内容self.cid=""   #弹幕唯一 IDself.nl=0   #贵族等级self.level =0   #用户等级self.bnn = ""  # 徽章昵称self.bl = 0  # 徽章等级self.brid=0   #徽章房间 idclass Brrage_Dgb(Brrage_Base):'''表示为“赠送礼物”消息,type固定为 dgb '''def __init__(self):self.gfid=0      #礼物 idself.gfcnt =1 #礼物个数:默认值 1self.hits=1   #礼物连击次数:默认值 1(表示 1 连击)class Brrage_Enter(Brrage_Base):''' 表示为“用户进房通知”消息,type固定为 uenter '''def __init__(self):self.nl = 0  # 贵族等级class Brrage_Spbc(Brrage_Base):''' 房间内礼物广播,type固定为 spbc'''def __init__(self):self.drid = 0  #赠送房间 rid ,默认为0self.sn = ""  # 赠送者昵称self.dn = ""  # 受赠者昵称self.gn = ""  # 礼物名称self.gc = 1  # 礼物数量# self.gs = ""  # 广播样式self.gb = 1  # 是否有礼包(0-无礼包,1-有礼包)# self.es = 1  # 广播展现样式(1-火箭,2-飞机)self.gfid = 1  #礼物 id

运行 main.py 看效果,,比 官方弹幕 还 全,,官方应该 对 tcp 粘包没处理好。

下面的是C#的代码,原理都一样

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;namespace danmu
{class Program{private static string SERVER_DOMAIN = "openbarrage.douyutv.com";private static int SERVER_PORT = 8601;private static int ROOM_ID = 288016;private static string FIX_TAIL = String.Empty;  //拼接处理后被丢弃的数据,防止弹幕丢失class BrrageMsg{public string Name = String.Empty;public string Txt = String.Empty;}static void Main(string[] args){try{Socket tcpClient = InitTcp(SERVER_DOMAIN, SERVER_PORT);Thread getDanmuThread = new Thread(GetDanmu);getDanmuThread.Start(tcpClient);Thread keepAliveThread = new Thread(KeepAlive);keepAliveThread.Start(tcpClient);}catch (Exception ex){Console.WriteLine(ex.ToString());}}static Socket InitTcp(string host, int port){IPHostEntry hostInfo = Dns.GetHostEntry(host);IPAddress ipAddress = hostInfo.AddressList[0]; //域名转IPIPEndPoint ipe = new IPEndPoint(ipAddress, port);Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);s.Connect(ipe);return s;}static byte[] DataToBytes(string data){string dantaNew = data + "\0";byte[] bodyDataByte = Encoding.UTF8.GetBytes(dantaNew);byte[] cType = BitConverter.GetBytes(689);int dataLength = dantaNew.Length + cType.Length + 8;byte[] dataLengthByte = BitConverter.GetBytes(dataLength);byte[] dataLengthByte2 = BitConverter.GetBytes(dataLength);byte[] result = new byte[dataLength + 4];Array.Copy(dataLengthByte, 0, result, 0, 4);Array.Copy(dataLengthByte2, 0, result, 4, 4);Array.Copy(cType, 0, result, 8, 4);Array.Copy(bodyDataByte, 0, result, 12, bodyDataByte.Length);byte[] source = new byte[result.Length];Array.Copy(result, 0, source, 0, result.Length);return result;}static void GetDanmu(object obj){Socket tcpClient = (Socket)obj;string login = "type@=loginreq/roomid@=" + ROOM_ID + "/";byte[] loginBytes = DataToBytes(login);tcpClient.Send(loginBytes);string joingroup = "type@=joingroup/rid@=" + ROOM_ID + "/gid@=-9999/";byte[] joingroupBytes = DataToBytes(joingroup);tcpClient.Send(joingroupBytes);string recvStr = "";byte[] recvBytes = new byte[1024];int bytes;while (true){bytes = tcpClient.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息recvStr = Encoding.UTF8.GetString(recvBytes, 0, bytes);ShowMsg(recvStr);}}static BrrageMsg GetMsgType(string[] msgType){BrrageMsg brrageMsg = new BrrageMsg();foreach (string keyValueTemp in msgType){string[] keyValue = Regex.Split(keyValueTemp, "@=", RegexOptions.IgnoreCase);if (keyValue.Length >= 2){string key = keyValue[0];string[] textArr = new string[keyValue.Length - 1];Array.Copy(keyValue, 1, textArr, 0, keyValue.Length - 1);string value = String.Join("@", textArr);if (key =="nn"){brrageMsg.Name = value;}if ((key == "txt")){brrageMsg.Txt = value;}}}return brrageMsg;}static void ShowMsg(string msg){msg = FIX_TAIL + msg;string[] chatmsgArray = Regex.Split(msg, "type@=", RegexOptions.IgnoreCase);FIX_TAIL = chatmsgArray[chatmsgArray.Length - 1];   //截取最后的丢弃数据,放在下个包的开头,防止数据丢失string[] newChatmsgArrayArr = new string[chatmsgArray.Length - 1];Array.Copy(chatmsgArray, 0, newChatmsgArrayArr, 0, chatmsgArray.Length - 1);foreach (string t in newChatmsgArrayArr){string[] msgType = t.Split('/');if (msgType.Length >= 2){string type = msgType[0];if (type == "chatmsg"){BrrageMsg brrageMsg=GetMsgType(msgType);string result = String.Format("[{0}]: {1}", brrageMsg.Name, brrageMsg.Txt);Console.WriteLine(result);}}}}static void KeepAlive(object obj){Socket tcpClient = (Socket)obj;byte[] aliveMsg = DataToBytes("type@=mrkl/");while (true){tcpClient.Send(aliveMsg);Thread.Sleep(40000);}}}
}

转载于:https://www.cnblogs.com/likehc/p/10427130.html

斗鱼连接弹幕Demo_pythonC#相关推荐

  1. .NET斗鱼直播弹幕客户端(2021)

    .NET斗鱼直播弹幕客户端(2021) 离之前更新的两篇<.NET斗鱼直播弹幕客户端>已经有一段时间,近期有许多客户向我反馈刚好有这方面的需求,但之前的代码不能用了--但网上许多流传的No ...

  2. .NET斗鱼直播弹幕客户端(下)

    前言 在上篇文章中,我们提到了如何使用 .NET连接斗鱼TV直播弹幕的基本操作.然而想要做得好,做得容易扩展,就需要做进一步的代码整理. 本文将涉及以下内容: 介绍如何使用 ReactiveExten ...

  3. .NET斗鱼直播弹幕客户端(上)

    前言 现在直播平台由于弹幕的存在,主播与观众可以更轻松地进行互动,非常受年轻群众的欢迎.斗鱼TV就是一款非常流行的直播平台,弹幕更是非常火爆.看到有不少主播接入 弹幕语音播报器. 弹幕点歌等模块,这都 ...

  4. python登录斗鱼_Python实现抓取斗鱼实时弹幕

    [Python] 纯文本查看 复制代码''' 文件名:爬取斗鱼直播间信息到jsonline文件.py ''' from __future__ import unicode_literals impor ...

  5. 斗鱼直播弹幕python_python利用danmu实时获取斗鱼等直播网站字幕

    danmu 是一个开源的直播平台弹幕接口 用python    pip install danmu # -*- coding: utf-8 -*- import time, sys from danm ...

  6. OBS斗鱼直播弹幕插件效果

    我没有安装任何OBS插件,一样达到了美化版弹幕效果

  7. dplayer弹幕服务器php,修复官方Dplayer-Typecho插件不能连接弹幕API后端的方法

    说明:博主之前发过DPlayer弹幕后端搭建教程→传送门,也说了下HTML代码的使用方法,不过对于Typecho博客来说,插件不能用会很麻烦,加上看见很多使用Typecho的同学对这个还是有点兴趣的, ...

  8. Python实现抓取斗鱼实时弹幕

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资 ...

  9. 超级卵杰的自动脚本(1)连接斗鱼弹幕服务器。

    这是关于超级卵杰(74751)直播间的python自动化脚本.超级卵杰只会玩卵子图,导致压分压哪输哪.所以做了个自动化脚本替我压分.基本上卵杰直播间的功能都能实现.接受弹幕是根据别人模板改的. 主要是 ...

  10. PHP点歌插件,斗鱼弹幕点歌插件_小葫芦社区_小葫芦插件交流 - Powered by Discuz!

    更新版本:3.3.7更新日期:2017-04-25更新日志:1. 修复 部分斗鱼房间无法连接弹幕的问题(主要是参与主播带你嗨购活动的主播)2. 修复 其他已知问题 更新版本:3.2.16更新日期:20 ...

最新文章

  1. c语言330转化成字符,c语言同步练习(330份).doc
  2. 如何修改Web Interface4.5多语言版的版权信息
  3. itk下FFTW的FFT和IFFT
  4. ec200s 方案 移远_移远4GCat1无线通讯模块EC200S
  5. 图解MySQL删除再安装教程
  6. linux下kodi没有声音的解决
  7. C# 使用 Index 和 Range 简化集合操作
  8. matlab期中考试卷,matlab期末考试试卷及答案.doc
  9. 如何在jsp页面中连接mysql数据库_如何使用JSP访问MySQL数据库
  10. 20190808估值方法
  11. VSS控制存储过程,及其asp.net的远程调试
  12. 开源自动化配置管理工具Puppet入门教程
  13. 计算机处理答题卡原理,基于图像处理的答题卡自动阅卷系统的设计与实现
  14. 自己动手简单实现vbb的URL静态化
  15. Amesim更改为中文
  16. h.264视频编码器
  17. 选中的磁盘具有mbr分区表。在efi_电脑磁盘怎么重建主引导记录mbr【详细步骤】...
  18. steam linux 安装目录,「Linux」- 安装 Steam 客户端 @20210219
  19. java雪崩_java-雪崩效应及解决办法
  20. 律师学python有什么用呢_《律》字意思读音、组词解释及笔画数 - 新华字典 - 911查询...

热门文章

  1. 简要概述网络I/O与并发
  2. 网络安全 Security+(SY0-601)学习笔记
  3. [C语言循环应用]--打印字符金字塔
  4. NYOJ-97兄弟郊游问题
  5. DRDS 柔性事务漫谈
  6. Android:Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
  7. Add NIC to Openfiler 2.3
  8. rsync数据同步工具
  9. NO.170 六问禅道1:为什么任务的剩余工时不自动更新?
  10. selenium 自动化web测试