高性能多媒体转发服务器的设计.docx
- 文档编号:27711166
- 上传时间:2023-07-04
- 格式:DOCX
- 页数:37
- 大小:5.05MB
高性能多媒体转发服务器的设计.docx
《高性能多媒体转发服务器的设计.docx》由会员分享,可在线阅读,更多相关《高性能多媒体转发服务器的设计.docx(37页珍藏版)》请在冰豆网上搜索。
高性能多媒体转发服务器的设计
华中科技大学
研究生课程考试答题本
考生姓名
考生学号
系、年级电子与信息工程系
考试科目软件工程及系统设计
考试日期2014年06月17日
评分
题号
得分
题号
得分
1、OPALVOIP项目分析
2、“高性能多媒体转发服务器”的设计
说明
1)请同学们统一使用小四字体,1.5倍行间距,A4纸打印。
总分:
评卷人:
注:
1无评卷人签名试卷无效。
2必须用钢笔或圆珠笔,使用红色。
用铅笔阅卷无效。
高性能多媒体转发服务器的设计
1概述
随着网络技术的迅速发展,各种各样的网络多媒体应用层出不穷,其中以流媒体技术为背景的应用发展最为迅速。
流媒体技术改变了互联网,更加丰富了互联网的功能。
现在很多应用都需要流媒体技术,如在线视频,网络视频监控系统等等。
随着智能家居的发展,构建网络视频监控系统更是未来的发展方向。
为了满足中心或者其他远程客户同时对远程监控场所的访问,这个时候就需要高性能的流媒体转发服务器。
2需求分析
该多媒体转发服务器需要实现TCP,UDP,RTP的多媒体数据转发,每个转发服务需要在独立的线程中完成,该服务器要具有状态监控的功能,具有码率控制的功能。
要求有概要设计,详细设计,并且采用面向对象的设计方法。
概要设计要求以明确部署结构,模块层次,模块结构,模块接口为目标。
需要包含系统环境部署形式等的部署图。
组件图包含组件的层次关系,组件的外部调用接口和数据接口的定义。
类要描述类层次和关联,接口实现类的具体化。
框架时序图要描述框架程序以及各个功能组件之间与接口相关的时序关系。
详细设计目标,详细描述各模块的实现算法、局部的数据结构,明确各组件中类或者函数的定义以及数据。
要详描述完整的用户界面,细化各个类的属性和方法。
详细描述各个调用接口参数或者数据接口格式。
3概要设计
3.1模块划分
根据需求分析,该多媒体转发服务器可以划分为服务器配置模块,服务器状态模块,网络模块(即网络TCP,UDP,RTP部分),码率控制模块、转码模块、存储模块等六个模块。
其中,服务器配置主要是设置流媒体服务器的参数,包括服务器监听的端口号,连接设备的上限等。
服务器状态主要是用来查看当前流媒体服务器转发的设备连接数量和状态等信息。
其功能模块图如下
3.2流媒体服务器算法流程图
3.3部署图
3.4组件图
3.5类图
3.6框架时序图
4详细设计
4.1用户界面
流媒体转发服务器界面,软件左边从上到下三块内容依次是连接信息区、支持设备区和命令信息区,右边从上到下依次是时钟区和按钮区。
按钮区有开始、停止、配置和退出四个按键。
连接信息区有连接通道数和连接客户端数信息。
支持设备区显示设备的编号以及对应的设备类型。
在命令信息区显示操作,以及对应的客户地址、客户端口、时间。
若要退出程序,必须要先停止服务器。
在配置界面里可以填入服务器监听端口,同时连接设备上限,每个视频支持的用户上限。
在弹出的对话框填入服务器的IP地址和端口号。
4.2类图
Codec转码
Storage存储
4.3类的结构和接口
TCPNet类
boolStartTcpNet(unsignedshortport,unsignedintinitConnNum,
unsignedintworkThreadNum,boolbBindLocal/*127.0.0.1orINADDR_ANY*/);
voidStopTcpNet();
voidRegisterTcpClientReceiveCallBack(TCPRECEIVEBUFFERCALLBACKreceiveCallback);
voidRegisterTcpSocketErrorCallBack(TCPSOCKERRORCALLBACKsocketErrCallback);
boolSendTcpBuffer(unsignedlongip,unsignedshortport,
boolReleaseConnection(unsignedlongip,unsignedshortport);
UDPNet类
unsignedshortGetUdpNetPort();
boolStartUdpNet(unsignedshortport,boolbBindLocal/*127.0.0.1orINADDR_ANY*/);
voidStopUdpNet();
voidRegisterUdpClientReceiveCallBack(UDPRECEIVEBUFFERCALLBACKreceiveCallback);
boolSendUdpBuffer(unsignedlongip,unsignedshortport,
unsignedchar*buffer,unsignedlonglen);
netmsg类
enumNetMsg:
unsignedchar{
//messages
CLIENT_PC_LOGIN=0,
CLIENT_PC_LOGOUT=2,
CLIENT_PC_STREAM_START=4,
CLIENT_PC_STREAM_STOP=6,
CLIENT_PC_CONTROL_PTZ=8,
CLIENT_PC_STREAM_QUALITY=10,
CLIENT_PC_STREAM_SWITCH=12,
CLIENT_PC_STREAM_RESEND=14,
CLIENT_PC_LOGIN_REPLY=16,
CLIENT_PC_LOGOUT_REPLY=18,
CLIENT_PC_STREAM_START_REPLY=20,
CLIENT_PC_STREAM_STOP_REPLY=22,
CLIENT_PC_TCP_CONNECTION_BREATHE=24,
CLIENT_PC_TCP_CONNECTION_BREATHE_REPLY=26,
};
#ifndefMAX_USERNAME_LENGTH
#defineMAX_USERNAME_LENGTH32
#endif
#ifndefMAX_PASSWORD_LENGTH
#defineMAX_PASSWORD_LENGTH64
#endif
typedefstructClientPcLogin{
CHAR_username[MAX_USERNAME_LENGTH];
CHAR_password[MAX_PASSWORD_LENGTH];
ULONG_Ip;
USHORT_tcpPort;
USHORT_udpPort;//pc'sudpnetport
}CLIENTPCLOGIN,*LPCLIENTPCLOGIN;
typedefstructClientPcLogout{
CHAR_username[MAX_USERNAME_LENGTH];
ULONG_Ip;
USHORT_tcpPort;
}CLIENTPCLOGOUT,*LPCLIENTPCLOGOUT;
typedefstructClientPcStreamStart{
CHAR_username[MAX_USERNAME_LENGTH];
ULONG_Ip;
USHORT_tcpPort;
GUID_dasId;
GUID_streamId;
}CLIENTPCSTREAMSTART,*LPCLIENTPCSTREAMSTART;
typedefstructClientPcStreamStop{
CHAR_username[MAX_USERNAME_LENGTH];
ULONG_Ip;
USHORT_tcpPort;
GUID_dasId;
GUID_streamId;
}CLIENTPCSTREAMSTOP,*LPCLIENTPCSTREAMSTOP;
typedefstructClientPcControlPtz{
CHAR_username[MAX_USERNAME_LENGTH];
GUID_dasId;
GUID_streamId;
INT_command;
INT_step;
}CLIENTPCCONTROLPTZ,*LPCLIENTPCCONTROLPTZ;
typedefstructClientPcStreamQuality{
CHAR_username[MAX_USERNAME_LENGTH];
GUID_dasId;
GUID_streamId;
INT_quality;
}CLIENTPCSTREAMQUALITY,*LPCLIENTPCSTREAMQUALITY;
typedefstructClientPcStreamSwitch{
CHAR_username[MAX_USERNAME_LENGTH];
GUID_dasId;
GUID_streamId;
}CLIENTPCSTREAMSWITCH,*LPCLIENTPCSTREAMSWITCH;
typedefstructClientPcStreamResend{
ULONG_pcIp;
USHORT_pcTcpPort;
GUID_streamId;
UINT_frameSeq;
std:
:
list
}CLIENTPCSTREAMRESEND,*LPCLIENTPCSTREAMRESEND;
typedefstructClientPcLoginReply{
ULONG_pcIp;
USHORT_pcPort;
INT_ret;
USHORT_pcTcpPort;
USHORT_udpNetPort;//server'sudpnetport
bool_bResendStream;
}CLIENTPCLOGINREPLY,*LPCLIENTPCLOGINREPLY;
typedefstructClientPcLogoutReply{
ULONG_pcIp;
USHORT_pcPort;
INT_ret;
}CLIENTPCLOGOUTREPLY,*LPCLIENTPCLOGOUTREPLY;
typedefstructClientPcStreamStartReply{
ULONG_pcIp;
USHORT_pcPort;
GUID_streamId;
INT_ret;
}CLIENTPCSTREAMSTARTREPLY,*LPCLIENTPCSTREAMSTARTREPLY;
typedefstructClientPcStreamStopReply{
ULONG_pcIp;
USHORT_pcPort;
GUID_streamId;
INT_ret;
}CLIENTPCSTREAMSTOPREPLY,*LPCLIENTPCSTREAMSTOPREPLY;
typedefstructClientPcTcpConnectionBreathe{
ULONG_pcIp;
USHORT_pcTcpPort;
}CLIENTPCTCPCONNECTIONBREATHE,*LPCLIENTPCTCPCONNECTIONBREATHE;
typedefstructClientPcTcpConnectionBreatheReplay{
ULONG_pcIp;
USHORT_pcTcpPort;
}CLIENTPCTCPCONNECTIONBREATHEREPLY,*LPCLIENTPCTCPCONNECTIONBREATHEREPLY;
typedefstructUdpNetMsg{
ULONG_ip;
USHORT_port;
LPBYTE_buffer;
DWORD_len;
}UDPNETMSG,*LPUDPNETMSG;
typedefstructClientOffline{
ULONG_ip;
ULONG_port;
INT_errCode;
}CLIENTOFFLINE,*LPCLIENTOFFLINE;
Storage类
classStore_Attemper:
publicACE_Task
{
public:
Store_Attemper();
~Store_Attemper();
staticvoidinsert_test_data();
virtualintopen(void*);
virtualintsvc(void);
virtualinttask_exit_handle(intrid);
virtualinthandle_timeout(constACE_Time_Value&t,constvoid*v);
virtualinthandle_close(ACE_HANDLE=ACE_INVALID_HANDLE,
ACE_Reactor_Maskmask=ACE_Event_Handler:
:
ALL_EVENTS_MASK);
public:
staticmap
private:
inttimer1_;
};
Encode类
classEncoder_Handler:
publicACE_Task
//,publicSource_Interface
{
public:
Encoder_Handler(intsid,intdid);
~Encoder_Handler();
virtualintopen(void*);
//virtualinthandle_signal(int,siginfo_t*=0,uconex_t*=0);
virtualintsvc(void);
virtualintclose(u_longflag);
virtualinthandle_input(ACE_HANDLE=ACE_INVALID_HANDLE);
virtualinthandle_timeout(constACE_Time_Value&t,constvoid*v);
virtualinthandle_close(ACE_HANDLE=ACE_INVALID_HANDLE,
ACE_Reactor_Maskmask=ACE_Event_Handler:
:
ALL_EVENTS_MASK);
virtualintremove_source();
virtualintregister_source();
private:
intrate_;
intstate_;
intcount_;
intsrc_id_;
intdst_id_;
intframe_type_;
intframe_rate_;
intbegin_flag_;
intend_flag_;
intdata_type_;
inttimer1_;
inttimer2_;
}
4.4算法
虽然基于IP协议的网络可以允许对大量结点的访问,但是由于用户每时每刻都在竞争带宽,在所需要的带宽比实际连接的容量搞的时候,就会出现网络拥塞,传输错误。
常见的传输错误有:
数据包被损坏,数据流在传输的过程中的顺序被打乱,接收方收到重复的数据包以及数据包的完整性进行验证,所以所有被损坏的数据包在到达用户之前都已经被丢弃。
而在数据链路层以上发生的数据包的损坏仅出现在网络出现故障的时候,所以数据包的损坏大部分都是表现为数据包的丢失。
因为网络状况的不断变化,阻塞随时发生。
而流媒体技术的主要优势在于它减少了用户的等待时间。
同时支持类似实况转播的媒体传播方式。
一个完整的流媒体传输解决方案大致包括以下的内容:
内容采集,音频视频捕获和压缩编码,内容存储和转发,服务器管理和用户管理等。
对于一个基于TCP/IP网络的流媒体传输系统,如果仅仅满足于流媒体能在网络上传输,那是远远不够的。
由于视频源众多,情况各异,客户所需要的流媒体传输数据往往会彼此或者和其他系统争用带宽。
如果只有一两个视频源,情况还可以忍受,但是如果视频源超过一定数目,需要看视频的用户又很多的话,局面就会混乱不堪。
后果就是质量下降,延迟,停滞,甚至造成系统瘫痪。
这是设计软件不能接受的。
为了解决网络带宽和视频服务器自身对硬件和图像传输要求的限制,在客户端设计了流媒体转发服务器。
流媒体转发服务器通过网络获取视频流,同时转发给请求的用户,可以节省带宽资源。
一个流媒体转发服务器可以并发响应多个用户的请求,可以运用P2P网络技术,各个客户端便是节点,收到视频流也可以向其他节点提供视频流的传输,并且节点的退出和增加并不影响整个网络的正常工作,其功能实现的算法是:
首先,创建一个TCP/UDP套接字并且将其绑定到所提供服务的地址上,第二步就是反复调用接收模块,接收来自客户的是视频数据的请求报告,根据其类型做出响应。
对新实时客户的请求,把客户地址添加到实时服务的客户列表中,对已经在服务中的客户则调整服务。
第三步,调用流媒体数据接口函数,获取用户指定的通道的实时视频流,同时创建一个新的线程,将获取的视频实时数据转发给请求的用户。
本文设计的流媒体转发服务器,在代码中,主进程封装在NETProxy类中,整个程序有一个NetProxy对象。
NetProxy对象对每个请求创建子进程,子进程中创建NetClientSession类对象。
NetClientSession类用于处理用户的网络请求,包括TCP,UDP,RTP等。
ProxyMediaSession封装了用户请求的流媒体。
媒体中每一路网络数据由ProxyMediaSession封装,该类同时完成TCP传输。
4.5数据网络传输
为了让终端之间能够顺利的连接通信,需要在网络上传输各种数据,包括控制、语音、视频、文本数据。
其中控制包发送的消息内容有,连接请求、同意、拒绝以及断开连接信息。
为了方便区分它们之间的不同,分别给他们设置数值:
#defineTYPE_CONTROL11
#defineTYPE_AUDIO12
#defineTYPE_VIDEO13
#defineTYPE_TEXT14
在发送时分别使用不同的端口号:
#definePORT_CONTROL6000
#definePORT_AUDIO6002
#definePORT_VIDEO6004
#definePORT_TEXT6006
由于控制报文有不同的四种类型,为了方便区别,使用数值:
#defineMESG_CONNECT101
#defineMESG_DISCONNECT102
#defineMESG_ACCEPT103
#defineMESG_REJECT104
本程序是主要完成语音视频数据的传输功能,所以使用UDP相比TCP更有优势,因为此处更注重的是传输的实时性,而不是传输的准确性,故创建socket时使用的是SOCK_DGRAM类型:
voidDSocket:
:
CreateSocket(intport,intdtype)
{
this->Create(port,SOCK_DGRAM);
type=dtype;
}
4.5.1数据包发送
控制报文有多种控制内容需要发送,所以将数据包的第一个字节设置为控制类型,第二字节内容为主机名字节长度,其余为主机名:
Type:
1byte
Lengthofhostname:
1byte
Hostname:
//发送控制报文数据到远方
voidDSocket:
:
SendControlMessage(inttype,char*address)
{
chardata[1000];
intn;
data[0]=type;
n=strlen(localname);
data[1]=n;
memcpy(&data[2],localname,n);
if(address==NULL)
{
SendTo(data,n+2,PORT_CONTROL,remoteaddress);
}
else
{
SendTo(data,n+2,PORT_CONTROL,address);
}
}
//发送音频数据包到远方
voidDSocket:
:
SendAudioData(unsignedchar*data,intlength)
{
SendTo(data,length,PORT_AUDIO,remoteaddress);
}
//发送视频数据包到远方
voidDSocket:
:
SendVideoData(unsignedchar*data,intlength)
{
SendTo(data,length,PORT_VIDEO,remoteaddress);
}
//发送文本数据包到远方
voidDSocket:
:
SendTextData(unsignedchar*data,shortlength)
{
unsignedchar*packet=newunsignedchar[length+500];
intn;
//区分为文本数据
packet[0]=TYPE_TEXT;
//主机名长度
n=strlen(localname);
packet[1]=n;
//主机名
memcpy(&packet[2],localname,n);
//数据的大小
packet[n+2]=(unsignedchar)length;
packet[n+3]=(unsignedchar)(length>>8);
//数据内容
memcpy(&packet[n+4],data,length);
SendTo(packet,n+4+length,PORT_TEXT,remoteaddress);
}
4.5.2数据包接收
任何数据到达本机时,调用同一个函数errcode(),由于在创建socket时是在不同的端口上进行的,所以可以根据数据包的类型值来直接区分,并对应进行不同的操作:
假若为contro
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 性能 多媒体 转发 服务器 设计