每天总结自己编写代码中所犯的错误,并反思出错的原因;总结所获取的经验;归纳编程的基本原则。
文档的编写:
以后所有提交的文档的文件名中写三部分:文件名-姓名-日期。文件名要简洁,语义清晰。这样文档多了容易查找程序开发
变量:命名规范函数的编写
注释:
错误处理 函数参数检查
内存管理
版本控制
日志系统
阅读以下书籍:
《C++ Primer》
《Effective C++》
以下几点是在程序开发过程中实际发现的应当遵守的地方。
- 错误处理:
- 有限状态自动机是保证 编程正确性,安全性的 有力武器。比如在网络编程时,状态记录有助于排错。
使满足状态的包才会被处理,不满足状态变迁的包将被丢弃。如只有登陆后才进行继续的处理。防止恶意包和欺骗行为。
任何不满足格式要求的包将被抛弃。
- 一定要对收到的数据包的每一个字段进行长度检查,不满足长度要求得数据包进行抛弃。
- 对数据包的源地址进行检查,不满足长度要求进行抛弃。
eyeBeam,语音和视频从不同的IP发送是不可以接受的。nettalk中途更换语音的发送IP也是不可以接受的。其语音包的负载大小:也必须是20个字节:20ms的数据。
对于大于20的语音包,直接抛弃。如我们的nettalk.当视频RTP包发送到语音RTP包的接收端口时,由于没有做长度检查,导致内存越界,使得接收SOcket被改写。。
指针越界问题:使用必要的边界检查。预防缓冲区溢出漏洞
如果可能,进行必要的协议分析,以保证程序的正确性。
2,函数必须有两种返回值,1),程序是否正确执行,2),程序执行的结果
错误检查是保证程序健壮性的必要因素。
3,能用if条件判断的,不使用异常。
4,对于两种不同的协议,使用不同的端口进行处理。RTPRelay的命令包和RTP数据流应当分开。
5, 遵守最基本的命名规范,成员变量全部为private, 以m_*开头。。变量名应当容易理解,见名知意。
不要使用什么 dd ,zhu等看不出含义的名字。
变量的作用域越大,变量的命名应当越谨慎。
如有可能,不要使用全局变量。
禁止使用如下方式:
#define PORT 18800
原因:很有可能出现宏重定义,且名字也不清晰。
6,动态内存的管理:尽量少用。
使用内存检查工具检查内存内存泄露,如valgrind,但不要完全把希望寄托到检查工具上。
编写内存安全的代码是程序开发人员的责任。Win32的RuntimeChecker
使用相匹配的new/delete
char *pbuf = new char[len+1];
delete [] pbuf;
使用valgrind:
[hongleij@hustp2psrv bin]$ valgrind -v --leak-check=full ./meridianClient
==11443== 1 errors in context 7 of 9:
==11443== Conditional jump or move depends on uninitialised value(s)
==11443== at 0x418AE16F: pthread_mutex_init (in /lib/libpthread-2.5.so)
==11443== by 0x418128DC: pthread_mutex_init (in /lib/libc-2.5.so)
==11443== by 0x4010877: CMeridianThread::CMeridianThread() (CriticalSection.h:55)
==11443== by 0x4015A80: StartRTPRelay (RTPMain.cpp:17)
==11443== by 0x804868B: main (Client.cpp:7)
使用必要的初始化函数:
CriticalSection()
{
pthread_mutexattr_t mutex_attribute;
pthread_mutexattr_init(&mutex_attribute);//add jianghonglei 081010
pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex_, &mutex_attribute);
pthread_mutexattr_destroy(&mutex_attribute);//add jianghonglei 081010
}
7,使用CVS或SVN服务器来进行版本控制,并对文件目录的设置进行规范。
维护以下部分:
源代码,文档,参考资料
尤其是跨平台程序的开发。win工程文件使用单独的目录,代码与配置清晰
设置的目的不仅仅维护代码,而且包括文档,
每个用户有不同的权限,每次提交必须添加注释,表明这次修改的目的,和测试结果
8, 编写可复用的代码。相当于对代码进行了多次测试。品质更容易保障。
9,统一的日志输出格式:正确区分编程错误,网络IO错误,和异常情况。可以支持模块化调试。
如只输出某个或某几个模块的调试信息。
1), 调试信息以模块名开头如:KAD
2), 并区分错误信息的等级,类型:
3), 输出时间
10:绝不允许出现类似如下的情况:
char * pBuf =NULL;
std::cout<<pBuf;
11: 不允许出现函数需要返回值却没有返回值 的情况,例如
int func()
{
if(true)
{
return 1;
}
//this place should add return !!!
}
最好保证函数有单一的入口和出口。
12: 调用网络相关函数,必须对错误情况/返回值进行检查。不允许不做检查的情况出现。!!!
sendto, recvfrom
ReceiverAddr.sin_family = AF_INET;//IMOPTANT!!!!
ReceiverAddr.sin_port=htons(18888);
ReceiverAddr.sin_addr.s_addr=inet_addr(iter->ip);
13:为防止端口冲突,程序中所有端口在同一文件中配置。
14: 每行代码不超过80个字。目的:在比较时容易忽略掉。
15: C++异常的处理,如果使用,应当尽可能在最内层处理。
16:数据一致性是程序正确性最根本的保证。应当充分尊重数据库的黄金法则:“同一个意思只表达一次”。至少包括两层意思:代码简练,少冗余。
17.不得做如下调用,在同一函数中调用2次inet_ntoa函数;
RTPAdd(localIP,AVIO_PORT,
inet_ntoa(pMgr->m_CalleeAddr.sin_addr),ntohs(pMgr->m_CalleeAddr.sin_port),
inet_ntoa(pMgr->m_SuperNode.sin_addr),MERIDIAN_COMMAND_PORT
,NULL,NULL,GetTickCount());
18: 调用sendto()时,必须是系统支持的库函数
void CAVIOMgr::OnRelayCommand(const char * ppc,int recvPackLen,SOCKADDR *recvAddr)
{
SOCKADDR_IN pingAddr ;//TODO 为什么必须要进行一次转换??
memcpy(&pingAddr,recvAddr,sizeof(SOCKADDR_IN) );
int bytesSended = m_Socket.SendTo((const char *)tmpBuf.GetBufferPrt(),tmpBuf.GetWritePos(),(SOCKADDR*)&pingAddr);
//否则会产生10047 WSAEAFNOSUPPORT 错误
}
19,select的使用:
if( FD_ISSET( pMgr->m_Socket.GetSocket(), &writefds ) )
{
pMgr->processPackSend();
}
if( FD_ISSET( pMgr->m_Socket.GetSocket(), &readfds ) ) //不是 else if
{
}
20:创建项目的Bug错误列表。
表明程序的修订状况。
21: 出现Stack错误。
在调试状态没有问题,不调试出现问题。
原因:某些变量在使用时没有初始化。。
22: 保证程序的健壮
程序的
================================
l99.com -> 相机照片,时间,GPS数据整合 -〉应用
未来的信息搜索 --〉 依时间轴依次排列,关联度(where ,what,time),
拼车网 --〉撮合率 凡事预则立 (临时需求)
火车票
游戏组队
信息的过滤和筛选--〉有用信息,BBS,
51758855--719
但>2M*7K=
实际用户数:license
>30-40 CPS
2get 1put 30*2 =60读
用户数据量:IMS标准 3GPP 30K
CSF
话单
DNS 解析:
nokia sip stack
ims mar maa
没有评论:
发表评论