房间16401 300100

30010级以下的猎人RAID及庆祝活动Dota-在线观看-风行网
全部标记为已读
您暂未收到新消息哦~
***PC客户端
把想看的剧下载到本地吧~
点击立即下载就可以下载当前视频了哦~
我来说两句
播放:1,147
播放:6,362
播放:4,533
播放:472,958
播放:100,259
播放:1,010
播放:3,580
播放:2,845
播放:3,131
播放:17,362
精选视频号我玩过的游戏我收藏的游戏
热门月排行热门总排行
3.2分3.2分3.2分3.2分3.2分
3.2分3.2分3.2分3.2分3.2分
30010小游戏最新推荐
30010小游戏专题推荐
30010经典游戏
30010女生小游戏
射击类小游戏
战争类小游戏
益智类小游戏
双人类小游戏
休闲类小游戏
敏捷类小游戏
30010小游戏热门分类
网站为您提供、、等深受广大网友喜爱的基于C#分步式聊天系统的在线视频直播系统设计 - CSDN博客
基于C#分步式聊天系统的在线视频直播系统设计
视频在线直播系统:;在线聊天系统demo:
核心系统框架
&&&&&&&& 视频直播核心系统架构主要包括Web端架构、聊天系统架构、视频直播、用户状态同步架构等。
由Nginx组成的前端负载集群,后端由IIS、FPM服务器进行解析。前端将由Nginx集群处理已静态化页面及向后端提交未静态或不做静态化要求的请求,后端Cached为应用缓存,主要减少对数据库无意义请求造成的压力,数据库架构由一主一备组成(目前暂无备库)。
聊天系统框架
&&&&&&&& 聊天系统分为聊天室(ChatRoom)、消息同步中心(CastServer)、用户列表(UserList Server)、系统广播(SystemCast Server)及监控报表(Report)组成。同房间不同服务器之间用户的消息系统广播、及用户列表则通过消息同步中心进行传递。用户连接房间之前由调度中心分配聊天室服务器进行连接。该架构特点是同时在线人数易扩展、可实现负载均衡。
用户状态同步机制
&&&&&&& 用户状态(Session)的同步机制之所以列为核心,是考虑到用户消费、充值等行为与非用户行为造成用户属性变更能及时反馈给用户,此举能大大提高产品的用户体验。该机制主要实现不同框架、不同服务器、不同站点(域名)之间用户状态的同步。同步之主要工作由SessionComponents组件完成。
用户端反应
用户充值
用户成功充值后由系统发起系统广播,通知在线用户充值成功,并无需刷新帐号金额自动同步。
运营发放库存及运营币
无论用户呆在哪个房间,都能收到该系统消息(目前如果用户不在线,不能成功接收)
服务器规划
CPU:4核,内存8G
含:聊天室、用户列表、系统广播(注:服务器要求双线机房)
CPU:4核,内存:8G
站点、充值、接口、资源、活动等服务器
CPU:4核,内存:8G
Nginx服务器
分步式缓存
CPU:4核,内存:8G
Memcached服务器(应用缓存与用户Session状态)
CPU:8核,内存:16G
数据库服务器,一主一备
CPU:8核,内存:16G
Rtmp服务器
&&&&&&&& 视频系统主要包含客户端推流、服务端处理、客户端接收流三大部份。视频流畅效果取决于推流端与接收端两端带宽,任何一方网络带宽问题都会将降低观看者效果,其中推流端由为重要,其将影响所有人观看。
&&&&&&&& 高清插件由Flash调用的ActiveX控件,只支持以IE为内核的浏览器调用,适用于主播端。高清插件主要功能有两个,1、加水印;2、进行高清编码。
插件代码片断
void RtmpLiveScreen::Run()
&&& //连接rtmp server,完成握手等协议
&&& librtmp_-&Open(rtmp_url_.c_str());
&&& //发送metadata包?
&&& SendMetadataPacket();
&&& //开始捕获音视频
&&& ds_capture_-&StartAudio();
&&& ds_capture_-&StartVideo();
&&& while (true)
if(SimpleThread::IsStop()) break;
// 从队列中取出音频或视频数据
&&&&&&& std::deque&RtmpDataBuffer&rtmp_
&&&&&&&&&&& base::AutoLock alock(queue_lock_);
&&&&&&&&&&&
if(false == process_buf_queue_.empty())
&&&&&&&&&&& {
&&&&&&&&&&&&&&&rtmp_datas = process_buf_queue_;
&&&&&&&&&&&&&&&process_buf_queue_.clear();
&&&&&&&&&&& }
// 加上时戳发送给rtmp server
for (std::deque&RtmpDataBuffer&::iterator it =rtmp_datas.begin();
&&&&&&&&&&& it!= rtmp_datas.end(); ++it)
&&&&&&&&&&&RtmpDataBuffer& rtmp_data = *
&&&&&&&&&&&
if (rtmp_data.data != NULL)
&&&&&&&&&&& {
&&&&&&&&&&&&&&&if (rtmp_data.type ==FLV_TAG_TYPE_AUDIO)
&&&&&&&&&&&&&&&&&&&SendAudioDataPacket(rtmp_data.data, rtmp_data.timestamp);
&&&&&&&&&&&&&&&else
&&&&&&&&&&&&&&&&&&&SendVideoDataPacket(rtmp_data.data, rtmp_data.timestamp,rtmp_data.is_keyframe);
&&&&&&&&&&& }
&&&&&&&Sleep(1);
&&&ds_capture_-&StopVideo();
&&&ds_capture_-&StopAudio();
&&&librtmp_-&Close();
流媒体服务
&&&&&&&& 视频流完全可以不经过流媒体服务,由于各家CDN所覆盖区域偏重点不一致,故系统采用流媒体服务实现一对多的推流是为了更好的适应不同区域客户端的网络情况。如下图所示:
http://up./live/ROOMID
live为发布点名称,与CDN商量协定,ROOMID为房间ID
http://down./live/ROOMID
聊天服务由底层采用Socket中的完成端口方式实现,该系统单台服务器支持10000以上的连接数,虽然所有Socket连接方式的客户端都被接受,但在服务端有身份验证机制防止恶意连接。目前实现对接的客户端有Flash、C++。服务端与客户端通讯由固定协议(包头+包体)完成,包体大都采用JSON进行序列化及反序列化。
&&&&&&&& 每条完整的消息由包头和包体组成(当然包体可以为空,也就是消息仅含包头的情况),包头共20字节,由5组int类型数据组成,分别代表指令ID、房间ID、用户ID、时间及描述包体长度。
Header/Body
BODYLENGTH
数值
指令JSON格式(示例)
COMMAND_SYSTEM_SYN_MESSAGE
同步系统消息
COMMAND_SYSTEM_SYN_USERMESSAGE
同步用户消息
COMMAND_SYSTEM_MESSAGE
COMMAND_SYSTEM_SYN_USEREXITSTATUS
用户退出消息
COMMAND_SYSTEM_SYN_USERJOINSTATUS
用户进入房间消息
COMMAND_SYSTEM_USERINFOCHANGE
用户余额变更
COMMAND_SYSTEM_SYN_ROOMINFOREPORTMESSAGE
同步统计房间用户信息
COMMAND_SYSTEM_CASTROOMMESSAGE
COMMAND_SYSTEM_WORLDCASTROOMMESSAGE
COMMAND_SYSTEM_CAST_SUNNY
COMMAND_USER_GIFTS
用户送礼
COMMAND_USER_MESSAGE
用户聊天消息
COMMAND_USER_MANAGER_MESSAGE
用户管理消息
COMMAND_USER_OPERATE_EXITMESSAGE
用户主动退出消息
COMMAND_USER_ANCHOR_LIVEIN
主播正在直播消息
COMMAND_CLIENT_LOGININFO
用户登录消息
COMMAND_CLIENT_USERLIST
用户列表通知消息
COMMAND_CLIENT_LOGINOTHERUSER
用户登录后通知其它用户的消息
COMMAND_CLIENT_LOGINOUTOTHERUSER
用户退出后通知其它用户的消息
COMMAND_CLIENT_USERROLELIST
用户权限列表
COMMAND_CLIENT_APPENDUSERLIST
追加用户列表
COMMAND_CLIENT_SENDMESSAGESOFAST
警告发送过快消息
COMMAND_CLIENT_REQUESTSENDUSERLIST
请求加载用户列表消息
COMMAND_RETURN_CONNECTED
客户端连接成功消息
COMMAND_RETURN_CANNOTSPEAK
用户被禁言消息
COMMAND_RETURN_OPERATE_CANNOTSPEAK_SUCCESS
禁言用户成功消息
COMMAND_RETURN_OPERATE_CANNOTSPEAK_FAILURE
禁言用户失败消息
COMMAND_RETURN_OPERATE_KICKUSER_SUCCESS
踢出用户成功消息
COMMAND_RETURN_OPERATE_KICKUSER_FAILURE
踢出用户失败消息
COMMAND_RETURN_OPERATE_BANIPUSER_SUCCESS
禁IP成功消息
COMMAND_RETURN_OPERATE_BANIPUSER_FAILURE
禁IP失败消息
COMMAND_RETURN_OPERATE_RELIEVE_SUCCESS
取消禁言成功消息
COMMAND_RETURN_OPERATE_RELIEVE_FAILURE
取消禁言失败消息
COMMAND_RETURN_OPERATE_SETADMIN_SUCCESS
设置用户为管理员成功消息
COMMAND_RETURN_OPERATE_SETADMIN_FAILURE
设置用户为管理员失败消息
COMMAND_RETURN_OPERATE_RMADMIN_SUCCESS
删除用户管理员成功消息
COMMAND_RETURN_OPERATE_RMADMIN_FAILURE
删除用户管理员失败消息
COMMAND_RETURN_USERVERIFY_FAILURE_KICK
用户验证失败(被踢出了)
COMMAND_RETURN_USERVERIFY_FAILURE
用户验证失败
COMMAND_RETURN_USER_NOTWORTHBALANCE
用户余额不足
COMMAND_RETURN_DEDUCTIONS_FAILURE
扣费验证失败
COMMAND_SCENE_MANAGER_BEGIN
COMMAND_SCENE_MANAGER_END
COMMAND_SCENE_MANAGER_RETURN
操作失败消息
COMMAND_SCENE_MANAGER_SEATUSERLIT
座位列表消息
COMMAND_SCENE_MANAGER_ENCORE
安可的开启与关闭
COMMAND_SCENE_MANAGER_ENCOREINFO
安可信息的发送
COMMAND_CLIENT_SENDTOCLIENTSTATUS
客户端向服务器报告连接状态
COMMAND_FACETIME_REQUEST
COMMAND_FACETIME_UPDATE
联麦信息更新
COMMAND_FACETIME_USER_COMPLETE
COMMAND_FACETIME_USERLIST
联麦用户列表
COMMAND_FACETIME_ADDFACETIMES
增加联麦时间
COMMAND_FACETIME_REQUESTOUTER
申请退出联麦
COMMAND_FACETIME_REQUESTCASTUSERLIST
申请广播联麦用户列表
SERVER_CHATROOM_USERJOIN
用户进入(同步至用户列表服务器)
SERVER_CHATROOM_USEROUTER
用户退出(同步至用户列表服务器)
SERVER_CHATROOM_CASTUSERLIST
广播用户列表(用户列表服务器)
SERVER_CHATROOM_USERSTAT
发送房间统计数据
SERVER_CHATROOM_USERLIST_RESET
清除用户列表服务器上用户(当聊天服务器重启时)
SERVER_CHATROOM_USERINFO_UPDATE
房间用户信息变更(同步更新至用户列表服务器)
SERVER_CHATROOM_SYNC_SERVERSTATUS
子服务状态同步
SERVER_CHATROOM_SYNC_CASTMESSAGE
广播消息同步
SERVER_CHATROOM_SYNC_CONVEYMESSAGE
广播消息中转
COMMAND_SYSTEM_OPERATE_GETROOMINFO
获取房间日志
Flash的特殊处理
Flash通过Socket连接聊天服务端会出现安全策略问题,通常页面上加载Flash时会默认请求当前域下的crossdomain.xml和这里的情况一样。所以,在服务端***时对请求做特殊的处理,将策略文件内容通过连接发送回去。一般策略文件请求在连接端口的Socket中收到,但在这之前Flash默认的会先对843端口提交请求,只有失败后或超时(约3秒)才会向连接端口重新请求,所以在843端口另启***线程专门来应对策略文件的请求会比一般的处理速度更快。
消息处理分线程
bool _iocpSocket_OnRecv(RecvMessage recv)
Message message = recv.M
if (null == message)
return false;
ChatRoom chatRoom =_chatRooms.GetChatRoom(message.Head.RoomId,
DealWithMessageThread dealWith = null;
switch ((Command)mand)
&&&&&&&&&&
case Command.COMMAND_CLIENT_LOGININFO:
&&&&&&&&&&&&& chatRoom.messageDealWithNew(recv.SO,message);
&&&&&&&&&&&&&
Log.WriteErrorLog(&SocketServer::_iocpSocket_OnRecv&,message.ToString());
&&&&&&&&&&&&&
&&&&&&&&&&
case Command.COMMAND_USER_GIFTS:
&&&&&&&&&&&&& dealWith= _dealWithGiftsThreadPool.Get();
&&&&&&&&&&&&& dealWith.Add(newMessageParams(0,recv.SO, recv.Message, chatRoom,null));
&&&&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&&&& dealWith= _dealWithMessageThreadPool.Get();
&&&&&&&&&&&&& dealWith.Add(newMessageParams(0,recv.SO, recv.Message, chatRoom,null));
&&&&&&&&&&&&&
return true;
&&& catch (Exceptionex)
Log.WriteErrorLog(&SocketServer::_iocpSocket_OnRecv&,ex.Message);
&&& returnfalse;
各服务器间的消息同步
privatevoid recvMessageDealWith(Messagemessage,EndPoint
&&&&&& _tmpMessage.Add(String.Format(&[{0}]来自{1}的消息{2}&,DateTime.Now,endPoint,JsonConvert.SerializeObject(message.Head)));
if (_tmpMessage.Count & 50)
&&&&&&&&&& _tmpMessage.RemoveAt(0);
string ip = Convert.ToString(endPoint).Split(':')[0];
//string port = Convert.ToString(endPoint).Split(':')[1];
switch ((Command)mand)
&&&&&&&&&&
///服务器状态同步
&&&&&&&&&&
case Command.SERVER_CHATROOM_SYNC_SERVERSTATUS:
&&&&&&&&&&&&&
ServerInfo info = ByteConverter.BytesToObject(message.Body)asServerInfo;
&&&&&&&&&&&&&
ChildServer _s = loadServer(ip, info);
&&&&&&&&&&&&& _s.Reset(info);
&&&&&&&&&&&&&
if (_s.IsNode && null== _nodeServer)
&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&& _nodeServer= _s;
&&&&&&&&&&&&& }
&&&&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&&&& sysCast(message,ip);
&&&&&&&&&&&&&
&&& catch (Exceptionex)
Log.WriteErrorLog(&ServerControl::recvMessageDealWith&,&{0}&,Encoding.UTF8.GetString(message.Body));
策略文件***
_crossDomainServer =
new CrossDomainServer();
bool ret =_crossDomainServer.StartListen(_helper.GetCrossDomainPolicyPort(),_helper.GetCrossDomainPolicyData());
Log.WriteSystemLog(&SocketServer::Listen&,&服务器[{0}]成功开启安全策略请求的***器,端口为[{1}]&,
_helper.GetLocalServerId(), _helper.GetCrossDomainPolicyPort());
Log.WriteSystemLog(&SocketServer::Listen&,&警告警告服务器 [{0}]开启安全策略请求的***器,端口为
[{1}]失败”,_helper.GetLocalServerId(), _helper.GetCrossDomainPolicyPort());
策略文件处理
if (null!= client)
SendMessage sm = newSendMessage(client, _crossDomainXmlBytes);
&&& client.BeginSend(sm.SendBuffer,sm.SendIndex, sm.SendCount
&&&&&&&&&&&&&&&&&&&&&&&& ,SocketFlags.Partial,newAsyncCallback(clientSendCallback),sm);
Flash端连接处理
var tryCount:int = 0;//重连次数
var reconndelay:int = 3000;//重连间隔
var socket = new Socket();
socket.addEventListener(Event.CONNECT,connectOk);
socket.addEventListener(Event.CLOSE,closed);
socket.addEventListener(IOErrorEvent.IO_ERROR,ioErrored);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityErrored);
connectToServer();
private function connectToServer():void
&&& woo.debug.debug.trace(&socket&,&正在连接到&+HOST+&:&+PORT);
&&& setTimeout(function():void{socket.connect(HOST,PORT);},reconndelay*tryCount);
&&& tryCount ++;
private function securityErrored(eve:SecurityErrorEvent):void
&&& //安全策略错误处理
private function ioErrored (eve:SecurityErrorEvent):void
&&& //IOERROR处理
private function closed (eve:SecurityErrorEvent):void
&&& connectToServer();//重连
Flash端消息发送
socket.addEventListener(ProgressEvent.SOCKET_DATA,receiveData);
private function receiveData(eve:ProgressEvent =null):void
&&& if(this.DATA.CMD==0)
&&&&&& if(socket.bytesAvailable&=20)
&&&&&&&&&& varhead:ByteArray = new ByteArray();
&&&&&&&&&& socket.readBytes(head,0,20);
&&&&&&&&&& varbyte0:ByteArray = new ByteArray();
&&&&&&&&&& varbyte1:ByteArray = new ByteArray();
&&&&&&&&&& varbyte2:ByteArray = new ByteArray();
&&&&&&&&&& varbyte3:ByteArray = new ByteArray();
&&&&&&&&&& varbyte4:ByteArray = new ByteArray();
&&&&&&&&&& byte0.position= 0;
&&&&&&&&&& byte1.position= 0;
&&&&&&&&&& byte2.position= 0;
&&&&&&&&&& byte3.position= 0;
&&&&&&&&&& byte4.position= 0;
&&&&&&&&&& head.readBytes(byte0,0,4);
&&&&&&&&&& head.readBytes(byte1,0,4);
&&&&&&&&&& head.readBytes(byte2,0,4);
&&&&&&&&&& head.readBytes(byte3,0,4);
&&&&&&&&&& head.readBytes(byte4,0,4);
&&&&&&&&&& DATA.CMD= byteToInt(byte0);
&&&&&&&&&& DATA.ROOMID= byteToInt(byte1);
&&&&&&&&&& DATA.USERID= byteToInt(byte2);
&&&&&&&&&& DATA.TIME= byteToInt(byte3);
&&&&&&&&&& DATA.BODYLENGTH= byteToInt(byte4);
&&&&&& else
&&& if(socket.bytesAvailable&=this.DATA.BODYLENGTH)
&&&&&& varbody:String = socket.readUTFBytes(DATA.BODYLENGTH);
&&&&&& DATA.BODY =
&&& & this.sendNotification(Notifications.M_SOCKET_RECEIVE_MSG,this.DATA);
&&&&&& data =
&&&&&& data = newSocketMsgVo();//完整消息取完,清空数据对象
&&&&&& if(20&=socket.bytesAvailable)
&&&&&&&&&& arguments.callee();//再执行当前方法
&&&&&& else
Flash消息的发送
public function sendMsg(vo:SocketMsgVo):void
&&& if(socket.connected)
&&&&&& socket.writeBytes(vo.bytes,0,vo.bytes.length);
&&&&&& socket.flush();
&&&&&& socket.connect(HOST,PORT);
充值
&&&&&&&& 充值采用第三方充值平台实现,可接入支付宝、易宝等第三方开发平台,原理简单,不做详细介绍。
虚拟礼物
&&&&&&&& 虚拟礼物的实现主要分为两块,用户提交送礼请求由扣费服务验证,成功后广播到房间所有用户在前端展示礼物效果。
送礼详细流程
扣费代码片断
礼物展示代码片断
//播放礼物
publicfunction ShowGiftInter(id:int, num:int,type:int,w:int,h:int, msg:String =&&) {
&&&&&&&&&&& this.setStageSize(w,h);
&&&&&&&&&&& _gift.showGiftInter(id, num, type,msg);
&&&&&&&&&&& trace(&123123&);
//设置播放区域
publicfunction setStageSize(wid:int, het:int) {
&&&&&&&&&&& _gift.resetGroup(wid - w,het - h);
&&&&&&&&&&& w =
&&&&&&&&&&& h =
&&&&&&&&&&& _fs.setStageSize(wid, het);
&&&&&&&&&&& _gift.setStageSize(wid, het);
//播放飞屏
publicfunction showFlyText(str:String,w:int,h:int,speed:int = 4) {
&&&&&&&&&&& setStageSize(w,h);
&&&&&&&&&&& _fs.setStaticText(str, speed);
//播放进场动画
publicfunction ShowCarInter(id:int,w:int,h:int,_no:int,_nick:String,_sex:int)
&&&&&&&&&&& this.setStageSize(w,h);
&&&&&&&&&&& _gift.showGiftInter(id,1,5,{liangNo:_no,nickName:_nick,sex:_sex});
本文已收录于以下专栏:
相关文章推荐
核心系统框架
         视频直播核心系统架构主要包括Web端架构、聊天系统架构、视频直播、用户状态同步架构等。
由Nginx组成的前端负载集群,后端由IIS、FPM...
文件日志组件,组件分调试、普通、警告、系统、异常5个等级,根据配置等级将日志写入文件。
博客一:转自:http://blog.csdn.net/u/article/details/大家好,本人刚毕业程序猿一枚。受人所托,第一次写博客,如有错误之处敬请谅解...
一般而言,视频会议的主要核心功能是:多人语音、多人视频、公共电子白板、会议房间管理。GGMeeting 1.0 已经实现了这几个核心功能,后续我们会不断增强GGMeeting ,每次版本发布都会放出源...
一对多聊天系统在上一篇博客中,我们写了一个基于TCP的客户端和服务器的一对一双向聊天系统,但只能开一个客户端与服务器通信,我们在之前的代码做一些改动,就实现了多个客户端与服务器通信的系统,且服务器能向...
对于基于TCP开发的通讯程序,有个很重要的问题需要解决,就是封包和拆包.下面就针对这个问题谈谈我的想法,抛砖引玉.若有不对,不妥之处,恳求大家指正.在此先谢过大家了.
转载地址:http://h...
他的最新文章
讲师:王禹华
讲师:宋宝华
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

参考资料

 

随机推荐