分析一个通用的rtsp server实现过程基础模块
来源:互联网 发布:如何删除部落冲突数据 编辑:程序博客网 时间:2024/06/06 23:50
本文分析先分析common模块: common 模块有tcp,udp,socket,mutex类以及cyclebuffer类,StdAfx类
1. mutux类实现,这里的类实现的方法有点冗余,源码如下,
class TLock{ public: TLock( void ) { pthread_mutexattr_t mattr; pthread_mutexattr_init( &mattr ); pthread_mutex_init( &m_mutex, &mattr ); }; virtual ~TLock( void ) { pthread_mutex_lock( &m_mutex ); pthread_mutex_unlock( &m_mutex ); pthread_mutex_destroy( &m_mutex ); }; virtual void Lock( void ) { pthread_mutex_lock( &m_mutex ); }; virtual void UnLock( void ) { pthread_mutex_unlock( &m_mutex ); }; protected: private: pthread_mutex_t m_mutex;};class ATLock{ public: ATLock( TLock* pTLock ) { m_pTLock = pTLock; m_pTLock->Lock(); }; ATLock( TLock& lock ) { m_pTLock = &lock; m_pTLock->Lock(); }; virtual ~ATLock() { m_pTLock->UnLock(); }; protected: TLock* m_pTLock;};这里的代码需要建议修改,建议可以参考比较规范的定义类的方式,可以复用和单独提供处理作为库,给其他模块调用,建议用下面的方式,具体的实现,需要读者来参考上面的补上相应的函数就ok了,就不贴出了!
class thread_mutex{ public: thread_mutex(); ~thread_mutex(); public: void lock(); void unlock(); private: pthread_mutex_t m_mutex;};
2. Cyclebuffer类,这个作为一个环形缓冲,可以参考前面我写的的java的双缓冲文章,基本的思路都是有的,这里直接给出另外的write和read的C++实现方式,这里有个技巧需要重新计算get_free_space的空间,然后重新给读和写的位置赋值。
write函数如下:
int cycle_buffer::write( const unsigned char* buffer, int len ){ unsigned int free_space_size = 0; unsigned int writed_size = len; /* 修改获取相应的space 的信息*/ unsigned char* pRPos = NULL; unsigned char* pWPos = NULL; free_space_size = get_free_space( &pRPos, &pWPos ); if ( free_space_size < len ) { return 0; } if ( m_flag_buffering_data_ok != 1 ) { //没有缓冲满,需要进行计数 m_buffering_write_count += len; if ( m_buffering_write_count > m_bufferingsize ) { //已经缓冲满 m_flag_buffering_data_ok = 1; } } if ( ( m_cb.end - pWPos + 1 ) < len ) { /*出现翻转的情况*/ writed_size = m_cb.end - pWPos + 1; memcpy( pWPos, buffer, writed_size ); memcpy( m_cb.begin, buffer + writed_size, len - writed_size ); } else { memcpy( pWPos, buffer, writed_size ); } int offset = ( ( pWPos - m_cb.begin ) + len ) % m_cb.size; m_cb.wpos = m_cb.begin + offset; return len;}
read函数也是一样的,和上面一样的架构!
int cycle_buffer::read( unsigned char* buffer, int len ){ if ( m_flag_buffering_data_ok != 1 ) { //没有缓冲满,无法进行读 return 0; } unsigned int valid_data_size = 0; unsigned int read_size = len; /* 修改获取相应的space 的信息,主要的原因就是有一个是需要空出来的*/ unsigned char* pRPos = NULL; unsigned char* pWPos = NULL; valid_data_size = m_cb.size - get_free_space( &pRPos, &pWPos ) - 1; if ( valid_data_size < len ) { return 0; } if ( ( m_cb.end - pRPos + 1 ) < len ) { /*出现翻转的情况*/ read_size = m_cb.end - pRPos + 1; memcpy( buffer, pRPos, read_size ); memcpy( buffer + read_size, m_cb.begin, len - read_size ); } else { memcpy( buffer, pRPos, read_size ); } int offset = ( ( pRPos - m_cb.begin ) + len ) % m_cb.size; m_cb.rpos = m_cb.begin + offset; return len;}
从这两段的代码逻辑可以看出,简单的问题复杂化了,其实只要根据write,read和start,end的位置就可以写出具体的读写buffer了,参考前面java ringbuffer修改,相信也不是太难。当然这里可以看出,有一个地方需要锁的地方,就是:
get_free_space
这个函数,read和write不同线程,同时调用的话,会打乱write和read的位置,里面最好加一把锁!
3. tcp/ip 相关base类:
直接看bass socket类,这里才是核心的架构,
class Socket{ public: virtual int Write( PBYTE pBuffer, int writeSize, UINT nTimeOut = 2000000 ); // 2 sec virtual int Read( BYTE* pBuffer, int readSize, UINT nTimeOut = 2000000 ); // 2 sec protected: int Select( int mode, int timeoutUsec ); SOCKET m_Socket; SOCKADDR_IN m_BindAddr; SOCKADDR_IN m_ConnectAddr;};这里可以看出,所有的网络通信是继承这个基础类,不过从整体架构感觉这里的socket类有点不规范,
如果需要重构的话,最好这里全部是虚函数,然后重新写一个类来实现,如select函数的东西,将socket里面的基本通信方式全部补上,这里比较合理。
这里m_socket就是上层打开socekt传过来的,因为所有后面的读写全部调用这里的方式实现,统一节省资源,
同时不需要锁,因为m_socket唯一性决定!
然后看tcp类的实现方式:
class Tcp : public Socket{ public: virtual BOOL Open( PCSTR bindIp = "", INT bindPort = 0 ); virtual BOOL Connect( PCSTR connectIp, INT connectPort ); protected: BOOL m_isConnect;};
这里只有open和connect函数,明显定义的不够好,并且从tcp.cpp可以看出:
open函数里面包含了bind的函数,耦合性过强,建议分开单独成函数,使架构更加清晰!
接下来看下UDP类的实现,因为数据都是rtp包发送,而rtp是通过udp来实现,因此需要实现下面的方式,来交互数据
class Udp : public Socket{ public: virtual BOOL Open( string bindIp = "", int bindPort = 0 ); virtual BOOL Connect( string connectIp, int connectPort ); virtual int Read( BYTE* pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000 ); virtual int Write( PBYTE pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000 ); protected: BOOL m_isConnect;};
这里就read和write函数会call子类的读写函数,当然open和上面的一样的模式,建议后期修改!
当然tcp和udp的在open的都是,可以设置一系列等参数,
用setsockopt来设置,这里就不详细的介绍了!
4. 当然为了保存兼容想,需要单独定义个类,StdAfx类
用来兼容命名的统一性,如下:
typedef unsigned char BYTE;typedef unsigned short WORD;typedef BYTE* PBYTE;typedef const char* PCSTR;typedef unsigned long ULONG;typedef void* PVOID;
因此,这个架构就将上面的基础组件搭建好,后面就需要根据这个做具体的逻辑处理任务!
接下来,进一步介绍rtsp的相应整体架构流程,对于太细的细节不做过多的详述!
- 分析一个通用的rtsp server实现过程基础模块
- 分析一个通用的rtsp server实现过程串联模块
- 分析一个通用的rtsp server实现过程发送模块
- 分析一个通用的rtsp server实现采集模块
- 分析一个通用的rtsp server实现过程总纲
- go: 一个通用log模块的实现
- SQL Server 一个比较通用的分页存储过程
- C# 通用存储过程ORMapping的实现 [基础篇]
- Java 通用存储过程ORMapping的实现 [基础篇]
- SQL Server通用分页存储过程:利用SQL Server未公开的存储过程实现
- SQL Server通用分页存储过程:利用SQL Server未公开的存储过程实现
- SQL Server通用分页存储过程:利用SQL Server未公开的存储过程实现
- RTSP服务器端实现的一个问题
- Sql Server通用的分页存储过程
- 简单完整的一个 rtsp 交互过程 live555-openRTSP
- 一个通用dao的实现
- 一个通用dao的实现
- IEditableObject的一个通用实现
- 利用Python爬取可用的代理IP
- Linux 常见文件后缀解压命令
- 微信开发刷新网页code过期
- git 常见问题 及 操作
- Mybatis总体架构分析
- 分析一个通用的rtsp server实现过程基础模块
- 如何编写makefile文件
- python中set和list的操作
- 重建二叉树
- 日常学习2017.8.5
- xml基础及解析案例
- Netty网络聊天室之会话管理
- POJ1236---Network of Schools (强连通分量,缩点,Tarjan算法)
- 传智_Springmvc+Mybatis由浅入深全套视频教程(燕青)-mybatis笔记(两天)(2017年8月5日16:09:55)