分析一个通用的rtsp server实现过程基础模块
2017-08-05 16:10
741 查看
本文分析先分析common模块:
common 模块有tcp,udp,socket,mutex类以及cyclebuffer类,StdAfx类
1. mutux类实现,这里的类实现的方法有点冗余,源码如下,
2. Cyclebuffer类,这个作为一个环形缓冲,可以参考前面我写的的java的双缓冲文章,基本的思路都是有的,这里直接给出另外的write和read的C++实现方式,这里有个技巧需要重新计算get_free_space的空间,然后重新给读和写的位置赋值。
write函数如下:
read函数也是一样的,和上面一样的架构!
从这两段的代码逻辑可以看出,简单的问题复杂化了,其实只要根据write,read和start,end的位置就可以写出具体的读写buffer了,参考前面java ringbuffer修改,相信也不是太难。当然这里可以看出,有一个地方需要锁的地方,就是:
这个函数,read和write不同线程,同时调用的话,会打乱write和read的位置,里面最好加一把锁!
3. tcp/ip 相关base类:
直接看bass socket类,这里才是核心的架构,
如果需要重构的话,最好这里全部是虚函数,然后重新写一个类来实现,如select函数的东西,将socket里面的基本通信方式全部补上,这里比较合理。
这里m_socket就是上层打开socekt传过来的,因为所有后面的读写全部调用这里的方式实现,统一节省资源,
同时不需要锁,因为m_socket唯一性决定!
然后看tcp类的实现方式:
这里只有open和connect函数,明显定义的不够好,并且从tcp.cpp可以看出:
open函数里面包含了bind的函数,耦合性过强,建议分开单独成函数,使架构更加清晰!
接下来看下UDP类的实现,因为数据都是rtp包发送,而rtp是通过udp来实现,因此需要实现下面的方式,来交互数据
这里就read和write函数会call子类的读写函数,当然open和上面的一样的模式,建议后期修改!
当然tcp和udp的在open的都是,可以设置一系列等参数,
用setsockopt来设置,这里就不详细的介绍了!
4. 当然为了保存兼容想,需要单独定义个类,StdAfx类
用来兼容命名的统一性,如下:
因此,这个架构就将上面的基础组件搭建好,后面就需要根据这个做具体的逻辑处理任务!
接下来,进一步介绍rtsp的相应整体架构流程,对于太细的细节不做过多的详述!
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实现采集模块
- Sql server Insert执行的秘密(上)一个最简单的INSERT分析 执行过程
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为(转)
- go: 一个通用log模块的实现
- tomcat架构分析(connector BIO 实现)——serverSocket即在connector模块创建
- node.js基础模块http、网页分析工具cherrio实现爬虫
- 使用WIN32汇编语言实现一个基本windows窗口的过程分析
- 一个通用的分页存储过程实现-SqlServer(附上sql源码,一键执行即刻搭建运行环境)
- 一个RtspServer的设计与实现和RTSP2.0简介
- 一个简单的hibernate java project实现过程(MS Sql Server)
- 一个分析“文件夹”选择框实现方法的过程
- 项目管理实战之团队管理 对团队的管理需要重视以下几个方面 一个系统不仅需要优秀的分析和设计,更需要一个良好的过程将其从蓝图转化为实现。这个过程中最重要的是对团队的管理,也就是人的管理
- 一个RtspServer的设计与实现和RTSP2.0简介
- node.js基础模块http、网页分析工具cherrio实现爬虫
- node.js基础模块http、网页分析工具cherrio实现爬虫
- 学习Java基础的一些知识(2)实现一个Java程序的过程
- 使用WIN32汇编语言实现一个基本windows窗体的过程分析