当前位置: 首页 > news >正文

网站建设注册门户网站的优点

网站建设注册,门户网站的优点,房产发布网站建设,怎样网站seo文章目录1.函数重载#xff1a;writetofile()#xff0c;Ctrue和false#xff0c;C0和非02.类和对象#xff1a;vprintf构造函数#xff1a;对成员变量初始化析构函数#xff1a;一个类只有一个#xff0c;不允许被重载3.引用#xff1a;C中取地址#xff0c;C中… 文章目录1.函数重载writetofile()Ctrue和falseC0和非02.类和对象vprintf构造函数对成员变量初始化析构函数一个类只有一个不允许被重载3.引用C中取地址C中引用。引用就像起别名typedef宏define。对引用的操作与对变量直接操作一样4.string类string strstrstr.c_str()5.vector容器vector与string类一样属于STL6.类继承class派生类名public基类名7.类多态子类必重写父类纯虚函数8.socketsend/recv8.1 简单文件传输CTcpClientCTcpServer8.2 文件下载模块不建议将tcpgetfile.cpptcpfileserver.cpp反过来虽然全双工但会出现连不上服务器被上网行为审计系统拦截8.3 高性能网络服务多线程数据库连接池多线程每启一个线程都要连数据库耗资源9.进程fork()ps -ef (同-aux) | more10.信号signal, EXITjps10.1 捕捉信号ctrlc210.2 捕捉信号kill -9910.3 捕捉信号kill1510.4 程序后台运行两种方法ctrlc无法中止用killall book1或kill 进程号。if fork()0return 0 父进程退出1._public.h2._public.cpp3._cmpublic.h4._ooci.h5._ooci.cpp1.函数重载writetofile()Ctrue和falseC0和非0 C动态内存分配在C语言中动态分配内存用malloc()函数释放内存用free()函数。C中new和delete。C函数重载C中不允许函数同名如下 以上为C写法下面为C函数重载写法。函数重载规则1.函数名必须同2.参数列表必须不同。C是如何做到函数重载的C代码在编译时会根据参数列表对函数进行重命名。 2.类和对象vprintf 上面完整下面两行中下行是上行改进效果一样但没有涉及类和对象。 上面完整下面结构体升级为类。 下面为三种show函数重载实现如下字符串理论上可定义为char name[10]但在函数里字符串也只能传地址所以只能定义为char * name。char name不行char类型是单个字符调用时直接给字符串值。 下面为三种Show调用。 构造函数对成员变量初始化 CFile是类CFile()是函数。 如下两个构造函数该类对象被创建时编译系统对象分配内存空间并自动调用该构造函数由构造函数完成成员的初始化工作属于成员函数。 析构函数一个类只有一个不允许被重载 3.引用C中取地址C中引用。引用就像起别名typedef宏define。对引用的操作与对变量直接操作一样 引用的声明方法类型标识符 引用名目标变量名如int a; int raa; 定义了引用ra它是变量a的引用即别名。引用可以用const修饰表示只读用这种方式声明的引用不能通过引用对目标变量的值进行修改。 4.string类string strstrstr.c_str() C中以0结尾的字符数组表示字符串定义后大小不可变C中string随着存放字符长度自动伸缩不用担心内存溢出。string类是一个模板类位于std命名空间如果不加using namespace std就要用std::string str。 string特性描述函数int size()返回当前字符串大小int length()返回当前字符串的长度void clear()清空字符串。string本质是一个类通过动态分配内存实现对字符串的存储string对象用于存放字符的内存地址是变化的。也就是地址存放的下就不再重新分配存放不下就重新分配地址。 5.vector容器vector与string类一样属于STL 容器的使用1.存放整数 访问容器中元素可以像数组形式一样。 2.存放字符串。 3.存放结构体4.存放类存放字符串中string就是类。 vector其他成员函数1.定位的函数 2.增加元素的函数 3.删除元素的函数 4.判断容器的大小 bool empty()判断容器是否为空 int size()返回容器中元素的个数 5.作业题封装随机数 //此程序用于生成一组随机数, 指定数组范围和是否重复 #include_public.hclass CRand { public:CRand();~CRand();vector int m_val; //m_val容器 bool checkexit(const int aryyval, const int aryysize); // 用于检查是否为重复数据,aryyval为重复的值这函数不单用用于Rand成员函数里void Rand(const int minvalue,const int maxvalue,bool breptrue, const int nog5); //brep为是否允许重复; 默认为允许重复nog指定生成多少个随机数 };//111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 void CRand::Rand(const int minvalue,const int maxvalue,bool brep,const int nog) {int len maxvalue-minvalue;int ii0, itmp0, jtmp0; // ii生成第几个jtmp实际生成共多少个itmp生成的值m_val.clear();if(breptrue) // 允许重复{jtmp nog;for(ii0;iijtmp;ii){itmp rand()%(len1)minvalue; // (0~len)minvalueitmp就是min~max之间的值不是len长度m_val.push_back(itmp); }return; //return是函数直接返回, 也就是结束该函数。//要跳出循环用break, if代码段是不能用break跳出的, 在一个函数内任意位置调用return, 直接退出Rand函数下面代码不执行。}jtmp nog; // 以下为不允许重复 因为没进入if(breptrue)if (noglen) jtmp len 1; // 比如5-14但1到5可以生成5个所以如果nog大于len的话就取len1个前提不允许重复。while(1) {if (jtmp m_val.size()) break; //生成满了跳出循环itmp rand()%(len1)minvalue;if (ii0) // 生成第一个不用管checkexit重不重复{m_val.push_back(itmp);ii;continue;} if (checkexit(itmp,ii) false) continue; // checkexit为false则不允许重复m_val.push_back(itmp); ii;}return; }//11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 bool CRand::checkexit(const int aryyval, const int aryysize) // aryyval重复的值aryysize允许多少个重复 {for (int ii0; iiaryysize; ii){if (aryyval m_val[ii]) return false;}return true; }CRand::~CRand() {m_val.clear(); }CRand::CRand() {struct timeval begin;gettimeofday(begin, 0);srand(begin.tv_usec); }//1111111111111111111111111111111111111111111111111111111111111111111111111111111111 int main() //如何用CRand这个类 {CRand CrtRand;CrtRand.Rand(0, 10, false); // 若false为true允许重复不管范围多少取nog个for(int ii0;iiCrtRand.m_val.size();ii){printf(%d\n,CrtRand.m_val[ii]);} return 0; }6.类继承class派生类名public基类名 如下子类可直接用父类属性和方法。 7.类多态子类必重写父类纯虚函数 8.socketsend/recv 服务端 客户端 1.send函数。 2.recv函数。 1.socket函数 8.1 简单文件传输CTcpClientCTcpServer // 本程序演示采用CTcpClient类实现socket通讯的客户端和文件传输demo13.cpp #include _public.h bool SendFile(int sockfd,char *filename,int filesize); //把文件的内容发送给服务端 int main(int argc,char *argv[]) {if (argc ! 4){printf(\n);printf(Using:./demo13 ip port filename\n\n);printf(Example:./demo13 118.89.50.198 5010 test1.jpg\n\n);printf(本程序演示采用CTcpClient类实现socket通讯的客户端和文件传输。\n\n);return -1;} if (access(argv[3],R_OK) ! 0) //判断文件是否存{printf(file %s not exist.\n,argv[3]); return -1;}int uFileSize0;char strMTime[20],strRecvBuffer[1024],strSendBuffer[1024];memset(strMTime,0,sizeof(strMTime)); //获取文件的时间和大小FileMTime(argv[3],strMTime); uFileSizeFileSize(argv[3]); //获取文件的大小// 把文件的信息封装成一个xml报文发送给服务端memset(strSendBuffer,0,sizeof(strSendBuffer));snprintf(strSendBuffer,100,filename%s/filenamemtime%s/mtimesize%lu/size,argv[3],strMTime,uFileSize);CTcpClient TcpClient;//1111111111111111111111111111111111111111111111111111.向服务器发起连接if (TcpClient.ConnectToServer(argv[1],atoi(argv[2])) false){printf(TcpClient.ConnectToServer(%s,%d) failed.\n,argv[1],atoi(argv[2])); return -1;}//1111111111111111111111111111111111111111112.把文件信息的xml发送给服务端并没有接收服务端回应没必要减少tcp交互次数if (TcpClient.Write(strSendBuffer)false){printf(TcpClient.Write() failed.\n); return -1;}printf(send xml:%s\n,strSendBuffer);printf(send file ...);//111111111111111111111111111111111111111111111111111113.把文件的内容发送给服务端if (SendFile(TcpClient.m_sockfd,argv[3],uFileSize)false){printf(SendFile(%s) failed.\n,argv[3]); return -1;} memset(strRecvBuffer,0,sizeof(strRecvBuffer));//1111111111111111111111111111111111111111111111111114.接收服务端返回的回应报文if (TcpClient.Read(strRecvBuffer)false){printf(TcpClient.Read() failed.\n); return -1;}if (strcmp(strRecvBuffer,ok)0)printf(ok.\n);elseprintf(failed.\n);return 0; }//111111111111111111111111111111111111111111111111113.把文件的内容发送给服务端 bool SendFile(int sockfd,char *filename,int filesize) {int bytes0;int total_bytes0;int onread0;char buffer[1000];FILE *fpNULL;if ( (fpfopen(filename,rb)) NULL ) {printf(fopen(%s) failed.\n,filename); return false;}while (true){memset(buffer,0,sizeof(buffer));if ((filesize-total_bytes) 1000) onread1000; //一次读1000个字节else onreadfilesize-total_bytes;bytesfread(buffer,1,onread,fp); if (bytes 0){if (Writen(sockfd,buffer,bytes) false){printf(Writen() failed.\n); fclose(fp); fpNULL; return false;}}total_bytes total_bytes bytes;if ((int)total_bytes filesize) break;}fclose(fp);return true; }// 本程序演示采用CTcpServer类实现socket通讯的服务端和文件传输demo14.cpp #include _public.h bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename); //接收文件的内容 int main(int argc,char *argv[]) {if (argc ! 3){printf(\n);printf(Using:./demo14 port filename\n\n);printf(Example:./demo14 5010 test2.jpg\n\n); //test2.jpg重新命名printf(本程序演示采用CTcpServer类实现socket通讯的服务端和文件传输。\n\n);return -1;}CTcpServer TcpServer; //1111111111111111111111111111111111111111111111111111.服务端初始化if (TcpServer.InitServer(atoi(argv[1])) false){printf(TcpServer.InitServer(%s) failed.\n,argv[1]); return -1;}//1111111111111111111111111111111111111111111111111112.等待客户端的连接if (TcpServer.Accept() false){printf(TcpServer.Accept() failed.\n); return -1;}//11111111111111111111111111111111111111111113.读取客户端的报文等时间是20秒char strRecvBuffer[1024],strSendBuffer[1024];memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpServer.Read(strRecvBuffer,20)false) {printf(TcpServer.Read() failed.\n); return -1;}printf(recv:%s\n,strRecvBuffer);printf(recv file ...);//111111111111111111111111111111111111111111114.接收文件的内容memset(strSendBuffer,0,sizeof(strSendBuffer));if (RecvFile(strRecvBuffer,TcpServer.m_connfd,argv[2])true){strcpy(strSendBuffer,ok);printf(ok.\n);}else{strcpy(strSendBuffer,failed);printf(failed.\n);}//1111111111111111111111111111111111111111111111111115.接收ok后向客户端返回响应内容if (TcpServer.Write(strSendBuffer)false) {printf(TcpServer.Write() failed.\n); return -1;}printf(send:%s\n,strSendBuffer);return 0; }//1111111111111111111111111111111111111111111111111114.接收文件的内容 bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename) {int ufilesize0;char strmtime[20]; memset(strmtime,0,sizeof(strmtime));// 获取待接收的文件的时间和大小GetXMLBuffer(strRecvBuffer,mtime,strmtime);GetXMLBuffer(strRecvBuffer,size,ufilesize);FILE *fpNULL;if ( (fpfopen(strfilename,wb)) NULL){printf(create %s failed.\n,strfilename); return false;}int total_bytes0;int onread0;char buffer[1000];while (true){memset(buffer,0,sizeof(buffer));if ((ufilesize-total_bytes) 1000) onread1000; //根据文件大小知道文件接下来读取多少内容else onreadufilesize-total_bytes;if (Readn(sockfd,buffer,onread) false){printf(Readn() failed.\n); fclose(fp); fpNULL; return false;}fwrite(buffer,1,onread,fp); //一次读1个字节读onread次total_bytes total_bytes onread;if ((int)total_bytes ufilesize) break;}fclose(fp);// 读完后重置文件原始的时间不是本地接收生成的时间UTime(strfilename,strmtime);return true; }如下传二进制文件。 8.2 文件下载模块不建议将tcpgetfile.cpptcpfileserver.cpp反过来虽然全双工但会出现连不上服务器被上网行为审计系统拦截 // 这是一个通用的功能模块采用TCP协议获取文件的 客户端tcpgetfile.cpp #include _public.h struct st_arg {char ip[31]; // 服务器端的IP地址。int port; // 服务器端的端口。int ptype; // 文件获取成功后文件的处理方式1-保留文件2-删除文件3-移动到备份目录。char clientpath[301]; // 本地文件存放的根目录。char srvpath[301]; // 服务端文件存放的根目录。char srvpathbak[301]; // 文件成功获取后服务端文件备份的根目录当ptype3时有效。bool andchild; // 是否获取srvpath目录下各级子目录的文件true-是false-否。char matchname[301]; // 待获取文件名的匹配方式如*.TXT,*.XML注意用大写。char okfilename[301]; // 已获取成功文件名清单。listfilename不需要了服务端返回的报文直接放容器里了int timetvl; // 扫描本地目录文件的时间间隔单位秒。 } starg; char strRecvBuffer[TCPBUFLEN10]; // 接收报文的缓冲区 char strSendBuffer[TCPBUFLEN10]; // 发送报文的缓冲区 vectorstruct st_fileinfo vlistfile,vlistfile1; vectorstruct st_fileinfo vokfilename,vokfilename1; bool LoadListFile(); // 把服务端srvpath目录下的文件加载到vlistfile容器中 bool LoadOKFileName(); // 把okfilename文件内容加载到vokfilename容器中 // 把vlistfile容器中的文件与vokfilename容器中文件对比得到两个容器 // 一、在vlistfile中存在并已经采集成功的文件vokfilename1 // 二、在vlistfile中存在新文件或需要重新采集的文件vlistfile1 bool CompVector(); bool WriteToOKFileName(); // 把vokfilename1容器中的内容先写入okfilename文件中覆盖之前的旧okfilename文件 bool AppendToOKFileName(struct st_fileinfo *stfileinfo); // 如果ptype1把采集成功的文件记录追加到okfilename文件中 CTcpClient TcpClient; CLogFile logfile; bool _tcpgetfiles(); void EXIT(int sig); void _help(char *argv[]); bool _xmltoarg(char *strxmlbuffer); // 把xml解析到参数starg结构中 bool ClientLogin(const char *argv); // 登录服务器 bool ActiveTest(); // 向服务端发送心跳报文 bool _tcpgetfiles(); // 实现文件获取的功能int main(int argc,char *argv[]) {if (argc!3) { _help(argv); return -1; }CloseIOAndSignal();signal(SIGINT,EXIT); signal(SIGTERM,EXIT);if (logfile.Open(argv[1],a)false){printf(打开日志文件失败%s。\n,argv[1]); return -1;}if (_xmltoarg(argv[2])false) return -1; //把xml解析到参数starg结构中while (true){ ClientLogin(argv[2]); // 向服务器发起连接并登录// 实现文件获取的功能_tcpgetfiles()出现通讯故障没有关socket_tcpgetfiles函数返回后vlistfile容器是不空的//循环到了ClientLogin这里判断登录ClientLogin里不判断socket有没有问题不会去重新登录又到_tcpgetfiles死循环_tcpgetfiles();if (vlistfile.size()0){ ActiveTest(); // 向服务端发送心跳报文sleep(starg.timetvl);}}return 0; }void EXIT(int sig) {logfile.Write(程序退出sig%d\n\n,sig);TcpClient.Close();exit(0); }//111111111111111111111111111111111111111111111111111显示程序的帮助 void _help(char *argv[]) {printf(\n);printf(Using:/htidc/public/bin/tcpgetfiles logfilename xmlbuffer\n\n);printf(Sample:/htidc/public/bin/tcpgetfiles /log/shqx/tcpgetfiles_surfdata.log \ip172.16.0.15/ipport5010/portptype1/ptypeclientpath/data/shqx/sdata/surfdata/clientpathsrvpath/data/shqx/tcp/surfdata/srvpathsrvpathbak/data/shqx/tcp/surfdatabak/srvpathbakandchildtrue/andchildmatchnameSURF_*.TXT,*.DAT/matchnameokfilename/data/shqx/tcplist/tcpgetfiles_surfdata.xml/okfilenametimetvl10/timetvl\\n\n\n);printf(这是一个通用的功能模块采用TCP协议获取文件的客户端。\n);printf(logfilename 本程序运行的日志文件。\n);printf(xmlbuffer 本程序运行的参数如下\n);printf(ip 服务器端的IP地址。\n);printf(port 服务器端的端口。\n);printf(clientpath 客户端文件存放的根目录。\n);printf(srvpath 服务端文件存放的根目录。\n);printf(ptype 文件获取成功后服务端文件的处理方式1-保留文件2-删除文件3-移动到备份目录。\n);printf(srvpathbak 文件成功获取后服务端文件备份的根目录当ptype3时有效缺省为空。\n);printf(andchild 是否获取srvpath目录下各级子目录的文件true-是false-否缺省为false。\n);printf(matchname 待获取文件名的匹配方式如\*.TXT,*.XML\注意用大写。\n);printf(okfilename 已获取成功文件名清单缺省为空。\n);printf(timetvl 扫描本地目录文件的时间间隔单位秒取值在1-50之间。\n\n\n); }//1111111111111111111111111111111111111111111111把xml解析到参数starg结构中 bool _xmltoarg(char *strxmlbuffer) {memset(starg,0,sizeof(struct st_arg));GetXMLBuffer(strxmlbuffer,ip,starg.ip);if (strlen(starg.ip)0) { logfile.Write(ip is null.\n); return false; }GetXMLBuffer(strxmlbuffer,port,starg.port);if ( starg.port0) { logfile.Write(port is null.\n); return false; }GetXMLBuffer(strxmlbuffer,ptype,starg.ptype);if ((starg.ptype!1)(starg.ptype!2)(starg.ptype!3) ) { logfile.Write(ptype not in (1,2,3).\n); return false; }GetXMLBuffer(strxmlbuffer,clientpath,starg.clientpath);if (strlen(starg.clientpath)0) { logfile.Write(clientpath is null.\n); return false; }GetXMLBuffer(strxmlbuffer,srvpathbak,starg.srvpathbak);if ((starg.ptype3)(strlen(starg.srvpathbak)0)) { logfile.Write(srvpathbak is null.\n); return false; }GetXMLBuffer(strxmlbuffer,srvpath,starg.srvpath);if (strlen(starg.srvpath)0) { logfile.Write(srvpath is null.\n); return false; }GetXMLBuffer(strxmlbuffer,andchild,starg.andchild);GetXMLBuffer(strxmlbuffer,matchname,starg.matchname);if (strlen(starg.matchname)0) { logfile.Write(matchname is null.\n); return false; }GetXMLBuffer(strxmlbuffer,okfilename,starg.okfilename);if ((starg.ptype1)(strlen(starg.okfilename)0)) { logfile.Write(okfilename is null.\n); return false; }GetXMLBuffer(strxmlbuffer,timetvl,starg.timetvl);if (starg.timetvl0) { logfile.Write(timetvl is null.\n); return false; }if (starg.timetvl50) starg.timetvl50;return true; }//1111111111111111111111111111111111111111111111111111111登录服务器 bool ClientLogin(const char *argv) {if (TcpClient.m_sockfd0) return true;int ii0;while (true){if (ii0) sleep(20); // 第一次进入循环不休眠// 向服务器发起连接if (TcpClient.ConnectToServer(starg.ip,starg.port) false){logfile.Write(TcpClient.ConnectToServer(%s,%d) failed.\n,starg.ip,starg.port); continue;}memset(strRecvBuffer,0,sizeof(strRecvBuffer));memset(strSendBuffer,0,sizeof(strSendBuffer));strcpy(strSendBuffer,argv); strcat(strSendBuffer,clienttype2/clienttype);// logfile.Write(1 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpClient.Write(strSendBuffer) false){logfile.Write(1 TcpClient.Write() failed.\n); continue;}if (TcpClient.Read(strRecvBuffer,20) false){logfile.Write(1 TcpClient.Read() failed.\n); continue;}// logfile.Write(1 strRecvBuffer%s\n,strRecvBuffer); // xxxxxxbreak;}logfile.Write(login(%s,%d) ok.\n,starg.ip,starg.port);return true; }//11111111111111111111111111111111111111111111111111向服务端发送心跳报文 bool ActiveTest() {memset(strRecvBuffer,0,sizeof(strRecvBuffer));memset(strSendBuffer,0,sizeof(strSendBuffer));strcpy(strSendBuffer,activetestok/activetest);// logfile.Write(2 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpClient.Write(strSendBuffer) false){logfile.Write(2 TcpClient.Write() failed.\n); TcpClient.Close(); return false;}if (TcpClient.Read(strRecvBuffer,20) false){logfile.Write(2 TcpClient.Read() failed.\n); TcpClient.Close(); return false;}// logfile.Write(2 strRecvBuffer%s\n,strRecvBuffer); // xxxxxxif (strcmp(strRecvBuffer,ok) ! 0) { TcpClient.Close(); return false; }return true; }//111111111111111111111111111111111111111111111111111实现文件获取的功能 bool _tcpgetfiles() {// 把服务端srvpath目录下的文件加载到vlistfile容器中if (LoadListFile()false){logfile.Write(LoadListFile() failed.\n); TcpClient.Close(); return false;}if (starg.ptype1){// 加载okfilename文件中的内容到容器vokfilename中LoadOKFileName();// 把vlistfile容器中的文件与vokfilename容器中文件对比得到两个容器// 一、在vlistfile中存在并已经采集成功的文件vokfilename1// 二、在vlistfile中存在新文件或需要重新采集的文件vlistfile1CompVector(); WriteToOKFileName(); // 把vokfilename1容器中的内容先写入okfilename文件中覆盖之前的旧okfilename文件 vlistfile.clear(); vlistfile.swap(vlistfile1); // 把vlistfile1容器中的内容复制到vlistfile容器中}for (int ii0;iivlistfile.size();ii) // 从服务端逐个获取新文件或已改动过的文件{ memset(strSendBuffer,0,sizeof(strSendBuffer)); // 向服务端发送将获取下载的文件信息sprintf(strSendBuffer,filename%s/filenamefilesize%d/filesizemtime%s/mtime,vlistfile[ii].filename,vlistfile[ii].filesize,vlistfile[ii].mtime);// logfile.Write(3 strSendBuffer%s\n,strSendBuffer); // xxxxxx if (TcpClient.Write(strSendBuffer) false){logfile.Write(3 TcpClient.Write() failed.\n); TcpClient.Close(); return false;}// 文件信息已知道此报文有些多余但是为了兼容SendFile和RecvFile函数对性能不会有影响。if (TcpClient.Read(strRecvBuffer) false){logfile.Write(3 TcpClient.Read() failed.\n); TcpClient.Close(); return false;}// logfile.Write(3 strRecvBuffer%s\n,strRecvBuffer); // xxxxxx // 把文件名中的clientpath替换成srvpath要小心第三个参数struct st_fileinfo stfileinfo;memset(stfileinfo,0,sizeof(struct st_fileinfo));strcpy(stfileinfo.filename,vlistfile[ii].filename);strcpy(stfileinfo.mtime,vlistfile[ii].mtime);stfileinfo.filesizevlistfile[ii].filesize;UpdateStr(stfileinfo.filename,starg.srvpath,starg.clientpath);logfile.Write(get %s ...,stfileinfo.filename);// ptype1是增量传输对服务端来说什么都不干保留oklistfile是客户端的事 if (RecvFile(logfile,TcpClient.m_sockfd,stfileinfo) false) // 接收文件的内容{logfile.Write(RecvFile() failed.\n); TcpClient.Close(); return false;}logfile.WriteEx(ok.\n);// 如果ptype1把采集成功的文件记录追加到okfilename文件中if (starg.ptype1) AppendToOKFileName(vlistfile[ii]);}return true; }//11111111111111111111111111111111111111111把服务端srvpath目录下的文件加载到vlistfile容器中 bool LoadListFile() {vlistfile.clear();memset(strSendBuffer,0,sizeof(strSendBuffer));strcpy(strSendBuffer,list); //向服务端发list就像向ftp服务端发nlist命令一样// logfile.Write(4 strSendBuffer%s\n,strSendBuffer); // xxxxxx if (TcpClient.Write(strSendBuffer) false){logfile.Write(4 TcpClient.Write() failed.\n); return false;}memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpClient.Read(strRecvBuffer,20) false){logfile.Write(4 TcpClient.Read() failed.\n); return false;}// logfile.Write(4 strRecvBuffer%s\n,strRecvBuffer); // xxxxxx// Read到的报文就是文件总数int totalfile0; GetXMLBuffer(strRecvBuffer,totalfile,totalfile);struct st_fileinfo stfileinfo;for (int ii0;iitotalfile;ii) //利用循环接收文件清单报文解析出来放入vlistfile容器里{memset(stfileinfo,0,sizeof(struct st_fileinfo));memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpClient.Read(strRecvBuffer,20) false){logfile.Write(5 TcpClient.Read() failed.\n); return false;}// logfile.Write(5 strRecvBuffer%s\n,strRecvBuffer); // xxxxxxGetXMLBuffer(strRecvBuffer,filename,stfileinfo.filename);GetXMLBuffer(strRecvBuffer,filesize,stfileinfo.filesize);GetXMLBuffer(strRecvBuffer,mtime,stfileinfo.mtime); vlistfile.push_back(stfileinfo);// logfile.Write(vlistfile filename%s,mtime%s\n,stfileinfo.filename,stfileinfo.mtime);}return true; }//11111111111111111111111111111111111111111111111把okfilename文件内容加载到vokfilename容器中 bool LoadOKFileName() {vokfilename.clear();CFile File;// 注意如果程序是第一次采集okfilename是不存在的并不是错误所以也返回true。if (File.Open(starg.okfilename,r) false) return true;struct st_fileinfo stfileinfo;char strbuffer[301];while (true){memset(stfileinfo,0,sizeof(struct st_fileinfo));if (File.Fgets(strbuffer,300,true)false) break;GetXMLBuffer(strbuffer,filename,stfileinfo.filename,300);GetXMLBuffer(strbuffer,mtime,stfileinfo.mtime,20);vokfilename.push_back(stfileinfo);// logfile.Write(vokfilename filename%s,mtime%s\n,stfileinfo.filename,stfileinfo.mtime);}return true; }//11111111111111111111111111111把vlistfile容器中的文件与vokfilename容器中文件对比得到两个容器 // 一、在vlistfile中存在并已经采集成功的文件vokfilename1 // 二、在vlistfile中存在新文件或需要重新采集的文件vlistfile1 bool CompVector() {vokfilename1.clear(); vlistfile1.clear();for (int ii0;iivlistfile.size();ii){int jj0;for (jj0;jjvokfilename.size();jj){if ( (strcmp(vlistfile[ii].filename,vokfilename[jj].filename)0) (strcmp(vlistfile[ii].mtime,vokfilename[jj].mtime)0) ){vokfilename1.push_back(vlistfile[ii]); break;}}if (jjvokfilename.size()){vlistfile1.push_back(vlistfile[ii]);}}/*for (int ii0;iivokfilename1.size();ii){logfile.Write(vokfilename1 filename%s,mtime%s\n,vokfilename1[ii].filename,vokfilename1[ii].mtime);}for (int ii0;iivlistfile1.size();ii){logfile.Write(vlistfile1 filename%s,mtime%s\n,vlistfile1[ii].filename,vlistfile1[ii].mtime);}*/return true; }//111111111111111把vokfilename1容器中的内容先写入okfilename文件中覆盖之前的旧okfilename文件 bool WriteToOKFileName() {CFile File;if (File.Open(starg.okfilename,w,false) false) // 注意打开文件不要采用缓冲机制{logfile.Write(File.Open(%s) failed.\n,starg.okfilename); return false;}for (int ii0;iivokfilename1.size();ii){File.Fprintf(filename%s/filenamemtime%s/mtime\n,vokfilename1[ii].filename,vokfilename1[ii].mtime);}return true; }//1111111111111111111111如果ptype1把采集成功的文件记录追加到okfilename文件中 bool AppendToOKFileName(struct st_fileinfo *stfileinfo) {CFile File;if (File.Open(starg.okfilename,a,false) false){logfile.Write(File.Open(%s) failed.\n,starg.okfilename); return false;}File.Fprintf(filename%s/filenamemtime%s/mtime\n,stfileinfo-filename,stfileinfo-mtime);return true; }//这是一个通用的功能模块采用TCP协议实现文件传输的服务端tcpfileserver.cpp多线程。 #include _public.h struct st_arg {int clienttype;char ip[31]; // 服务器端的IP地址。int port; // 服务器端的端口。int ptype; // 文件发送成功后文件的处理方式1-保留文件2-移动到备份目录3-删除文件。char clientpath[301]; // 本地文件存放的根目录。char clientpathbak[301]; // 文件成功发送后本地文件备份的根目录当ptype2时有效。char srvpath[301]; // 服务端文件存放的根目录。char srvpathbak[301]; // 文件成功接收后服务端文件备份的根目录当ptype2时有效。bool andchild; // 是否发送clientpath目录下各级子目录的文件true-是false-否。char matchname[301]; // 待发送文件名的匹配方式如*.TXT,*.XML注意用大写。char okfilename[301]; // 已发送成功文件名清单。int timetvl; // 扫描本地目录文件的时间间隔单位秒。 }; bool _xmltoarg(char *strxmlbuffer,struct st_arg *starg); //把xml解析到参数starg结构中 CLogFile logfile; bool ClientLogin(int clientfd,struct st_arg *starg); // 等待登录 bool ListFile(int clientfd,struct st_arg *starg); // 列出srvpath目录下文件的清单返回给客户端。 void EXIT(int sig); // 程序退出时调用的函数 void *pth_main(void *arg); // 与客户端通信线程的主函数 bool RecvFilesMain(int clientfd,struct st_arg *starg); // 接收文件主函数 bool SendFilesMain(int clientfd,struct st_arg *starg); // 发送文件主函数 vectorint vclientfd; // 存放客户端已连接的socket的容器 void AddClient(int clientfd); // 把客户端新的socket加入vclientfd容器中 void RemoveClient(int clientfd); // 关闭客户端的socket并从vclientfd容器中删除int main(int argc,char *argv[]) {if (argc ! 3){printf(\n);printf(Using:/htidc/public/bin/tcpfileserver1 logfilename port\n);printf(Example:/htidc/public/bin/tcpfileserver1 /log/shqx/tcpfileserver1.log 5010\n\n);printf(本程序是一个公共功能模块采用TCP/IP传输文件的服务端。\n);printf(本程序采用的是多线程的服务端多进程的服务端程序是tcpfileserver.cpp。\n);printf(logfilename 日志文件名。\n);printf(port 用于传输文件的TCP端口。\n);return -1;}CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);// 打开程序运行日志这是一个多进程程序日志不能自动切换if (logfile.Open(argv[1],a,false) false){printf(logfile.Open(%s) failed.\n,argv[1]); return -1;}logfile.Write(fileserver started(%s).\n,argv[2]);CTcpServer TcpServer; //定义为局部变量if (TcpServer.InitServer(atoi(argv[2])) false){logfile.Write(TcpServer.InitServer(%s) failed.\n,argv[2]); return -1;}AddClient(TcpServer.m_listenfd); //保存服务端的listenfd到vclientfdwhile (true){ if (TcpServer.Accept() false) //等待客户端的连接{logfile.Write(TcpServer.Accept() failed.\n); continue;}pthread_t pthid; //客户端连上后创建一线程下面将socket参数传进去与新连接上来的客户端通信// int4字节long8字节*指针8字节TcpServer.m_connfd定义的是整数intif (pthread_create(pthid,NULL,pth_main,(void*)(long)TcpServer.m_connfd)!0){ //主线程等子线程结束才行logfile.Write(创建线程失败程序退出。n); close(TcpServer.m_connfd); EXIT(-1);}logfile.Write(%s is connected.\n,TcpServer.GetIP()); AddClient(TcpServer.m_connfd); //保存每个客户端的socket到vclientfd}return 0; }//11111111111111111111111111111111111111111111111111111111111111 void EXIT(int sig) {signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN);if (sig0) signal(sig,SIG_IGN);logfile.Write(tcpfileserver1 exit,sig%d...\n,sig);// 关闭vclientfd容器中全部的socket,释放出资源for (int ii0;iivclientfd.size();ii){close(vclientfd[ii]);}exit(0); }//11111111111111111111111111111111111111111111111111111111等待登录 bool ClientLogin(int clientfd,struct st_arg *starg) {int ibuflen0;char strRecvBuffer[TCPBUFLEN10]; // 接收报文的缓冲区char strSendBuffer[TCPBUFLEN10]; // 发送报文的缓冲区memset(strRecvBuffer,0,sizeof(strRecvBuffer));memset(strSendBuffer,0,sizeof(strSendBuffer));//以前用TcpServer.Read现在改为TcpRead对于线程里没有TcpServer这个对象了//TcpServer.Read里也是调用TcpReadif (TcpRead(clientfd,strRecvBuffer,ibuflen,20) false){logfile.Write(1 TcpRead() failed.\n); return false;}// logfile.Write(1 strRecvBuffer%s\n,strRecvBuffer); // xxxxxxGetXMLBuffer(strRecvBuffer,clienttype,starg-clienttype);if ( (starg-clienttype1) || (starg-clienttype2) )strcpy(strSendBuffer,ok);elsestrcpy(strSendBuffer,failed);// logfile.Write(1 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(1 TcpWrite() failed.\n); return false;}logfile.Write(login %s(clienttype%d).\n,strSendBuffer,starg-clienttype);if (strcmp(strSendBuffer,failed) 0) return false;// 把参数解析出来_xmltoarg(strRecvBuffer,starg);return true; }//11111111111111111111111111111111111111111111111111111接收文件主函数 bool RecvFilesMain(int clientfd,struct st_arg *starg) {int ibuflen0;char strRecvBuffer[TCPBUFLEN10]; // 接收报文的缓冲区char strSendBuffer[TCPBUFLEN10]; // 发送报文的缓冲区while (true){memset(strRecvBuffer,0,sizeof(strRecvBuffer));memset(strSendBuffer,0,sizeof(strSendBuffer));if (TcpRead(clientfd,strRecvBuffer,ibuflen,80) false){logfile.Write(TcpRead() failed.\n); return false;}// logfile.Write(2 strRecvBuffer%s\n,strRecvBuffer); // xxxxxx// 处理心跳报文if (strstr(strRecvBuffer,activetest)!0){strcpy(strSendBuffer,ok);// logfile.Write(2 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(2 TcpWrite() failed.\n); return false;}continue;}struct st_fileinfo stfileinfo;memset(stfileinfo,0,sizeof(struct st_fileinfo));// 获取待接收的文件的时间和大小GetXMLBuffer(strRecvBuffer,filename,stfileinfo.filename);GetXMLBuffer(strRecvBuffer,filesize,stfileinfo.filesize);GetXMLBuffer(strRecvBuffer,mtime,stfileinfo.mtime);// 把文件名中的clientpath替换成srvpath要小心第三个参数UpdateStr(stfileinfo.filename,starg-clientpath,starg-srvpath,false);// 接收文件的内容if (RecvFile(logfile,clientfd,stfileinfo) false){logfile.Write(RecvFile() failed.\n); return false;}logfile.Write(recv %s ok.\n,stfileinfo.filename);}return true; }//11111111111111111111111111111111111111111111111111111111发送文件主函数 bool SendFilesMain(int clientfd,struct st_arg *starg) {int ibuflen0;char strRecvBuffer[TCPBUFLEN10]; // 接收报文的缓冲区char strSendBuffer[TCPBUFLEN10]; // 发送报文的缓冲区while (true){memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpRead(clientfd,strRecvBuffer,ibuflen,80) false){logfile.Write(TcpRead() failed.\n); return false;}// logfile.Write(3 strRecvBuffer%s\n,strRecvBuffer); // xxxxxx// 处理心跳报文if (strstr(strRecvBuffer,activetest)!0){memset(strSendBuffer,0,sizeof(strSendBuffer));strcpy(strSendBuffer,ok);// logfile.Write(3 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(3 TcpWrite() failed.\n); return false;}continue;}// 处理获取文件列表报文if (strcmp(strRecvBuffer,list)0){if (ListFile(clientfd,starg)false){logfile.Write(ListFile() failed.\n); return false;}continue;}// 取文件报文if (strncmp(strRecvBuffer,filename,10)0){// 获取待接收的文件的时间和大小struct st_fileinfo stfileinfo;memset(stfileinfo,0,sizeof(struct st_fileinfo));GetXMLBuffer(strRecvBuffer,filename,stfileinfo.filename);GetXMLBuffer(strRecvBuffer,filesize,stfileinfo.filesize);GetXMLBuffer(strRecvBuffer,mtime,stfileinfo.mtime);// 把文件发送给客户端if (SendFile(logfile,clientfd,stfileinfo)false) return false;logfile.Write(put %s ...ok.\n,stfileinfo.filename);// 删除服务端的文件if (starg-ptype2) REMOVE(stfileinfo.filename);// 备份服务端的文件if (starg-ptype3) {char strfilenamebak[301];memset(strfilenamebak,0,sizeof(strfilenamebak));strcpy(strfilenamebak,stfileinfo.filename);UpdateStr(strfilenamebak,starg-srvpath,starg-srvpathbak,false); // 要小心第三个参数if (RENAME(stfileinfo.filename,strfilenamebak)false){logfile.Write(RENAME %s to %s failed.\n,stfileinfo.filename,strfilenamebak); return false;}}}}return true; }//11111111111111111111111111111111111111111111111111111把xml解析到参数starg结构中 bool _xmltoarg(char *strxmlbuffer,struct st_arg *starg) {GetXMLBuffer(strxmlbuffer,ip,starg-ip);GetXMLBuffer(strxmlbuffer,port,starg-port);GetXMLBuffer(strxmlbuffer,ptype,starg-ptype);GetXMLBuffer(strxmlbuffer,clientpath,starg-clientpath);GetXMLBuffer(strxmlbuffer,clientpathbak,starg-clientpathbak);GetXMLBuffer(strxmlbuffer,srvpath,starg-srvpath);GetXMLBuffer(strxmlbuffer,srvpathbak,starg-srvpathbak);GetXMLBuffer(strxmlbuffer,andchild,starg-andchild);GetXMLBuffer(strxmlbuffer,matchname,starg-matchname);GetXMLBuffer(strxmlbuffer,okfilename,starg-okfilename);GetXMLBuffer(strxmlbuffer,timetvl,starg-timetvl);return true; }//1111111111111111111111111111111111111111111111列出srvpath目录下文件的清单返回给客户端。 bool ListFile(int clientfd,struct st_arg *starg) {int ibuflen0;char strRecvBuffer[TCPBUFLEN10]; // 接收报文的缓冲区char strSendBuffer[TCPBUFLEN10]; // 发送报文的缓冲区CDir Dir;// 注意如果目录下的总文件数超过50000增量发送文件功能将有问题if (Dir.OpenDir(starg-srvpath,starg-matchname,50000,starg-andchild,false)false){logfile.Write(Dir.OpenDir(%s) 失败。\n,starg-srvpath); return false;}// 先把文件总数返回给客户端memset(strSendBuffer,0,sizeof(strSendBuffer));sprintf(strSendBuffer,totalfile%d/totalfile,Dir.m_vFileName.size());// logfile.Write(4 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(4 TcpWrite() failed.\n); return false;}// 把文件信息一条条的返回给客户端while (true){if (Dir.ReadDir()false) break;memset(strSendBuffer,0,sizeof(strSendBuffer));sprintf(strSendBuffer,filename%s/filenamemtime%s/mtimefilesize%d/filesize,Dir.m_FullFileName,Dir.m_ModifyTime,Dir.m_FileSize);// logfile.Write(5 strSendBuffer%s\n,strSendBuffer); // xxxxxxif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(5 TcpWrite() failed.\n); return false;}}return true; }//111111111111111111111111111111111111111111111111111111111与客户端通信线程的主函数 void *pth_main(void *arg) {int clientfd(long) arg; // arg参数为新客户端的socketpthread_detach(pthread_self());struct st_arg starg;memset(starg,0,sizeof(struct st_arg));// 等待客户端的登录if (ClientLogin(clientfd,starg) false) { RemoveClient(clientfd); pthread_exit(0); }// 接收文件主函数if (starg.clienttype1) {if (RecvFilesMain(clientfd,starg) false) { RemoveClient(clientfd); pthread_exit(0); }}// 发送文件主函数if (starg.clienttype2) {if (SendFilesMain(clientfd,starg) false) { RemoveClient(clientfd); pthread_exit(0); }}RemoveClient(clientfd); pthread_exit(0); }//11111111111111111111111111111111111111111111把客户端新的socket加入vclientfd容器中 void AddClient(int clientfd) {vclientfd.push_back(clientfd); }//11111111111111111111111111111111111111111关闭客户端的socket并从vclientfd容器中删除 void RemoveClient(int clientfd) {for (int ii0;iivclientfd.size();ii){if (vclientfd[ii]clientfd) { close(clientfd); vclientfd.erase(vclientfd.begin()ii); return; }} }8.3 高性能网络服务多线程数据库连接池多线程每启一个线程都要连数据库耗资源 如下开始APP服务端设计客户端就是手机app软件。第一次客户端将手机编号传给服务端服务端将站点信息传给客户端。 短连接客户端即用户点击按钮一次建立一次socket连接请求处理完一个就断开。响应慢建立一次socket连接费时间服务端fork一个进程也要时间之后和数据库连接也要时间。 长连接客户端与服务端socket一直连接着进行数据通信没有数据通信时用心跳之前文件传输都用的是长连接用户关了app连接才断开。费服务端资源长连接连上后数据库连接和进程都已准备好一直通信完才断开。响应快用户看到数据越快越好控制在1秒内。如下项目组织shtqapp是一个独立的项目。 如下第一行是上面创建用户sqlpdm文件是数据结构设计。 // client.cpp模拟tcp手机客户端客户端用短链接还是长连接由客户端自己安排 #include _freecplus.h CTcpClient TcpClient; char strSendBuffer[301],strRecvBuffer[301]; bool biz10000(); // 心跳 bool biz10001(); // 新用户登录只传个设备编号id服务端把城市站点信息传给客户端手机利用定位匹配int main(int argc,char *argv[]) {//if (TcpClient.ConnectToServer(127.0.0.1,5015)false) { printf(conn failed.\n); return -1; }if (TcpClient.ConnectToServer(172.16.0.15,5015)false) { printf(conn failed.\n); return -1; }//if (TcpClient.ConnectToServer(118.89.50.198,5015)false) { printf(conn failed.\n); return -1; }if (biz10000()false) return 0; // 心跳CTimer Timer;if (biz10001()false) return 0; // 新用户登录 printf(biz10001%lf\n,Timer.Elapsed());sleep(1); return 0; }bool biz10000() {memset(strSendBuffer,0,sizeof(strSendBuffer));memset(strRecvBuffer,0,sizeof(strRecvBuffer));strcpy(strSendBuffer,bizid10000/bizid);//printf(send%s\n,strSendBuffer);if (TcpClient.Write(strSendBuffer)false) { printf(send failed.\n); return false; }if (TcpClient.Read(strRecvBuffer,20)false) { printf(recv failed.\n); return false; }//printf(recv%s\n,strRecvBuffer);return true; }bool biz10001() {memset(strSendBuffer,0,sizeof(strSendBuffer)); memset(strRecvBuffer,0,sizeof(strRecvBuffer));// 如下请求报文strcpy(strSendBuffer,bizid10001/biziduserid52:54:00:83:0f:c1/useridttytype1/ttytypelat20.234518/latlon115.90832/lonheight150.5/height);//printf(send%s\n,strSendBuffer);if (TcpClient.Write(strSendBuffer)false) { printf(send failed.\n); return false; }//如下用一个循环接收全部的站点信息while (1){memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpClient.Read(strRecvBuffer,20)false) { printf(recv failed.\n); return false; }// printf(recv%s\n,strRecvBuffer); //手机端没数据库手机软件真正处理方法把数据保存到xml文件里if (strcmp(strRecvBuffer,ok)0) break; //接收到ok的话表示数据处理完了}return true; }数据库连接池的设计可用一个参数去控制连接池的总大小比如这连接池里有10个connection连接就需要10把锁。在sqlstatement每次想使用数据库连接时就会从10个已创建好的connection看看哪个没锁就拿1个过来用。 //上海天气APP软件服务端主程序。shtqappserver.cpp多线程方式采用连接池。 #include _freecplus.h #include _ooci.h #define MAXCONNS 10 // 数据库连接池的大小。 pthread_mutex_t mutex[MAXCONNS]; // 锁数组。 connection conns[MAXCONNS]; // 数据库连接数组。 bool initconns(); // 初始数据库连接池。 connection *getconns(); // 从连接池中获取一个数据库连接。 bool freeconns(connection *in_conn); // 释放数据库连接。struct st_biz // 业务请求 {int bizid; // 业务代码char userid[51]; // 设备IDint ttytype; // 用户的设备类型0-未知1-IOS2-Andriod2-鸿蒙。int usertype; // 用户分类0-未知1-普通用户2-气象志愿者3-内部用户。double lon;double lat;double height;char obtid[11];char xmlbuffer[1001]; }; void xmltobiz(char *strxmlbuffer,struct st_biz *stbiz); CTcpServer TcpServer; CLogFile logfile; void EXIT(int sig); // 程序退出时调用的函数 void *pth_main(void *arg); // 与客户端通信线程的主函数 bool biz10000(int clientfd); // 心跳业务 bool biz10001(struct st_biz *stbiz,int clientfd); // 新用户登录业务 bool biz10002(struct st_biz *stbiz,int clientfd); // 获取天气实况 bool InsertUSERLOG(struct st_biz *stbiz,connection *conn); // 插入用户请求日志表 vectorint vclientfd; // 存放客户端已连接的socket的容器 void AddClient(int clientfd); // 把客户端新的socket加入vclientfd容器中 void RemoveClient(int clientfd); // 关闭客户端的socket并从vclientfd容器中删除int main(int argc,char *argv[]) {if (argc ! 3){printf(\n);printf(Using:/htidc/shtqapp1/bin/shtqappserver1 logfilename port\n);printf(Example:/htidc/shtqapp1/bin/shtqappserver1 /log/shtqapp/shtqappserver1.log 5015\n\n);printf(本程序是上海天气APP软件的服务端。\n);printf(logfilename 日志文件名。\n);printf(port 用于传输文件的TCP端口。\n);return -1;}CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);// 打开程序运行日志这是一个多进程程序日志不能自动切换if (logfile.Open(argv[1],a,false) false){printf(logfile.Open(%s) failed.\n,argv[1]); return -1;}logfile.Write(shtqappserver started(%s).\n,argv[2]);if (TcpServer.InitServer(atoi(argv[2])) false){logfile.Write(TcpServer.InitServer(%s) failed.\n,argv[2]); EXIT(-1);}// 保存服务端的listenfd到vclientfdAddClient(TcpServer.m_listenfd);if (initconns()false) // 初始化数据库连接池。{logfile.Write(initconns() failed.\n); EXIT(-1);}while (true){if (TcpServer.Accept() false) // 等待客户端的连接{logfile.Write(TcpServer.Accept() failed.\n); continue;}pthread_t pthid; // 创建一线程与新连接上来的客户端通信if (pthread_create(pthid,NULL,pth_main,(void*)(long)TcpServer.m_connfd)!0){logfile.Write(创建线程失败程序退出。n); close(TcpServer.m_connfd); EXIT(-1);}logfile.Write(%s is connected.\n,TcpServer.GetIP()); AddClient(TcpServer.m_connfd); // 保存每个客户端的socket到vclientfd}return 0; }void EXIT(int sig) // 退出时调用的函数 {signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN);if (sig0) signal(sig,SIG_IGN);logfile.Write(tcpfileserver1 exit,sig%d...\n,sig);// 关闭vclientfd容器中全部的socketfor (int ii0;iivclientfd.size();ii){close(vclientfd[ii]);}for (int ii0;iiMAXCONNS;ii){logfile.Write(disconnect and pthread_mutex_destroy.\n);conns[ii].disconnect();pthread_mutex_destroy(mutex[ii]);}exit(0); }//11111111111111111111111111111111111111111与客户端通信线程的主函数 void *pth_main(void *arg) {int clientfd(long) arg; // arg参数为新客户端的socket。pthread_detach(pthread_self());struct st_biz stbiz;int ibuflen0;char strRecvBuffer[1024]; // 接收报文的缓冲区while (true){memset(strRecvBuffer,0,sizeof(strRecvBuffer));// 接收客户端的业务请求报文如果返回false认为是客户端退出或网络原因不写错误日志if (TcpRead(clientfd,strRecvBuffer,ibuflen,50) false){// logfile.Write(TcpRead() failed.\n); break;}logfile.Write(strRecvBuffer%s\n,strRecvBuffer); // xxxxxx// 把参数解析出来xmltobiz(strRecvBuffer,stbiz);if (stbiz.bizid10000) // 心跳报文{if (biz10000(clientfd)true) continue;else break;}// 新用户登录 if (stbiz.bizid10001) {if (biz10001(stbiz,clientfd)true) continue;else break;}// 获取天气实况if (stbiz.bizid10002) {if (biz10002(stbiz,clientfd)true) continue;else break;}// 体力活logfile.Write(非法报文%s\n,strRecvBuffer); break;}RemoveClient(clientfd);pthread_exit(0); }//111111111111111111111111111111111111111111把xml解析到参数starg结构中 void xmltobiz(char *strxmlbuffer,struct st_biz *stbiz) {memset(stbiz,0,sizeof(struct st_biz));// 业务代码GetXMLBuffer(strxmlbuffer,bizid,stbiz-bizid);// logfile.Write(bizid%d\n,stbiz-bizid);// 用户设备IDGetXMLBuffer(strxmlbuffer,userid,stbiz-userid,50);// logfile.Write(userid%s\n,stbiz-userid);GetXMLBuffer(strxmlbuffer,obtid,stbiz-obtid,10);// logfile.Write(obtid%s\n,stbiz-obtid);GetXMLBuffer(strxmlbuffer,lat,stbiz-lat);// logfile.Write(lat%lf\n,stbiz-lat);GetXMLBuffer(strxmlbuffer,lon,stbiz-lon);// logfile.Write(lon%lf\n,stbiz-lon);GetXMLBuffer(strxmlbuffer,height,stbiz-height);// logfile.Write(height%lf\n,stbiz-height);strncpy(stbiz-xmlbuffer,strxmlbuffer,1000);return; }//1111111111111111111111111111111111111111心跳业务 bool biz10000(int clientfd) {char strSendBuffer[1024]; // 发送报文的缓冲区memset(strSendBuffer,0,sizeof(strSendBuffer));strcpy(strSendBuffer,ok);if (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(biz10000 TcpWrite() failed.\n); return false;}return true; }//11111111111111111111111111111111111111111111新用户登录 bool biz10001(struct st_biz *stbiz,int clientfd) {CTimer Timer;char strSendBuffer[1024]; // 发送报文的缓冲区 connection *conngetconns(); // 获取一个数据库连接。// 插入用户基本信息表T_USERINFOsqlstatement stmt(conn);stmt.prepare(insert into T_USERINFO(userid,downtime,ttytype,keyid) values(:1,sysdate,:2,SEQ_USERINFO.nextval));stmt.bindin(1, stbiz-userid,50);stmt.bindin(2,stbiz-ttytype);if (stmt.execute() ! 0){if (stmt.m_cda.rc!1){logfile.Write(insert T_USERINFO failed.\n%s\n%s\n,stmt.m_cda.message,stmt.m_sql); freeconns(conn); return false;}}logfile.Write(insert T_USERINFO %lf\n,Timer.Elapsed());// 插入用户请求日志表if (InsertUSERLOG(stbiz,conn)false) { freeconns(conn); return false; }logfile.Write(insert T_USERLOG %lf\n,Timer.Elapsed());char strobtid[6],strobtname[31],strlon[11],strlat[11];stmt.prepare(select obtid,obtname,lon,lat from T_OBTCODE where rsts1 and rownum30);stmt.bindout(1,strobtid,5);stmt.bindout(2,strobtname,30);stmt.bindout(3,strlon,10);stmt.bindout(4,strlat,10);if (stmt.execute() ! 0){logfile.Write(select T_OBTCODE failed.\n%s\n%s\n,stmt.m_cda.message,stmt.m_sql); freeconns(conn); return false;}while (true){memset(strobtid,0,sizeof(strobtid)); memset(strobtname,0,sizeof(strobtname));memset(strlon,0,sizeof(strlon)); memset(strlat,0,sizeof(strlat));memset(strSendBuffer,0,sizeof(strSendBuffer));if (stmt.next()!0) break;sprintf(strSendBuffer,obtid%s/obtidobtname%s/obtnamelon%s/lonlat%s/latendl/,strobtid,strobtname,strlon,strlat);if (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(biz10001 TcpWrite() failed.\n); freeconns(conn); return false;}}logfile.Write(select %lf\n,Timer.Elapsed());strcpy(strSendBuffer,ok); //最后发送一个okif (TcpWrite(clientfd,strSendBuffer) false){logfile.Write(biz10001 TcpWrite() failed.\n); freeconns(conn); return false;}freeconns(conn);return true; }//11111111111111111111111111111111111111111111111插入用户请求日志表 bool InsertUSERLOG(struct st_biz *stbiz,connection *conn) {sqlstatement stmt(conn);stmt.prepare(insert into T_USERLOG(logid,userid,atime,bizid,obtid,lon,lat,height,xmlbuffer) values(SEQ_USERLOG.nextval,:1,sysdate,:2,:3,:4,:5,:6,:7));stmt.bindin(1, stbiz-userid,50);stmt.bindin(2,stbiz-bizid);stmt.bindin(3, stbiz-obtid,10);stmt.bindin(4,stbiz-lon);stmt.bindin(5,stbiz-lat);stmt.bindin(6,stbiz-height);stmt.bindin(7, stbiz-xmlbuffer,10000);if (stmt.execute() ! 0){logfile.Write(insert T_USERLOG failed.\n%s\n%s\n,stmt.m_cda.message,stmt.m_sql); return false;}return true; }//1111111111111111111111111111111111111111获取天气实况 bool biz10002(struct st_biz *stbiz,int clientfd) {return true; }//1111111111111111111111111111111111111把客户端新的socket加入vclientfd容器中 void AddClient(int clientfd) {vclientfd.push_back(clientfd); }//111111111111111111111111111111111111关闭客户端的socket并从vclientfd容器中删除 void RemoveClient(int clientfd) {for (int ii0;iivclientfd.size();ii){if (vclientfd[ii]clientfd) { close(clientfd); vclientfd.erase(vclientfd.begin()ii); return; }} }//111111111111111111111111111111111初始数据库连接池连接好数据库初始化锁 bool initconns() {for (int ii0;iiMAXCONNS;ii){logfile.Write(%d,connecttodb and pthread_mutex_init.\n,ii);// 连接数据库if (conns[ii].connecttodb(shtqapp/pwdidcsnorcl11g_198,Simplified Chinese_China.ZHS16GBK,true)!0){logfile.Write(conns[%d].connettodb() failed.\n,ii); return false;}pthread_mutex_init(mutex[ii],0); // 创建锁}return true; }//11111111111111111111111111111111111111111获得连接池 connection *getconns() {// for (int jj0;jj1000;jj)while (true){for (int ii0;iiMAXCONNS;ii){if (pthread_mutex_trylock(mutex[ii])0) {// logfile.Write(jj%d,ii%d\n,jj,ii);logfile.Write(get conns is %d.\n,ii);return conns[ii]; }} usleep(10000);} }//1111111111111111111111111111111111111111释放连接池 bool freeconns(connection *in_conn) {for (int ii0;iiMAXCONNS;ii){if (in_connconns[ii]) {logfile.Write(free conn %d.\n,ii);pthread_mutex_unlock(mutex[ii]); in_conn0; return true;}}return false; //理论上不会来到这里除非连接池搞乱了 }心跳报文业务不需要连接池先开启服务端。 9.进程fork()ps -ef (同-aux) | more 一个进程正在内存中运行的程序在内存里有三部分数据代码段相同堆栈段数据段不同。getpid库函数功能是获取进程编号该函数没有参数返回值是进程的编号相同程序在不同时间执行进程编号不同。 进程应用并发把socket服务端改为多进程每次accept到一个客户端连接后生成一个子进程让子进程负责与这个客户端通讯。父进程继续accept客户端连接。以下在服务端中在CTcpServer类中增加两个成员函数。 僵尸进程一个进程执行了exit系统调用退出时会向父进程发送SIGCHLD信号而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态如进程ID、终止状态等等)的进程ps显示有 default 。总结仔细处理子进程死后的信息如果不想处理就需要交给系统处理。 10.信号signal, EXITjps 进程间通信方式1.管道ls | grep 1。 2.消息队列内核创建的一个消息队列os中多个进程都能操作这个消息队列可以往里面发送消息可以接收消息。类似socket。 3.共享内存每个进程访问内存时有一个虚拟内存地址和物理内存地址的一个映射一般两个进程的虚拟内存地址可以一样但映射的物理内存地址一般不一样。共享内存就是将它们映射的物理内存地址也变一样这时两个进程能同时访问一块相同的物理内存于是借助这块物理内存实现通信。 4.套接字常见访问数据库进程和数据库进程本身这两个进程间通信就是通过3306号端口建立起的tcp套接字。本机访问mysql不走tcp的套接字而是走linux底层套接字。 5.信号量/灯类似一个计数器控制多个进程对一个共享资源的访问起到控制数量的锁机制。 6.信号一个进程可向另一个进程发送一个信号进程可处理这个信号。如下列出所有信号linux中信号大多数是把另一个进程杀死干脆把这个指令叫kill了如下64种死法。 如下是键盘中断ctrlc是当前shell向tail -f这个进程发送一个信号值为2的2SIGINT的信号。 10.1 捕捉信号ctrlc2 如下在死循环之前注册下信号的处理如下让ctrlc无效。 如下点击Build后就会将类编译出来。 如上ctrlc无法停止只能用killjps查看进程pid。 10.2 捕捉信号kill -99 10.3 捕捉信号kill15 将如上KILL换成TERM即SIGTERM重新build project。win下信号比linux下信号少很多将当前程序打包成jar包传到linux。用如下命令行打包。 如下用压缩软件打开1.jar。 如下后有一个空格最后一行是空行。 10.4 程序后台运行两种方法ctrlc无法中止用killall book1或kill 进程号。if fork()0return 0 父进程退出 信号作用服务程序在后台运行如果想终止它杀了它不是个好办法因为没有释放资源。如果能向程序发一个信号程序收到这个信号后调用一个函数在函数中编写释放资源代码程序就可以安全体面退出。 下面 EXIT函数就是自定义函数TcpServer设为全局变量因为EXIT函数要访问它并关闭socket。 1._public.h #ifndef _PUBLIC_H #define _PUBLIC_H 1 #include _cmpublic.h //全路径文件名大小时间的结构体 struct st_fileinfo {char filename[301];int filesize;char mtime[21]; };//1111111111111111111.读取某目录下的全部的文件 class CDir { public:char m_DirName[301]; // 目录名char m_FileName[301]; // 文件名不包括目录名char m_FullFileName[301]; // 文件全名包括目录名int m_FileSize; // 文件的大小char m_ModifyTime[21]; // 文件最后一次被修改的时间char m_CreateTime[21]; // 文件生成的时间char m_AccessTime[21]; // 文件最后一次被访问的时间int m_uPOS; // 已读取m_vFileName容器的位置vectorstring m_vFileName; // 存放OpenDir方法获取到的文件列表CDir();// 变量初始化void initdata();// 设置日期时间的格式支持yyyy-mm-dd hh24:mi:ss和yyyymmddhh24miss两种格式缺省是前者char m_DateFMT[21];void SetDateFMT(const char *in_DateFMT);// 打开目录获取文件名信息存放于m_vFileName容器中// in_DirName待打开的目录名// in_MatchStr待获取文件名的匹配规则// in_MaxCount获取文件的最大数量// bAndChild是否打开各级子目录// bSort是否对结果集进行排序bool OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount10000,const bool bAndChildfalse,bool bSortfalse);// 这是一个递归函数用于OpenDir()的调用。bool _OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild);// 逐个读取目录中的文件信息bool ReadDir();~CDir(); };//111111111111111111112.STRCPY、STRNCPY、STRCAT、STRNCAT四个函数弥补库函数的缺陷 // 以后可以用这四个函数取代strcpy、strncpy、strcat、strncat // 函数的第二个参数是第一个参数dest有效长度即占用内存的字节数-1。 // 该系列函数解决三个问题1变量初始化2内存溢出3修复strncpy的缺陷。 char *STRCPY(char* dest,const size_t destlen,const char* src); char *STRNCPY(char* dest,const size_t destlen,const char* src,size_t n); char *STRCAT(char* dest,const size_t destlen,const char* src); char *STRNCAT(char* dest,const size_t destlen,const char* src,size_t n);int SNPRINTF(char *str, size_t size, const char *fmt, ...);// 把整数的时间转换为字符串格式的时间格式如2019-02-08 12:05:08如果转换成功函数返回0失败返回-1函数的声明如下 int timetostr(const time_t ti,char *strtime);// 把字符串格式的时间转换为整数的时间函数的声明如下 int strtotime(const char *strtime,time_t *ti);// 从文件文件中读取一行 // strEndStr是一行数据的结束标志如果为空则以换行符\n为结束标志。 // 本函数不会删除行的结束标志 bool FGETS(const FILE *fp,char *strBuffer,const int ReadSize,const char *strEndStr0);//11111111111111111111113.文件操作类声明 class CFile { private:FILE *m_fp; // 文件指针bool m_bEnBuffer; // 是否启用缓冲区true-启用false-不启用char m_filename[301]; // 文件名char m_filenametmp[301]; // 临时文件名public:CFile(); // 类的构造函数~CFile(); // 类的析构函数bool IsOpened(); // 判断文件是否已打开// 打开文件参数与fopen相同打开成功true失败返回false bool Open(const char *filename,const char *openmode,bool bEnBuffertrue);// 关闭文件指针并删除文件bool CloseAndRemove();// 专为改名而创建文件参数与fopen相同打开成功true失败返回false // 函数将会创建filename后加.tmp的临时文件调用CloseAndRename()后才把临时文件改名为正式文件bool OpenForRename(const char *filename,const char *openmode,bool bEnBuffertrue);// 关闭文件并改名bool CloseAndRename();// 调用fprintf向文件写入数据void Fprintf(const char *fmt, ... );// 调用fgets从文件中读取一行bDelCRTtrue删除换行符false不删除缺省为falsebool Fgets(char *strBuffer,const int ReadSize,bool bDelCRTfalse);// 从文件文件中读取一行// strEndStr是一行数据的结束标志如果为空则以换行符\n为结束标志。// 与Fgets不同本函数不删除结束标志bool FFGETS(char *strBuffer,const int ReadSize,const char *strEndStr0);// 调用fread从文件中读取数据size_t Fread(void *ptr,size_t size);// 调用fwrite向文件中写数据size_t Fwrite(const void *ptr,size_t size);// 关闭文件指针如果存在临时文件就删除它。void Close(); };//1111111111111111111111111111114.拆分字符串的类 // 字符串的格式为:内容1分隔字符串内容2分隔字符串内容3 // 如:num~!~name~!~address,分隔符为~!~ class CCmdStr { public:vectorstring m_vCmdStr; // 存放拆分后的字段内容。CCmdStr();// 拆分字符串到容器中void SplitToCmd(const string in_string,const char *in_sep,const bool bdeletespacetrue);int CmdCount();// 获取字段的值取每个字段的值inum从0开始bool GetValue(const int inum,char *in_return);bool GetValue(const int inum,char *in_return,const int in_len);bool GetValue(const int inum,int *in_return);bool GetValue(const int inum,long *in_return);bool GetValue(const int inum,double *in_return);~CCmdStr(); };// 删除字符串左边指定的字符 void DeleteLChar(char *in_string,const char in_char);// 删除字符串右边指定的字符 void DeleteRChar(char *in_string,const char in_char);// 删除字符串两边指定的字符 void DeleteLRChar(char *in_string,const char in_char);//11111111111111111115.取操作系统的时间 /*out_stime是输出结果in_interval是偏移常量单位是秒返回的格式由fmt决定fmt目前的取值如下如果需要可以增加yyyy-mm-dd hh:mi:ss此格式是缺省格式,长度为19yyyymmddhhmissyyyy-mm-ddyyyymmddhh:mi:sshhmisshh:mihhmihhmi */ void LocalTime(char *out_stime,const char *in_fmt0,const int in_interval0);//日志文件操作类 #define MAXLOGFSIZE 100 // 日志文件切换的大小 // 日志文件操作类 class CLogFile { public:FILE *m_tracefp; // 日志文件指针char m_filename[301]; // 日志文件全名char m_openmode[11]; // 日志文件的打开方式bool m_bBackup; // 日志文件超出MAXLOGFSIZE是否自动备份bool m_bEnBuffer; // 写入日志时是否启用操作系统的缓冲机制CLogFile();// filename日志文件名// openmode打开文件的方式操作日志文件的权限,同打开文件函数(fopen)使用方法一致一般采用a// bBackuptrue-备份false-不备份在多进程的服务程序中如果多个进行共用一个日志文件bBackup必须为false// bEnBuffer:true-启用缓冲区false-不启用缓冲区如果启用缓冲区那么写进日志文件中的内容不会立即写入文件// 注意bEnBuffer参数的值如果设置为true可能会导致日志文件内容不完整。bool Open(const char *in_filename,const char *in_openmode,bool bBackuptrue,bool bEnBufferfalse);// 如果日志文件大于100M就备份它// 备份后的文件会在源文件名后加上日期时间// 注意在多进程程序中日志文件不可切换多线程程序中日志文件可切换。bool BackupLogFile();// 写日志文件,它是个可变参数的方法,同printf函数。// Write()方法会写入时间WriteEx()方法不写时间。bool Write(const char *fmt,...);bool WriteEx(const char *fmt,...);// 关闭日志文件void Close();~CLogFile(); };// 关闭全部的信号和输入输出 void CloseIOAndSignal();// 用某文件或目录的全路径中的目录创建目录以及该目录下的各级子目录 // pathorfilename 目录名或文件名 // bisfilename true-pathorfilename是文件名否则是目录名 bool MKDIR(const char *pathorfilename,bool bisfilenametrue);// 删除文件如果删除失败会尝试in_times次 bool REMOVE(const char *in_filename,const int in_times3);// 把in_srcfilename改名为in_dstfilename如果改名失败会尝试in_times次 bool RENAME(const char *in_srcfilename,const char *in_dstfilename,const int in_times3);// 把某一个文件复制到另一个文件 bool COPY(const char *srcfilename,const char *dstfilename);// 调用fopen函数打开文件如果文件名中包含的目录不存在就创建目录 FILE *FOPEN(const char *filename,const char *mode);// 获取文件的大小返回字节数 int FileSize(const char *in_FullFileName);// 获取文件的时间即modtime void FileMTime(const char *in_FullFileName,char *out_ModTime);// 更改文件的修改时间属性mtime指定了时间格式不限只要包括了yyyy,mm,dd,hh24,mi,ss即可。 int UTime(const char *filename,const char *mtime);// 把字符串格式的时间转换为time_t // stime为输入的时间格式不限但一定要包括yyyymmddhh24miss time_t UTCTime(const char *stime);// 从一个字符串中提取数字、符号和小数点并判断是否是一个合法的数 // 如果不合法将返回空字符串 // bWithSigntrue表示包括符号bWithDOTtrue表示包括圆点 void PickNumber(const char *strSrc,char *strDst,const bool bWithSign,const bool bWithDOT);// 判断字符串中的负号和圆点是否合法 bool JudgeSignDOT(const char *strSrc,const char *strBZ);/*把一个字符串表格的时间加上一个偏移量得到偏移后的时间in_stime是传入的时间任意格式但是一定要包括yyyymmddhh24miss是否有分隔符没有关系。把yyyy-mm-dd hh24:mi:ss偏移in_interval秒传出的格式由fmt决定fmt目前的取值如下如果需要可以增加yyyy-mm-dd hh24:mi:ss此格式是缺省格式yyyymmddhh24missyyyymmddhh24missyyyy-mm-ddyyyymmddhh24:mi:sshh24misshh24:mihh24mi返回值0-成功-1-失败。 */ int AddTime(const char *in_stime,char *out_stime,const int in_interval,const char *in_fmt0);//1111111111111111111111116.以下是XML格式字符串的相关操作函数和类 // 操作XMLBuffer的函数 // in_XMLBufferXML格式的字符串如下 // filename/tmp/readme.txt/filenamemtime2018-01-01 12:20:35/mtimesize10241/size // in_FieldName字段的标签名 // out_Value获取内容存放的变量的指针 bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,bool *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,int *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,unsigned int *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,long *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,unsigned long *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,double *out_Value); bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,char *out_Value,const int in_StrLen0);//11111111111111111111111117.判断文件名是否匹配in_MatchStr指定的规则 // in_FileName文件名 // in_MatchStr规则表达式如*.txt,*.xml中间用逗号分隔 bool MatchFileName(const string in_FileName,const string in_MatchStr);// 把小写转换成大写忽略不是字母的字符 void ToUpper(char *str); void ToUpper(string str);// 把大写转换成小写忽略不是字母的字符 void ToLower(char *str); void ToLower(string str);// 字符串替换函数 // 把in_string中的in_str1替换为in_str2 // bLoop是否循环执行替换 // 注意 // 1、如果in_str2比in_str1要长替换后in_string会变长所以必须保证in_string有足够的长度 否则内存会溢出 // 2、如果in_str2中包函了in_str1的内容且bLoop为true就会进入死循环最终导致内存溢出 void UpdateStr(char *in_string,const char *in_str1,const char *in_str2,bool bLooptrue);//111111111111111111111118.以下是TCP/IP通讯的函数和类 // socket通信的客户端类 class CTcpClient { public:int m_sockfd; // 客户端的socket.char m_ip[21]; // 服务端的ip地址。int m_port; // 与服务端通信的端口。bool m_state; // 与服务端的socket连接状态。bool m_btimeout; // 调用Read和Write方法时失败的原因是否是超时true-未超时false-已超时。int m_buflen; // 调用Read方法后接收到的报文的大小单位字节。CTcpClient(); // 构造函数。// 向服务端发起连接请求。// ip服务端的ip地址。// port服务端监听的端口。// 返回值true-成功false-失败。bool ConnectToServer(const char *ip,const int port);// 接收服务端发送过来的数据。// buffer接收数据缓冲区的地址数据的长度存放在m_buflen成员变量中。// itimeout等待数据的超时时间单位秒缺省值是0-无限等待。// 返回值true-成功false-失败失败有两种情况1等待超时成员变量m_btimeout的值被设置为true2socket连接已不可用。bool Read(char *buffer,const int itimeout0);// 向服务端发送数据。// buffer待发送数据缓冲区的地址。// ibuflen待发送数据的大小单位字节缺省值为0如果发送的是ascii字符串ibuflen取0如果是二进制流数据ibuflen为二进制数据块的大小。// 返回值true-成功false-失败如果失败表示socket连接已不可用。bool Write(const char *buffer,const int ibuflen0);// 断开与服务端的连接void Close();~CTcpClient(); // 析构函数自动关闭socket释放资源。 };// socket通信的服务端类 class CTcpServer { private:int m_socklen; // 结构体struct sockaddr_in的大小。struct sockaddr_in m_clientaddr; // 客户端的地址信息。struct sockaddr_in m_servaddr; // 服务端的地址信息。 public:int m_listenfd; // 服务端用于监听的socket。int m_connfd; // 客户端连接上来的socket。bool m_btimeout; // 调用Read和Write方法时失败的原因是否是超时true-未超时false-已超时。int m_buflen; // 调用Read方法后接收到的报文的大小单位字节。CTcpServer(); // 构造函数。// 服务端初始化。// port指定服务端用于监听的端口。// 返回值true-成功false-失败一般情况下只要port设置正确没有被占用初始化都会成功。bool InitServer(const unsigned int port); // 阻塞等待客户端的连接请求。// 返回值true-有新的客户端已连接上来false-失败Accept被中断如果Accept失败可以重新Accept。bool Accept();// 获取客户端的ip地址。// 返回值客户端的ip地址如192.168.1.100。char *GetIP();// 接收客户端发送过来的数据。// buffer接收数据缓冲区的地址数据的长度存放在m_buflen成员变量中。// itimeout等待数据的超时时间单位秒缺省值是0-无限等待。// 返回值true-成功false-失败失败有两种情况1等待超时成员变量m_btimeout的值被设置为true2socket连接已不可用。bool Read(char *buffer,const int itimeout);// 向客户端发送数据。// buffer待发送数据缓冲区的地址。// ibuflen待发送数据的大小单位字节缺省值为0如果发送的是ascii字符串ibuflen取0如果是二进制流数据ibuflen为二进制数据块的大小。// 返回值true-成功false-失败如果失败表示socket连接已不可用。bool Write(const char *buffer,const int ibuflen0);// 关闭监听的socket即m_listenfd常用于多进程服务程序的子进程代码中。void CloseListen();// 关闭客户端的socket即m_connfd常用于多进程服务程序的父进程代码中。void CloseClient();~CTcpServer(); // 析构函数自动关闭socket释放资源。 };// 接收socket的对端发送过来的数据。 // sockfd可用的socket连接。 // buffer接收数据缓冲区的地址。 // ibuflen本次成功接收数据的字节数。 // itimeout接收等待超时的时间单位秒缺省值是0-无限等待。 // 返回值true-成功false-失败失败有两种情况1等待超时2socket连接已不可用。 bool TcpRead(const int sockfd,char *buffer,int *ibuflen,const int itimeout0);// 向socket的对端发送数据。 // sockfd可用的socket连接。 // buffer待发送数据缓冲区的地址。 // ibuflen待发送数据的字节数如果发送的是ascii字符串ibuflen取0如果是二进制流数据ibuflen为二进制数据块的大小。 // 返回值true-成功false-失败如果失败表示socket连接已不可用。 bool TcpWrite(const int sockfd,const char *buffer,const int ibuflen0);// 从已经准备好的socket中读取数据。 // sockfd已经准备好的socket连接。 // buffer接收数据缓冲区的地址。 // n本次接收数据的字节数。 // 返回值成功接收到n字节的数据后返回truesocket连接不可用返回false。 bool Readn(const int sockfd,char *buffer,const size_t n);// 向已经准备好的socket中写入数据。 // sockfd已经准备好的socket连接。 // buffer待发送数据缓冲区的地址。 // n待发送数据的字节数。 // 返回值成功发送完n字节的数据后返回truesocket连接不可用返回false。 bool Writen(const int sockfd,const char *buffer,const size_t n);//111111111111111111119.这是一个精确到微秒的计时器 class CTimer { public:struct timeval m_start,m_end;CTimer();// 开始计时void Start();// 计算已逝去的时间单位秒小数点后面是微秒double Elapsed(); };#endif2._public.cpp #include _public.h int SNPRINTF(char *str, size_t size, const char *fmt, ...) {memset(str,0,size1);va_list arg;va_start( arg, fmt );vsnprintf( str,size, fmt, arg );va_end( arg ); }char *STRCPY(char* dest,const size_t destlen,const char* src) {memset(dest,0,destlen1); if (strlen(src)destlen) strncpy(dest,src,destlen);else strcpy(dest,src);return dest; }char *STRNCPY(char* dest,const size_t destlen,const char* src,size_t n) {memset(dest,0,destlen1); if (ndestlen) strncpy(dest,src,destlen);else strncpy(dest,src,n);return dest; }char *STRCAT(char* dest,const size_t destlen,const char* src) {memset(deststrlen(dest),0,destlen-strlen(dest)1); int leftdestlen-strlen(dest);int len0;if (strlen(src)left) lenleft;else lenstrlen(src);strncat(dest,src,len);return dest; }char *STRNCAT(char* dest,const size_t destlen,const char* src,size_t n) {memset(deststrlen(dest),0,destlen-strlen(dest)1); int leftdestlen-strlen(dest);int len0;if (nleft) lenleft;else lenn;strncat(dest,src,len);return dest; }// 把整数的时间转换为字符串格式的时间格式如2019-02-08 12:05:08如果转换成功函数返回0失败返回-1函数的声明如下 int timetostr(const time_t ti,char *strtime) {struct tm *sttm; if ( (sttmlocaltime(ti))0 ) return -1;sprintf(strtime,%d-%02d-%02d %02d:%02d:%02d,\sttm-tm_year1900,sttm-tm_mon1,sttm-tm_mday,sttm-tm_hour,sttm-tm_min,sttm-tm_sec);return 0; }// 把字符串格式的时间转换为整数的时间函数的声明如下 int strtotime(const char *strtime,time_t *ti) {char strtmp[11];//2019-02-08 12:05:08struct tm sttm; memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime,4);sttm.tm_yearatoi(strtmp)-1900;memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime5,2);sttm.tm_monatoi(strtmp)-1;memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime8,2);sttm.tm_mdayatoi(strtmp);memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime11,2);sttm.tm_houratoi(strtmp);memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime14,2);sttm.tm_minatoi(strtmp);memset(strtmp,0,sizeof(strtmp));strncpy(strtmp,strtime17,2);sttm.tm_secatoi(strtmp);*timktime(sttm);return *ti; }CFile::CFile() // 类的构造函数 {m_fp0;m_bEnBuffertrue;memset(m_filename,0,sizeof(m_filename));memset(m_filenametmp,0,sizeof(m_filenametmp)); }// 关闭文件指针 void CFile::Close() {if (m_fp0) return;fclose(m_fp); // 关闭文件指针m_fp0;memset(m_filename,0,sizeof(m_filename));// 如果存在临时文件就删除它。if (strlen(m_filenametmp)!0) remove(m_filenametmp);memset(m_filenametmp,0,sizeof(m_filenametmp)); }// 判断文件是否已打开 bool CFile::IsOpened() {if (m_fp0) return false;return true; }// 关闭文件指针并删除文件 bool CFile::CloseAndRemove() {if (m_fp0) return true;fclose(m_fp); // 关闭文件指针m_fp0;if (remove(m_filename) ! 0) { memset(m_filename,0,sizeof(m_filename)); return false; }memset(m_filename,0,sizeof(m_filename));return true; }CFile::~CFile() // 类的析构函数 {Close(); }// 打开文件参数与FOPEN相同打开成功true失败返回false bool CFile::Open(const char *filename,const char *openmode,bool bEnBuffer) {Close();if ( (m_fpFOPEN(filename,openmode)) 0 ) return false;memset(m_filename,0,sizeof(m_filename));strncpy(m_filename,filename,300);m_bEnBufferbEnBuffer;return true; }// 专为改名而打开文件参数与fopen相同打开成功true失败返回false bool CFile::OpenForRename(const char *filename,const char *openmode,bool bEnBuffer) {Close();memset(m_filename,0,sizeof(m_filename));strncpy(m_filename,filename,300);memset(m_filenametmp,0,sizeof(m_filenametmp));SNPRINTF(m_filenametmp,300,%s.tmp,m_filename);if ( (m_fpFOPEN(m_filenametmp,openmode)) 0 ) return false;m_bEnBufferbEnBuffer;return true; }// 关闭文件并改名 bool CFile::CloseAndRename() {if (m_fp0) return false;fclose(m_fp); // 关闭文件指针m_fp0;if (rename(m_filenametmp,m_filename) ! 0){remove(m_filenametmp);memset(m_filename,0,sizeof(m_filename));memset(m_filenametmp,0,sizeof(m_filenametmp));return false;}memset(m_filename,0,sizeof(m_filename));memset(m_filenametmp,0,sizeof(m_filenametmp));return true; }// 调用fprintf向文件写入数据 void CFile::Fprintf(const char *fmt, ... ) {if ( m_fp 0 ) return;va_list arg;va_start( arg, fmt );vfprintf( m_fp, fmt, arg );va_end( arg );if ( m_bEnBuffer false ) fflush(m_fp); }// 调用fgets从文件中读取一行bDelCRTtrue删除换行符false不删除缺省为false bool CFile::Fgets(char *strBuffer,const int ReadSize,bool bDelCRT) {if ( m_fp 0 ) return false;memset(strBuffer,0,ReadSize1);if (fgets(strBuffer,ReadSize,m_fp) 0) return false;if (bDelCRTtrue){DeleteRChar(strBuffer,\n); DeleteRChar(strBuffer,\r);}return true; }// 从文件文件中读取一行 // strEndStr是一行数据的结束标志如果为空则以换行符\n为结束标志。 // 与Fgets不同本函数不删除结束标志 bool CFile::FFGETS(char *strBuffer,const int ReadSize,const char *strEndStr) {return FGETS(m_fp,strBuffer,ReadSize,strEndStr); }// 调用fread从文件中读取数据。 size_t CFile::Fread(void *ptr, size_t size) {if ( m_fp 0 ) return -1;return fread(ptr,1,size,m_fp); }// 调用fwrite向文件中写数据 size_t CFile::Fwrite(const void *ptr, size_t size ) {if ( m_fp 0 ) return -1;size_t ttfwrite(ptr,1,size,m_fp);if ( m_bEnBuffer false ) fflush(m_fp);return tt; }// 从文件文件中读取一行 // strEndStr是一行数据的结束标志如果为空则以换行符\n为结束标志。 // 本函数不会删除行的结束标志 bool FGETS(const FILE *fp,char *strBuffer,const int ReadSize,const char *strEndStr) {char strLine[ReadSize1];memset(strLine,0,sizeof(strLine));while (true){memset(strLine,0,ReadSize1);if (fgets(strLine,ReadSize,(FILE *)fp) 0) break;// 防止strBuffer溢出if ( (strlen(strBuffer)strlen(strLine)) (unsigned int)ReadSize ) break;strcat(strBuffer,strLine);if (strEndStr 0) return true;if (strstr(strLine,strEndStr)! 0) return true;}return false; }CCmdStr::CCmdStr() {m_vCmdStr.clear(); }void CCmdStr::SplitToCmd(const string in_string,const char *in_sep,const bool bdeletespace) {// 清除所有的旧数据m_vCmdStr.clear();int iPOS0;string srcstr,substr;srcstrin_string;char str[2048];while ( (iPOSsrcstr.find(in_sep)) 0){substrsrcstr.substr(0,iPOS);if (bdeletespace true){memset(str,0,sizeof(str));strncpy(str,substr.c_str(),2000);DeleteLRChar(str, );substrstr;}m_vCmdStr.push_back(substr);iPOSiPOSstrlen(in_sep);srcstrsrcstr.substr(iPOS,srcstr.size()-iPOS);}substrsrcstr;if (bdeletespace true){memset(str,0,sizeof(str));strncpy(str,substr.c_str(),2000);DeleteLRChar(str, );substrstr;}m_vCmdStr.push_back(substr);return; }int CCmdStr::CmdCount() {return m_vCmdStr.size(); }bool CCmdStr::GetValue(const int inum,char *in_return) {if (inum m_vCmdStr.size()) return false;strcpy(in_return,m_vCmdStr[inum].c_str());return true; }bool CCmdStr::GetValue(const int inum,char *in_return,const int in_len) {memset(in_return,0,in_len1);if (inum m_vCmdStr.size()) return false;if (m_vCmdStr[inum].length() (unsigned int)in_len){strncpy(in_return,m_vCmdStr[inum].c_str(),in_len);}else{strcpy(in_return,m_vCmdStr[inum].c_str());}return true; }bool CCmdStr::GetValue(const int inum,int *in_return) {(*in_return) 0;if (inum m_vCmdStr.size()) return false;(*in_return) atoi(m_vCmdStr[inum].c_str());return true; }bool CCmdStr::GetValue(const int inum,long *in_return) {(*in_return) 0;if (inum m_vCmdStr.size()) return false;(*in_return) atol(m_vCmdStr[inum].c_str());return true; }bool CCmdStr::GetValue(const int inum,double *in_return) {(*in_return) 0;if (inum m_vCmdStr.size()) return false;(*in_return) (double)atof(m_vCmdStr[inum].c_str());return true; }CCmdStr::~CCmdStr() {m_vCmdStr.clear(); }/* 删除字符串左边指定的字符 */ void DeleteLChar(char *in_string,const char in_char) {if (in_string 0) return;if (strlen(in_string) 0) return;char strTemp[strlen(in_string)1];int iTemp0;memset(strTemp,0,sizeof(strTemp));strcpy(strTemp,in_string);while ( strTemp[iTemp] in_char ) iTemp;memset(in_string,0,strlen(in_string)1);strcpy(in_string,strTempiTemp);return; }/* 删除字符串右边指定的字符 */ void DeleteRChar(char *in_string,const char in_char) {if (in_string 0) return;int istrlen strlen(in_string);while (istrlen0){if (in_string[istrlen-1] ! in_char) break;in_string[istrlen-1]0;istrlen--;} }/* 删除字符串两边指定的字符 */ void DeleteLRChar(char *in_string,const char in_char) {DeleteLChar(in_string,in_char);DeleteRChar(in_string,in_char); }/*取操作系统的时间out_stime是输出结果in_interval是偏移常量单位是秒返回的格式由fmt决定fmt目前的取值如下如果需要可以增加yyyy-mm-dd hh24:mi:ss此格式是缺省格式yyyymmddhh24missyyyy-mm-ddyyyymmddhh24:mi:sshh24misshh24:mihh24mihh24mi */ void LocalTime(char *out_stime,const char *in_fmt,const int in_interval) {if (in_fmt 0) memset(out_stime,0,191);else memset(out_stime,0,strlen(in_fmt)1); time_t timer;struct tm nowtimer;time( timer ); timertimerin_interval;nowtimer *localtime ( timer ); nowtimer.tm_mon;if (in_fmt0){snprintf(out_stime,20,%04u-%02u-%02u %02u:%02u:%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);return;}if (strcmp(in_fmt,yyyy-mm-dd hh24:mi:ss) 0){snprintf(out_stime,20,%04u-%02u-%02u %02u:%02u:%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);return;}if (strcmp(in_fmt,yyyy-mm-dd hh24:mi) 0){snprintf(out_stime,17,%04u-%02u-%02u %02u:%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min);return;}if (strcmp(in_fmt,yyyy-mm-dd hh24) 0){snprintf(out_stime,14,%04u-%02u-%02u %02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour);return;}if (strcmp(in_fmt,yyyy-mm-dd) 0){snprintf(out_stime,11,%04u-%02u-%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday); return;}if (strcmp(in_fmt,yyyy-mm) 0){snprintf(out_stime,8,%04u-%02u,nowtimer.tm_year1900,nowtimer.tm_mon); return;}if (strcmp(in_fmt,yyyymmddhh24miss) 0){snprintf(out_stime,15,%04u%02u%02u%02u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);return;}if (strcmp(in_fmt,yyyymmddhh24mi) 0){snprintf(out_stime,13,%04u%02u%02u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min);return;}if (strcmp(in_fmt,yyyymmddhh24) 0){snprintf(out_stime,11,%04u%02u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour);return;}if (strcmp(in_fmt,yyyymmdd) 0){snprintf(out_stime,9,%04u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday); return;}if (strcmp(in_fmt,hh24miss) 0){snprintf(out_stime,7,%02u%02u%02u,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); return;}if (strcmp(in_fmt,hh24mi) 0){snprintf(out_stime,5,%02u%02u,nowtimer.tm_hour,nowtimer.tm_min); return;}if (strcmp(in_fmt,hh24) 0){snprintf(out_stime,3,%02u,nowtimer.tm_hour); return;}if (strcmp(in_fmt,mi) 0){snprintf(out_stime,3,%02u,nowtimer.tm_min); return;} }CLogFile::CLogFile() {m_tracefp 0;memset(m_filename,0,sizeof(m_filename));memset(m_openmode,0,sizeof(m_openmode));m_bBackuptrue;m_bEnBufferfalse; //日志文件一般不启用缓冲区可以立即看到 }CLogFile::~CLogFile() {Close(); }void CLogFile::Close() {if (m_tracefp ! 0){fclose(m_tracefp); m_tracefp0;} }// filename日志文件名 // openmode打开文件的方式操作日志文件的权限,同打开文件函数(FOPEN)使用方法一致 // bBackuptrue-备份false-不备份在多进程的服务程序中如果多个进行共用一个日志文件bBackup必须为false // bEnBuffer:true-启用缓冲区false-不启用缓冲区如果启用缓冲区那么写进日志文件中的内容不会立即写入文件是 bool CLogFile::Open(const char *in_filename,const char *in_openmode,bool bBackup,bool bEnBuffer) {if (m_tracefp ! 0) { fclose(m_tracefp); m_tracefp0; }m_bEnBufferbEnBuffer;memset(m_filename,0,sizeof(m_filename));strcpy(m_filename,in_filename);memset(m_openmode,0,sizeof(m_openmode));strcpy(m_openmode,in_openmode);if ((m_tracefpFOPEN(m_filename,m_openmode)) NULL) return false;m_bBackupbBackup;return true; }// 如果日志文件大于MAXLOGFSIZE就备份它 bool CLogFile::BackupLogFile() {// 不备份if (m_bBackup false) return true;if (m_tracefp 0) return true;fseek(m_tracefp,0L,2); //定位到文件最后我们打开日志文件用a或a这种方式一打开任何时候文件指针都是在文件最后这行代码可省if (ftell(m_tracefp) MAXLOGFSIZE*1024*1024) // 看看文件有多大{fclose(m_tracefp); m_tracefp0;char strLocalTime[21];memset(strLocalTime,0,sizeof(strLocalTime));LocalTime(strLocalTime,yyyymmddhhmiss);char bak_filename[301];memset(bak_filename,0,sizeof(bak_filename));snprintf(bak_filename,300,%s.%s,m_filename,strLocalTime);rename(m_filename,bak_filename); printf(rename %s m_filename ok\n,bak_filename);if ((m_tracefpFOPEN(m_filename,m_openmode)) NULL) return false;}return true; }bool CLogFile::Write(const char *fmt,...) {if (BackupLogFile() false) return false;char strtime[20]; LocalTime(strtime);va_list ap;va_start(ap,fmt);if (m_tracefp 0) // m_tracefp日志文件指针{fprintf(stdout,%s ,strtime); // stdoutC语言缺省的标准输出strtime输出时间vfprintf(stdout,fmt,ap); // ap输出内容if (m_bEnBufferfalse) fflush(stdout);}else{fprintf(m_tracefp,%s ,strtime);vfprintf(m_tracefp,fmt,ap);if (m_bEnBufferfalse) fflush(m_tracefp);}va_end(ap);return true; }bool CLogFile::WriteEx(const char *fmt,...) {va_list ap;va_start(ap,fmt);if (m_tracefp 0){vfprintf(stdout,fmt,ap);if (m_bEnBufferfalse) fflush(stdout);}else{vfprintf(m_tracefp,fmt,ap);if (m_bEnBufferfalse) fflush(m_tracefp);}va_end(ap);return true; }// 关闭全部的信号和输入输出 void CloseIOAndSignal() {int ii0;for (ii0;ii50;ii){signal(ii,SIG_IGN); close(ii);} }// 用某文件或目录的全路径中的目录创建目录以级该目录下的各级子目录 bool MKDIR(const char *filename,bool bisfilename) {// 检查目录是否存在如果不存在逐级创建子目录char strPathName[301];for (int ii1; iistrlen(filename);ii){if (filename[ii] ! /) continue;memset(strPathName,0,sizeof(strPathName));strncpy(strPathName,filename,ii);if (access(strPathName,F_OK) 0) continue;if (mkdir(strPathName,00755) ! 0) return false;}if (bisfilenamefalse){if (access(filename,F_OK) ! 0){if (mkdir(filename,00755) ! 0) return false;}}return true; }// 调用fopen函数打开文件如果文件名中包含的目录不存在就创建目录 FILE *FOPEN(const char *filename,const char *mode) {if (MKDIR(filename) false) return NULL;return fopen(filename,mode); }// 获取文件的大小返回字节数 int FileSize(const char *in_FullFileName) {struct stat st_filestat;if (stat(in_FullFileName,st_filestat) 0) return -1;return st_filestat.st_size; }// 更改文件的修改时间属性 int UTime(const char *filename,const char *mtime) {struct utimbuf stutimbuf;stutimbuf.actimestutimbuf.modtimeUTCTime(mtime);return utime(filename,stutimbuf); }// 把字符串格式的时间转换为time_t // stime为输入的时间格式不限但一定要包括yyyymmddhh24miss time_t UTCTime(const char *stime) {char strtime[21],yyyy[5],mm[3],dd[3],hh[3],mi[3],ss[3];memset(strtime,0,sizeof(strtime));memset(yyyy,0,sizeof(yyyy));memset(mm,0,sizeof(mm));memset(dd,0,sizeof(dd));memset(hh,0,sizeof(hh));memset(mi,0,sizeof(mi));memset(ss,0,sizeof(ss));PickNumber(stime,strtime,false,false);if (strlen(strtime) ! 14) return -1;strncpy(yyyy,strtime,4);strncpy(mm,strtime4,2);strncpy(dd,strtime6,2);strncpy(hh,strtime8,2);strncpy(mi,strtime10,2);strncpy(ss,strtime12,2);struct tm time_str;time_str.tm_year atoi(yyyy) - 1900;time_str.tm_mon atoi(mm) - 1;time_str.tm_mday atoi(dd);time_str.tm_hour atoi(hh);time_str.tm_min atoi(mi);time_str.tm_sec atoi(ss);time_str.tm_isdst 0;return mktime(time_str); }// 从一个字符串中提取数字bWithSigntrue表示包括负号bWithDOTtrue表示包括圆点 void PickNumber(const char *strSrc,char *strDst,const bool bWithSign,const bool bWithDOT) {char strtemp[1024];memset(strtemp,0,sizeof(strtemp));strncpy(strtemp,strSrc,1000);DeleteLRChar(strtemp, );// 为了防止strSrc和strDst为同一变量的情况所以strDst不能初始化// 判断字符串中的负号是否合法if ( (bWithSigntrue) (JudgeSignDOT(strtemp,-) false) ){strcpy(strDst,); return;}// 判断字符串中的正号是否合法if ( (bWithSigntrue) (JudgeSignDOT(strtemp,) false) ){strcpy(strDst,); return;}// 判断字符串中的圆点是否合法if ( (bWithDOTtrue) (JudgeSignDOT(strtemp,.) false) ){strcpy(strDst,); return;}int iPosSrc,iPosDst,iLen;iPosSrciPosDstiLen0;iLenstrlen(strtemp);for (iPosSrc0;iPosSrciLen;iPosSrc){if ( (bWithSigntrue) (strtemp[iPosSrc] ) ){strDst[iPosDst]strtemp[iPosSrc]; continue;}if ( (bWithSigntrue) (strtemp[iPosSrc] -) ){strDst[iPosDst]strtemp[iPosSrc]; continue;}if ( (bWithDOTtrue) (strtemp[iPosSrc] .) ){strDst[iPosDst]strtemp[iPosSrc]; continue;}if (isdigit(strtemp[iPosSrc])) strDst[iPosDst]strtemp[iPosSrc];}strDst[iPosDst]0;return; }// 判断字符串中的负号和圆点是否合法 bool JudgeSignDOT(const char *strSrc,const char *strBZ) {char *pos0;pos(char *)strstr(strSrc,strBZ);// 如果没有包括待搜索的字符串就返回trueif (pos 0) return true;// 如果strlen(pos)1表示结果中只有符号没有其它字符返回falseif (strlen(pos)1) return false;// 如果待搜索的字符串是号就一定要是第一个字符if ( (strcmp(strBZ,) 0) (strncmp(strSrc,,1) ! 0) ) return false;// 如果待搜索的字符串是-号就一定要是第一个字符if ( (strcmp(strBZ,-) 0) (strncmp(strSrc,-,1) ! 0) ) return false;// 如果包括多个待搜索的字符串就返回falseif (strstr(pos1,strBZ) 0) return false;return true; }/*把一个字符串表格的时间加上一个偏移量得到偏移后的时间in_stime是传入的时间任意格式但是一定要包括yyyymmddhh24miss是否有分隔符没有关系。把yyyy-mm-dd hh24:mi:ss偏移in_interval秒传出的格式由fmt决定fmt目前的取值如下如果需要可以增加yyyy-mm-dd hh24:mi:ss此格式是缺省格式yyyymmddhh24missyyyymmddhh24missyyyy-mm-ddyyyymmddhh24:mi:sshh24misshh24:mihh24mi返回值0-成功-1-失败。 */ int AddTime(const char *in_stime,char *out_stime,const int in_interval,const char *in_fmt) {time_t timer;struct tm nowtimer;timerUTCTime(in_stime)in_interval;nowtimer *localtime ( timer ); nowtimer.tm_mon;// 为了防止in_stime和out_stime为同一变量的情况所以out_stime在此处初始化代码不可提前out_stime[0]0;if (in_fmt0){snprintf(out_stime,20,%04u-%02u-%02u %02u:%02u:%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); return 0;}if (strcmp(in_fmt,yyyy-mm-dd hh24:mi:ss) 0){snprintf(out_stime,20,%04u-%02u-%02u %02u:%02u:%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); return 0;}if (strcmp(in_fmt,yyyymmddhh24miss) 0){snprintf(out_stime,15,%04u%02u%02u%02u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); return 0;}if (strcmp(in_fmt,yyyy-mm-dd) 0){snprintf(out_stime,11,%04u-%02u-%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday); return 0;}if (strcmp(in_fmt,yyyymmdd) 0){snprintf(out_stime,9,%04u%02u%02u,nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday); return 0;}if (strcmp(in_fmt,hh24:mi:ss) 0){snprintf(out_stime,9,%02u:%02u:%02u,nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); return 0;}if (strcmp(in_fmt,hh24:mi) 0){snprintf(out_stime,9,%02u:%02u,nowtimer.tm_hour,nowtimer.tm_min); return 0;}if (strcmp(in_fmt,hh24mi) 0){snprintf(out_stime,7,%02u%02u,nowtimer.tm_hour,nowtimer.tm_min); return 0;}return -1; }// 获取文件的时间即modtime void FileMTime(const char *in_FullFileName,char *out_ModTime) {struct tm nowtimer;struct stat st_filestat;stat(in_FullFileName,st_filestat);nowtimer *localtime(st_filestat.st_mtime);nowtimer.tm_mon;snprintf(out_ModTime,15,%04u%02u%02u%02u%02u%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec); }// 操作XMLBuffer的函数 // in_XMLBufferXML格式的字符串 // in_FieldName字段的标签名 // out_Value获取内容存放的变量的指针 bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,char *out_Value,const int in_Len) {strcpy(out_Value,);char *startNULL,*endNULL;char m_SFieldName[51],m_EFieldName[51];int m_NameLen strlen(in_FieldName);memset(m_SFieldName,0,sizeof(m_SFieldName));memset(m_EFieldName,0,sizeof(m_EFieldName));snprintf(m_SFieldName,50,%s,in_FieldName);snprintf(m_EFieldName,50,/%s,in_FieldName);start0; end0;start (char *)strstr(in_XMLBuffer,m_SFieldName);if (start ! 0){end (char *)strstr(start,m_EFieldName);}if ((start0) || (end 0)){return false;}int m_ValueLen end - start - m_NameLen - 2 1 ;if ( ((m_ValueLen-1) in_Len) || (in_Len 0) ){strncpy(out_Value,startm_NameLen2,m_ValueLen-1); out_Value[m_ValueLen-1]0;}else{strncpy(out_Value,startm_NameLen2,in_Len); out_Value[in_Len]0;}DeleteLRChar(out_Value, );return true; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,bool *out_Value) {(*out_Value) false;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,10) true){if ( (strcmp(strTemp,true)0) || (strcmp(strTemp,true)0) ) (*out_Value)true; return true;}return false; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,int *out_Value) {(*out_Value) 0;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,50) true){(*out_Value) atoi(strTemp); return true;}return false; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,unsigned int *out_Value) {(*out_Value) 0;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,50) true){(*out_Value) (unsigned int)atoi(strTemp); return true;}return false; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,long *out_Value) {(*out_Value) 0;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,50) true){(*out_Value) atol(strTemp); return true;}return false; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,unsigned long *out_Value) {(*out_Value) 0;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,50) true){(*out_Value) (unsigned long)atol(strTemp); return true;}return false; }bool GetXMLBuffer(const char *in_XMLBuffer,const char *in_FieldName,double *out_Value) {(*out_Value) 0;char strTemp[51];memset(strTemp,0,sizeof(strTemp));if (GetXMLBuffer(in_XMLBuffer,in_FieldName,strTemp,50) true){(*out_Value) atof(strTemp); return true;}return false; }// 判断文件名是否和MatchFileName匹配如果不匹配返回失败 bool MatchFileName(const string in_FileName,const string in_MatchStr) {// 如果用于比较的字符是空的返回falseif (in_MatchStr.size() 0) return false;// 如果被比较的字符串是“*”返回trueif (in_MatchStr *) return true;// 处理文件名匹配规则中的时间匹配dd-nn.mmchar strTemp[2049];memset(strTemp,0,sizeof(strTemp));strncpy(strTemp,in_MatchStr.c_str(),2000);int ii,jj;int iPOS1,iPOS2;CCmdStr CmdStr,CmdSubStr;string strFileName,strMatchStr;strFileNamein_FileName;strMatchStrstrTemp;// 把字符串都转换成大写后再来比较ToUpper(strFileName);ToUpper(strMatchStr);CmdStr.SplitToCmd(strMatchStr,,);for (ii0;iiCmdStr.CmdCount();ii){// 如果为空就一定要跳过否则就会被配上if (CmdStr.m_vCmdStr[ii].empty() true) continue;iPOS1iPOS20;CmdSubStr.SplitToCmd(CmdStr.m_vCmdStr[ii],*);for (jj0;jjCmdSubStr.CmdCount();jj){// 如果是文件名的首部if (jj 0){if (strncmp(strFileName.c_str(),CmdSubStr.m_vCmdStr[jj].c_str(),CmdSubStr.m_vCmdStr[jj].size()) ! 0) break;}// 如果是文件名的尾部if (jj CmdSubStr.CmdCount()-1){if (strcmp(strFileName.c_str()strFileName.size()-CmdSubStr.m_vCmdStr[jj].size(),CmdSubStr.m_vCmdStr[jj].c_str()) ! 0) break;}iPOS2strFileName.find(CmdSubStr.m_vCmdStr[jj],iPOS1);if (iPOS2 0) break;iPOS1iPOS2CmdSubStr.m_vCmdStr[jj].size();}if (jjCmdSubStr.CmdCount()) return true;}return false; }void ToUpper(char *str) {if (str 0) return;if (strlen(str) 0) return;int istrlenstrlen(str);for (int ii0;iiistrlen;ii){if ( (str[ii] 97) (str[ii] 122) ) str[ii]str[ii] - 32;} }void ToUpper(string str) {if (str.empty()) return;char strtemp[str.size()1];memset(strtemp,0,sizeof(strtemp));strcpy(strtemp,str.c_str());ToUpper(strtemp);strstrtemp;return; }void ToLower(char *str) {if (str 0) return;if (strlen(str) 0) return;int istrlenstrlen(str);for (int ii0;iiistrlen;ii){if ( (str[ii] 65) (str[ii] 90) ) str[ii]str[ii] 32;} }void ToLower(string str) {if (str.empty()) return;char strtemp[str.size()1];memset(strtemp,0,sizeof(strtemp));strcpy(strtemp,str.c_str());ToLower(strtemp);strstrtemp;return; }CDir::CDir() {m_uPOS0;memset(m_DateFMT,0,sizeof(m_DateFMT));strcpy(m_DateFMT,yyyy-mm-dd hh24:mi:ss);m_vFileName.clear();initdata(); }void CDir::initdata() {memset(m_DirName,0,sizeof(m_DirName));memset(m_FileName,0,sizeof(m_FileName));memset(m_FullFileName,0,sizeof(m_FullFileName));m_FileSize0;memset(m_CreateTime,0,sizeof(m_CreateTime));memset(m_ModifyTime,0,sizeof(m_ModifyTime));memset(m_AccessTime,0,sizeof(m_AccessTime)); }// 设置日期时间的格式支持yyyy-mm-dd hh24:mi:ss和yyyymmddhh24miss两种格式缺省是前者 void CDir::SetDateFMT(const char *in_DateFMT) {memset(m_DateFMT,0,sizeof(m_DateFMT));strcpy(m_DateFMT,in_DateFMT); }// 打开目录获取文件名信息存放于m_vFileName容器中 // in_dirname待打开的目录名 // in_MatchStr待获取文件名的匹配规则 // in_MaxCount获取文件的最大数量 // bAndChild是否打开各级子目录 // bSort是否对结果时行排序 bool CDir::OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild,bool bSort) {m_uPOS0;m_vFileName.clear();// 如果目录不存在就创建该目录if (MKDIR(in_DirName,false) false) return false;bool bRet_OpenDir(in_DirName,in_MatchStr,in_MaxCount,bAndChild);if (bSorttrue){sort(m_vFileName.begin(), m_vFileName.end());}return bRet; }// 打开目录这是个递归函数 bool CDir::_OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild) {DIR *dir;if ( (diropendir(in_DirName)) NULL ) return false;char strTempFileName[1024];struct dirent *st_fileinfo;struct stat st_filestat;while ((st_fileinforeaddir(dir)) ! NULL){// 以.打头的文件不处理if (st_fileinfo-d_name[0].) continue;memset(strTempFileName,0,sizeof(strTempFileName));snprintf(strTempFileName,300,%s//%s,in_DirName,st_fileinfo-d_name);UpdateStr(strTempFileName,//,/);stat(strTempFileName,st_filestat);// 判断是否是目录if (S_ISDIR(st_filestat.st_mode)){if (bAndChild true){if (_OpenDir(strTempFileName,in_MatchStr,in_MaxCount,bAndChild) false) {closedir(dir); return false;}}}else{if (MatchFileName(st_fileinfo-d_name,in_MatchStr) false) continue;m_vFileName.push_back(strTempFileName);if ( m_vFileName.size()in_MaxCount ) break;}}closedir(dir);return true; }bool CDir::ReadDir() {initdata();// 如果已读完清空容器if (m_uPOS m_vFileName.size()) {m_uPOS0; m_vFileName.clear(); return false;}int pos0;posm_vFileName[m_uPOS].find_last_of(/);// 目录名memset(m_DirName,0,sizeof(m_DirName));strcpy(m_DirName,m_vFileName[m_uPOS].substr(0,pos).c_str());// 文件名memset(m_FileName,0,sizeof(m_FileName));strcpy(m_FileName,m_vFileName[m_uPOS].substr(pos1,m_vFileName[m_uPOS].size()-pos-1).c_str());// 文件全名包括路径snprintf(m_FullFileName,300,%s,m_vFileName[m_uPOS].c_str());struct stat st_filestat;stat(m_FullFileName,st_filestat);m_FileSizest_filestat.st_size;struct tm nowtimer;if (strcmp(m_DateFMT,yyyy-mm-dd hh24:mi:ss) 0){nowtimer *localtime(st_filestat.st_mtime); nowtimer.tm_mon;snprintf(m_ModifyTime,20,%04u-%02u-%02u %02u:%02u:%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);nowtimer *localtime(st_filestat.st_ctime); nowtimer.tm_mon;snprintf(m_CreateTime,20,%04u-%02u-%02u %02u:%02u:%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);nowtimer *localtime(st_filestat.st_atime); nowtimer.tm_mon;snprintf(m_AccessTime,20,%04u-%02u-%02u %02u:%02u:%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);}if (strcmp(m_DateFMT,yyyymmddhh24miss) 0){nowtimer *localtime(st_filestat.st_mtime); nowtimer.tm_mon;snprintf(m_ModifyTime,20,%04u%02u%02u%02u%02u%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);nowtimer *localtime(st_filestat.st_ctime); nowtimer.tm_mon;snprintf(m_CreateTime,20,%04u%02u%02u%02u%02u%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);nowtimer *localtime(st_filestat.st_atime); nowtimer.tm_mon;snprintf(m_AccessTime,20,%04u%02u%02u%02u%02u%02u,\nowtimer.tm_year1900,nowtimer.tm_mon,nowtimer.tm_mday,\nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);}m_uPOS;return true; }CDir::~CDir() {m_vFileName.clear();// m_vDirName.clear(); }// 把字符串中的某字符串用另一个字符串代替 void UpdateStr(char *in_string,const char *in_str1,const char *in_str2,bool bLoop) {if (in_string 0) return;if (strlen(in_string) 0) return;char strTemp[2048];char *strStartin_string;char *strPos0;while (true){if (strlen(in_string) 2000) break;if (bLoop true){strPosstrstr(in_string,in_str1);}else{strPosstrstr(strStart,in_str1);}if (strPos 0) break;memset(strTemp,0,sizeof(strTemp));strncpy(strTemp,in_string,strPos-in_string);strcat(strTemp,in_str2);strcat(strTemp,strPosstrlen(in_str1));strcpy(in_string,strTemp);strStartstrPosstrlen(in_str2);} }// 删除文件如果删除失败会尝试in_times次 bool REMOVE(const char *in_filename,const int in_times) {// 如果文件不存在直接返回失败if (access(in_filename,R_OK) ! 0) return false;for (int ii0;iiin_times;ii){if (remove(in_filename) 0) return true;usleep(100000);}return false; }// 把in_srcfilename改名为in_dstfilename如果改名失败会尝试in_times次 bool RENAME(const char *in_srcfilename,const char *in_dstfilename,const int in_times) {// 如果文件不存在直接返回失败if (access(in_srcfilename,R_OK) ! 0) return false;if (MKDIR(in_dstfilename) false) return false;for (int ii0;iiin_times;ii){if (rename(in_srcfilename,in_dstfilename) 0) return true;usleep(100000);}return false; }CTcpClient::CTcpClient() {m_sockfd-1;memset(m_ip,0,sizeof(m_ip));m_port0;m_btimeoutfalse; }bool CTcpClient::ConnectToServer(const char *ip,const int port) {if (m_sockfd ! -1) { close(m_sockfd); m_sockfd -1; }strcpy(m_ip,ip);m_portport;struct hostent* h;struct sockaddr_in servaddr;if ( (m_sockfd socket(AF_INET,SOCK_STREAM,0) ) 0) return false;if ( !(h gethostbyname(m_ip)) ){close(m_sockfd); m_sockfd -1; return false;}memset(servaddr,0,sizeof(servaddr));servaddr.sin_family AF_INET;servaddr.sin_port htons(m_port); // 指定服务端的通讯端口memcpy(servaddr.sin_addr,h-h_addr,h-h_length);if (connect(m_sockfd, (struct sockaddr *)servaddr,sizeof(servaddr)) ! 0){close(m_sockfd); m_sockfd -1; return false;}return true; }bool CTcpClient::Read(char *buffer,const int itimeout) {if (m_sockfd -1) return false;if (itimeout0){fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(m_sockfd,tmpfd);struct timeval timeout;timeout.tv_sec itimeout; timeout.tv_usec 0;m_btimeout false;int i;if ( (i select(m_sockfd1,tmpfd,0,0,timeout)) 0 ){if (i0) m_btimeout true;return false;}}m_buflen 0;return (TcpRead(m_sockfd,buffer,m_buflen)); }bool CTcpClient::Write(const char *buffer,const int ibuflen) {if (m_sockfd -1) return false;fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(m_sockfd,tmpfd);struct timeval timeout;timeout.tv_sec 5; timeout.tv_usec 0;m_btimeout false;int i;if ( (iselect(m_sockfd1,0,tmpfd,0,timeout)) 0 ){if (i0) m_btimeout true;return false;}int ilenibuflen;if (ibuflen0) ilenstrlen(buffer);return(TcpWrite(m_sockfd,buffer,ilen)); }void CTcpClient::Close() {if (m_sockfd 0) close(m_sockfd); m_sockfd-1;memset(m_ip,0,sizeof(m_ip));m_port0;m_btimeoutfalse; }CTcpClient::~CTcpClient() {Close(); }CTcpServer::CTcpServer() {m_listenfd-1;m_connfd-1;m_socklen0;m_btimeoutfalse; }bool CTcpServer::InitServer(const unsigned int port) {if (m_listenfd 0) { close(m_listenfd); m_listenfd-1; }m_listenfd socket(AF_INET,SOCK_STREAM,0);// WINDOWS平台如下//char b_opt1;//setsockopt(m_listenfd,SOL_SOCKET,SO_REUSEADDR,b_opt,sizeof(b_opt));//setsockopt(m_listenfd,SOL_SOCKET,SO_KEEPALIVE,b_opt,sizeof(b_opt));// Linux如下int opt 1; unsigned int len sizeof(opt);setsockopt(m_listenfd,SOL_SOCKET,SO_REUSEADDR,opt,len);setsockopt(m_listenfd,SOL_SOCKET,SO_KEEPALIVE,opt,len);memset(m_servaddr,0,sizeof(m_servaddr));m_servaddr.sin_family AF_INET;m_servaddr.sin_addr.s_addr htonl(INADDR_ANY);m_servaddr.sin_port htons(port);if (bind(m_listenfd,(struct sockaddr *)m_servaddr,sizeof(m_servaddr)) ! 0 ){CloseListen(); return false;}if (listen(m_listenfd,5) ! 0 ){CloseListen(); return false;}m_socklen sizeof(struct sockaddr_in);return true; }bool CTcpServer::Accept() {if (m_listenfd -1) return false;if ((m_connfdaccept(m_listenfd,(struct sockaddr *)m_clientaddr,(socklen_t*)m_socklen)) 0)return false;return true; }char *CTcpServer::GetIP() {return(inet_ntoa(m_clientaddr.sin_addr)); }bool CTcpServer::Read(char *buffer,const int itimeout) {if (m_connfd -1) return false;if (itimeout0){fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(m_connfd,tmpfd);struct timeval timeout;timeout.tv_sec itimeout; timeout.tv_usec 0;m_btimeout false;int i;if ( (i select(m_connfd1,tmpfd,0,0,timeout)) 0 ){if (i0) m_btimeout true;return false;}}m_buflen 0;return(TcpRead(m_connfd,buffer,m_buflen)); }bool CTcpServer::Write(const char *buffer,const int ibuflen) {if (m_connfd -1) return false;fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(m_connfd,tmpfd);struct timeval timeout;timeout.tv_sec 5; timeout.tv_usec 0;m_btimeout false;int i;if ( (iselect(m_connfd1,0,tmpfd,0,timeout)) 0 ){if (i0) m_btimeout true;return false;}int ilen ibuflen;if (ilen0) strlen(buffer);return(TcpWrite(m_connfd,buffer,ilen)); }void CTcpServer::CloseListen() {if (m_listenfd 0){close(m_listenfd); m_listenfd-1;} }void CTcpServer::CloseClient() {if (m_connfd 0){close(m_connfd); m_connfd-1; } }CTcpServer::~CTcpServer() {CloseListen(); CloseClient(); }bool TcpRead(const int sockfd,char *buffer,int *ibuflen,const int itimeout) {if (sockfd -1) return false;if (itimeout 0){fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(sockfd,tmpfd);struct timeval timeout;timeout.tv_sec itimeout; timeout.tv_usec 0;int i;if ( (i select(sockfd1,tmpfd,0,0,timeout)) 0 ) return false;}(*ibuflen) 0;if (Readn(sockfd,(char*)ibuflen,4) false) return false;if (Readn(sockfd,buffer,(*ibuflen)) false) return false;return true; }bool TcpWrite(const int sockfd,const char *buffer,const int ibuflen) {if (sockfd -1) return false;fd_set tmpfd;FD_ZERO(tmpfd);FD_SET(sockfd,tmpfd);struct timeval timeout;timeout.tv_sec 5; timeout.tv_usec 0;if ( select(sockfd1,0,tmpfd,0,timeout) 0 ) return false;int ilen0;// 如果长度为0就采用字符串的长度if (ibuflen0) ilenstrlen(buffer);else ilenibuflen;char strTBuffer[ilen4];memset(strTBuffer,0,sizeof(strTBuffer));memcpy(strTBuffer,ilen,4);memcpy(strTBuffer4,buffer,ilen);if (Writen(sockfd,strTBuffer,ilen4) false) return false;return true; }bool Readn(const int sockfd,char *buffer,const size_t n) {int nLeft,nread,idx;nLeft n;idx 0;while(nLeft 0){if ( (nread recv(sockfd,buffer idx,nLeft,0)) 0) return false;idx nread;nLeft - nread;}return true; }bool Writen(const int sockfd,const char *buffer,const size_t n) {int nLeft,idx,nwritten;nLeft n; idx 0;while(nLeft 0 ){ if ( (nwritten send(sockfd, buffer idx,nLeft,0)) 0) return false; nLeft - nwritten;idx nwritten;}return true; }// 把文件通过sockfd发送给对端 bool SendFile(int sockfd,struct st_fileinfo *stfileinfo,CLogFile *logfile) {char strSendBuffer[301],strRecvBuffer[301];memset(strSendBuffer,0,sizeof(strSendBuffer));snprintf(strSendBuffer,300,filename%s/filenamefilesize%d/filesizemtime%s/mtime,stfileinfo-filename,stfileinfo-filesize,stfileinfo-mtime);if (TcpWrite(sockfd,strSendBuffer) false){if (logfile!0) logfile-Write(SendFile TcpWrite() failed.\n); return false;}int bytes0;int total_bytes0;int onread0;char buffer[1000];FILE *fp0;if ( (fpFOPEN(stfileinfo-filename,rb)) 0 ){if (logfile!0) logfile-Write(SendFile FOPEN(%s) failed.\n,stfileinfo-filename); return false;}while (true){memset(buffer,0,sizeof(buffer));if ((stfileinfo-filesize-total_bytes) 1000) onread1000;else onreadstfileinfo-filesize-total_bytes;bytesfread(buffer,1,onread,fp);if (bytes 0){if (Writen(sockfd,buffer,bytes) false){if (logfile!0) logfile-Write(SendFile Writen() failed.\n); fclose(fp); fp0; return false;}}total_bytes total_bytes bytes;if ((int)total_bytes stfileinfo-filesize) break;}fclose(fp);// 接收对端返回的确认报文int buflen0;memset(strRecvBuffer,0,sizeof(strRecvBuffer));if (TcpRead(sockfd,strRecvBuffer,buflen)false){if (logfile!0) logfile-Write(SendFile TcpRead() failed.\n); return false;}if (strcmp(strRecvBuffer,ok)!0) return false;return true; }// 接收通过socdfd发送过来的文件 bool RecvFile(int sockfd,struct st_fileinfo *stfileinfo,CLogFile *logfile) {char strSendBuffer[301],strRecvBuffer[301];char strfilenametmp[301]; memset(strfilenametmp,0,sizeof(strfilenametmp));sprintf(strfilenametmp,%s.tmp,stfileinfo-filename);FILE *fp0;if ( (fpFOPEN(strfilenametmp,wb)) 0) // FOPEN可创建目录{if (logfile!0) logfile-Write(RecvFile FOPEN %s failed.\n,strfilenametmp); return false;}int total_bytes0;int onread0;char buffer[1000];while (true){memset(buffer,0,sizeof(buffer));if ((stfileinfo-filesize-total_bytes) 1000) onread1000;else onreadstfileinfo-filesize-total_bytes;if (Readn(sockfd,buffer,onread) false){if (logfile!0) logfile-Write(RecvFile Readn() failed.\n); fclose(fp); fp0; return false;}fwrite(buffer,1,onread,fp);total_bytes total_bytes onread;if ((int)total_bytes stfileinfo-filesize) break;}fclose(fp);// 重置文件的时间UTime(strfilenametmp,stfileinfo-mtime);memset(strSendBuffer,0,sizeof(strSendBuffer));if (RENAME(strfilenametmp,stfileinfo-filename)true) strcpy(strSendBuffer,ok);else strcpy(strSendBuffer,failed);// 向对端返回响应内容if (TcpWrite(sockfd,strSendBuffer)false){if (logfile!0) logfile-Write(RecvFile TcpWrite() failed.\n); return false;}if (strcmp(strSendBuffer,ok) ! 0) return false;return true; }// 把某一个文件复制到另一个文件 bool COPY(const char *srcfilename,const char *dstfilename) {if (MKDIR(dstfilename) false) return false;char strdstfilenametmp[301];memset(strdstfilenametmp,0,sizeof(strdstfilenametmp));snprintf(strdstfilenametmp,300,%s.tmp,dstfilename);int srcfd,dstfd;srcfddstfd-1;int iFileSizeFileSize(srcfilename);int bytes0;int total_bytes0;int onread0;char buffer[5000];if ( (srcfdopen(srcfilename,O_RDONLY)) 0 ) return false;if ( (dstfdopen(strdstfilenametmp,O_WRONLY|O_CREAT|O_TRUNC,S_IWUSR|S_IRUSR|S_IXUSR)) 0) { close(srcfd); return false; }while (true){memset(buffer,0,sizeof(buffer));if ((iFileSize-total_bytes) 5000) onread5000;else onreadiFileSize-total_bytes;bytesread(srcfd,buffer,onread);if (bytes 0) write(dstfd,buffer,bytes);total_bytes total_bytes bytes;if (total_bytes iFileSize) break;}close(srcfd);close(dstfd);// 更改文件的修改时间属性char strmtime[21];memset(strmtime,0,sizeof(strmtime));FileMTime(srcfilename,strmtime);UTime(strdstfilenametmp,strmtime);if (RENAME(strdstfilenametmp,dstfilename) false) { REMOVE(strdstfilenametmp); return false; }return true; }CTimer::CTimer() {memset(m_start,0,sizeof(struct timeval));memset(m_end,0,sizeof(struct timeval));// 开始计时Start(); }// 开始计时 void CTimer::Start() {gettimeofday( m_start, NULL ); }// 计算已逝去的时间单位秒小数点后面是微秒 double CTimer::Elapsed() {gettimeofday( m_end, NULL );double dstart,dend;dstartdend0;char strtemp[51];memset(strtemp,0,sizeof(strtemp));snprintf(strtemp,30,%ld.%ld,m_start.tv_sec,m_start.tv_usec);dstartatof(strtemp);memset(strtemp,0,sizeof(strtemp));snprintf(strtemp,30,%ld.%ld,m_end.tv_sec,m_end.tv_usec);dendatof(strtemp);// 重新开始计时Start();return dend-dstart; }3._cmpublic.h #ifndef _cmpublic_H #define _cmpublic_H#include stdio.h #include utime.h //#include curl/curl.h #include string.h #include strings.h #include ctype.h #include stdlib.h #include unistd.h #include fcntl.h #include limits.h #include time.h #include math.h #include stdarg.h #include errno.h #include signal.h #include netdb.h #include locale.h #include dirent.h #include termios.h #include pthread.h #include semaphore.h #include sys/stat.h #include sys/time.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include iconv.h //#includeopenssl/md5.h#include iostream #include string #include cstdlib #include cstring #include list #include vector #include deque #include algorithm//#include boost/thread/thread.hpp //#include boost/shared_ptr.hpp //#include boost/signal.hpp// 定义C标准模板库的命名空间 using namespace std;// 以下是定义布尔数据类型的几个宏,在有的UNIX中,不一定支持布尔类型, // 所以在这里自定义 #ifndef BOOL#define BOOL unsigned char #endif#ifndef bool#define bool unsigned char #endif#ifndef TRUE#define TRUE 1 #endif#ifndef true#define true 1 #endif#ifndef FALSE#define FALSE 0 #endif#ifndef false#define false 0 #endif#ifndef INT#define INT long #endif#ifndef UINT#define UINT unsigned long #endif#ifndef UCHAR#define UCHAR unsigned long #endif#endif4._ooci.h //connection和sqlstatement类CDA_DEF结构体 #ifndef __OOCI_H #define __OOCI_H// C/C库常用头文件 #include stdio.h #include string.h #include stdlib.h #include stdarg.h// oracle数据库接口库头文件必须在装有oracle数据库主机运行 #include oci.h// OCI登录环境 struct LOGINENV {char user[32]; // 数据库的用户名char pass[32]; // 数据库的密码char tnsname[51]; // 数据库的tnsname在ORACLE_HOME/network/admin/tnsnames.ora中配置OCIEnv *envhp; // 环境变量的句柄 };// OCI上下文 struct OCI_CXT {OCISvcCtx *svchp;OCIError *errhp;OCIEnv *envhp; // 环境变量的句柄 };// 语句 struct OCI_HANDLE {OCISvcCtx *svchp; // 服务器上下文的句柄引用context句柄OCIStmt *smthp;OCIBind *bindhp;OCIDefine *defhp;OCIError *errhp; // 错误句柄引用context句柄OCIEnv *envhp; // 环境变量的句柄 引用context句柄 };//11111111111111111111.OCI执行的结果 struct CDA_DEF {int rc; // 执行结果unsigned long rpc; // 执行SQL语句后影响记录的行数char message[2048]; // 执行SQL语句如果失败存放错误信息 };int oci_init(LOGINENV *env); int oci_close(LOGINENV *env); int oci_context_create(LOGINENV *env,OCI_CXT *cxt); int oci_context_close(OCI_CXT *cxt);int oci_stmt_create(OCI_CXT *cxt,OCI_HANDLE *handle); int oci_stmt_close(OCI_HANDLE *handle);//1111111111111111112.数据库连接池类 class connection { private:// 服务器环境句柄LOGINENV m_env;public:// 服务器上下文OCI_CXT m_cxt;// 连接状态0-未连接1-已连接int m_state;// 自动提交标志0-关闭自动提交1-开启自动提交int m_autocommitopt; // 数据库种类固定取值为oraclechar m_dbtype[21];// 用于存放connection操作数据库的错误或最后一次执行SQL语句的结果CDA_DEF m_cda;connection();~connection();// 设置字符集如果客户端的字符集与数据库的不一致就会出现乱码。// 本方法要在connecttodb()之前调用。void character(char *charset);// 连接数据库connstr的格式为username/passwordtnsnameautocommitopt0-关闭自动提交1-启用自动提交int connecttodb(char *connstr,char *charset,int autocommitopt0);// 从connstr中解析username,password,tnsnamevoid setdbopt(char *connstr);// 断开与数据库的连接int disconnect();// 提交事务int commit(); // 回滚事务int rollback();// 获取错误信息void err_report(); };//1111111111111111113.SQL语言数据操作类 class sqlstatement { public:// 与数据库连接池的状态0-未绑定1-已绑定int m_state; // 语句句柄OCI_HANDLE m_handle;connection *m_conn;// SQL语句char m_sql[10240];// 执行结果CDA_DEF m_cda;int m_sqltype; // 待执行的SQL语句的类型0-查询语句1-非查询语句// 自动提交标志0-关闭自动提交1-开启自动提交int m_autocommitopt; sqlstatement();sqlstatement(connection *conn);~sqlstatement();// 设定数据库连接池int connect(connection *conn); // 断开与数据库连接池的连接int disconnect();// 分析SQL语句,支持存储过程,采用立刻分析的方式,即时返回分析结果int prepare(const char *fmt,...);// 绑定输入变量的地址int bindin(unsigned int position,int *value);int bindin(unsigned int position,long *value);int bindin(unsigned int position,unsigned int *value);int bindin(unsigned int position,unsigned long *value);int bindin(unsigned int position,float *value);int bindin(unsigned int position,double *value);int bindin(unsigned int position,char *value,unsigned int len);// 绑定输出变量的地址int bindout(unsigned int position,int *value);int bindout(unsigned int position,long *value);int bindout(unsigned int position,unsigned int *value);int bindout(unsigned int position,unsigned long *value);int bindout(unsigned int position,float *value);int bindout(unsigned int position,double *value);int bindout(unsigned int position,char *value,unsigned int len);// 执行SQL语句int execute();// 如果SQL语句不需要输入和输出变量可以直接执行。int execute(const char *fmt,...);// 取下一条记录,只有当SQL语句是查询语句时才有意义 int next();// 错误报告void err_report();// 指向LOB字段的指针在执行execute后用bindblob或bindclob绑定再用next获取指针OCILobLocator *m_lob;// 初始化lob指针在sqlstatement::connect()中调用int alloclob();// 释放lob指针在sqlstatement::disconnect()中调用void freelob();// 绑定lob指针int bindblob();int bindclob();// 以下两个函数都是把文件中的内容写入LOB字段第二个函数是被第一个函数调用的int filetolob(char *filename);int filetolob(FILE *fp);// 把LOB字段中的内容写入文件int lobtofile(char *filename);int lobtofile(FILE *fp); }; #endif 5._ooci.cpp // 如果是windows平台要用以下行否则会报以下错误 // _ooci.cpp(845) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add #include stdafx.h to your source? // #include stdafx.h#include _ooci.h/* OCI_SUCCESS 0 // maps to SQL_SUCCESS of SAG CLI 函数执行成功 OCI_SUCCESS_WITH_INFO 1 // maps to SQL_SUCCESS_WITH_INFO 执行成功但有诊断消息返回// 可能是警告信息但是在测试的时候我还从未见// 识到OCI_SUCCESS_WITH_INFO是怎么回事 OCI_RESERVED_FOR_INT_USE 200 // reserved OCI_NO_DATA 100 // maps to SQL_NO_DATA 函数执行完成但没有其他数据 OCI_ERROR -1 // maps to SQL_ERROR 函数执行错误 OCI_INVALID_HANDLE -2 // maps to SQL_INVALID_HANDLE 传递给函数的参数为无效句柄// 或传回的句柄无效 OCI_NEED_DATA 99 // maps to SQL_NEED_DATA 需要应用程序提供运行时刻的数据 OCI_STILL_EXECUTING -3123 // OCI would block error 服务环境建立在非阻塞模式// OCI函数调用正在执行中OCI_CONTINUE -24200 // Continue with the body of the OCI function // 说明回调函数需要OCI库恢复其正常的处理操作 OCI_ROWCBK_DONE -24201 // done with user row callback */int oci_init(LOGINENV *env) {//初始化Oracle 环境变量int oci_ret;oci_ret OCIEnvCreate(env-envhp,OCI_DEFAULT,NULL,NULL,NULL,NULL,0,NULL);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ) {oci_close(env); return -1;}return 0; } int oci_close(LOGINENV *env) {int oci_ret;// 释放Oracle 环境变量oci_retOCIHandleFree(env-envhp,OCI_HTYPE_ENV);env-envhp 0;return oci_ret; }int oci_context_create(LOGINENV *env,OCI_CXT *cxt ) {// 创建数据库连接的上下文对象连接服务器认证并建立会话if (env-envhp 0) return -1;int oci_ret;oci_ret OCIHandleAlloc(env-envhp,(dvoid**)cxt-errhp,OCI_HTYPE_ERROR,(size_t) 0,NULL);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ) {oci_context_close(cxt); return -1;}// 登录oci_ret OCILogon(env-envhp,cxt-errhp,cxt-svchp,(OraText*)env-user,strlen(env-user),(OraText*)env-pass,strlen(env-pass),(OraText*)env-tnsname,strlen(env-tnsname));if( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){oci_context_close(cxt); return -1;}cxt-envhp env-envhp;return 0; }int oci_context_close(OCI_CXT *cxt) {// 关闭数据库连接的上下文int oci_ret;oci_ret OCILogoff(cxt-svchp,cxt-errhp);oci_ret OCIHandleFree(cxt-svchp,OCI_HTYPE_SVCCTX);oci_ret OCIHandleFree(cxt-errhp, OCI_HTYPE_ERROR);cxt-svchp0;cxt-errhp0;return oci_ret; }int oci_stmt_create(OCI_CXT *cxt,OCI_HANDLE *handle ) {//创建语句int oci_ret;oci_ret OCIHandleAlloc( cxt-envhp, (dvoid**)handle-smthp, OCI_HTYPE_STMT,(size_t)0, NULL);if( oci_ret OCI_SUCCESS || oci_ret OCI_SUCCESS_WITH_INFO ){handle-svchp cxt-svchp;handle-errhp cxt-errhp;handle-envhp cxt-envhp;oci_ret OCI_SUCCESS;}return oci_ret; }int oci_stmt_close(OCI_HANDLE *handle) {// 关闭语句int oci_ret0;oci_ret OCIHandleFree(handle-smthp,OCI_HTYPE_STMT);return oci_ret; }connection::connection() { m_state 0; memset(m_cxt,0,sizeof(OCI_CXT));memset(m_env,0,sizeof(LOGINENV));memset(m_cda,0,sizeof(m_cda));m_cda.rc-1;strncpy(m_cda.message,database not open.,128);// 数据库种类memset(m_dbtype,0,sizeof(m_dbtype));strcpy(m_dbtype,oracle); }connection::~connection() {disconnect(); }// 从connstr中解析username,password,tnsname void connection::setdbopt(char *connstr) {char strtemp[201];memset(strtemp,0,sizeof(strtemp));strncpy(strtemp,connstr,128);char *pos0;// tnsnamepos strstr(strtemp,);if (pos 0) {strncpy(m_env.tnsname,pos1,50); pos[0]0;}// passwordpos strstr(strtemp,/);if (pos 0) {strncpy(m_env.pass,pos1,30); pos[0]0;}// usernamestrncpy(m_env.user,strtemp,30); }// 设置字符集如果客户端的字符集与数据库的不一致就会出现乱码。 void connection::character(char *charset) {// UNIX平台是采用setenv函数setenv(NLS_LANG,charset,1);// windows是采用putenv如下/*char str[100];memset(str,0,sizeof(str));_snprintf(str,50,NLS_LANG%s,charset);putenv(str);*/ }int connection::connecttodb(char *connstr,char *charset,int autocommitopt) {// 如果已连接上数据库就不再连接// 所以如果想重连数据库必须显示的调用disconnect()方法后才能重连if (m_state 1) return 0;// 设置字符集character(charset);// 设置日期字段的输出格式// UNIX平台是采用setenv函数// setenv(NLS_DATE_FORMAT,yyyy-mm-dd hh24:mi:ss,1);// windows是采用putenv如下// putenv(NLS_DATE_FORMATyyyy-mm-dd hh24:mi:ss);// 从connstr中解析username,password,tnsnamesetdbopt(connstr);memset(m_cda,0,sizeof(m_cda));// 初始化环境int oci_ret oci_init(m_env);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){oci_close(m_env); m_cda.rc-1; strncpy(m_cda.message,initialize oracle call interface failed.\n,128); return -1;}// 创建句柄登录数据库oci_ret oci_context_create(m_env,m_cxt);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){oci_close(m_env); m_cda.rc1017; strncpy(m_cda.message,ORA-01017: invalid username/password,logon denied.\n,128); return -1;}m_state 1;m_autocommitoptautocommitopt;return 0; }int connection::disconnect() {memset(m_cda,0,sizeof(m_cda));if (m_state 0) { m_cda.rc-1; strncpy(m_cda.message,database not open.,128); return -1;}rollback();oci_context_close(m_cxt);oci_close(m_env);m_state 0; return 0; }int connection::rollback() { memset(m_cda,0,sizeof(m_cda));if (m_state 0) { m_cda.rc-1; strncpy(m_cda.message,database not open.,128); return -1;}int oci_ret OCITransRollback( m_cxt.svchp, m_cxt.errhp, OCI_DEFAULT ); if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){err_report(); return m_cda.rc;}return 0; }int connection::commit() { memset(m_cda,0,sizeof(m_cda));if (m_state 0) { m_cda.rc-1; strncpy(m_cda.message,database not open.,128); return -1;}int oci_ret OCITransCommit( m_cxt.svchp, m_cxt.errhp, OCI_DEFAULT );if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){err_report(); return m_cda.rc;}return 0; }void connection::err_report() {if (m_state 0) { m_cda.rc-1; strncpy(m_cda.message,database not open.,128); return;}memset(m_cda,0,sizeof(m_cda));m_cda.rc-1;strncpy(m_cda.message,call err_report failed.,128);if (m_cxt.errhp ! NULL){if (OCIErrorGet(m_cxt.errhp,1,NULL,m_cda.rc,(OraText*)m_cda.message,sizeof(m_cda.message),OCI_HTYPE_ERROR) OCI_NO_DATA){// 如果获取不到错误信息就返回正确的memset(m_cda,0,sizeof(m_cda)); return;}} }sqlstatement::sqlstatement() {m_state0; memset(m_handle,0,sizeof(m_handle));memset(m_cda,0,sizeof(m_cda));memset(m_sql,0,sizeof(m_sql));m_cda.rc-1;strncpy(m_cda.message,sqlstatement not connect to connection.\n,128); }sqlstatement::sqlstatement(connection *conn) {sqlstatement();connect(conn); }sqlstatement::~sqlstatement() {disconnect(); }int sqlstatement::connect(connection *conn) {// 注意一个sqlstatement在程序中只能连一个connection不允许连多个connection// 所以只要这个光标已打开就不允许再次打开直接返回成功if ( m_state 1 ) return 0;memset(m_cda,0,sizeof(m_cda));m_connconn;// 如果数据库连接类的指针为空直接返回失败if (m_conn 0) {m_cda.rc-1; strncpy(m_cda.message,database not open.\n,128); return -1;}// 如果数据库没有连接好直接返回失败if (m_conn-m_state 0) {m_cda.rc-1; strncpy(m_cda.message,database not open.\n,128); return -1;}m_cda.rc oci_stmt_create(m_conn-m_cxt,m_handle);if ( m_cda.rc ! OCI_SUCCESS m_cda.rc ! OCI_SUCCESS_WITH_INFO ){err_report(); return m_cda.rc;}m_state 1; // 光标成功打开m_autocommitoptm_conn-m_autocommitopt;m_cda.rc OCI_SUCCESS; alloclob();return 0; }int sqlstatement::disconnect() {if (m_state 0) return 0;memset(m_cda,0,sizeof(m_cda));freelob();m_cda.rc oci_stmt_close(m_handle);m_state0;memset(m_handle,0,sizeof(m_handle));memset(m_cda,0,sizeof(m_cda));memset(m_sql,0,sizeof(m_sql));m_cda.rc-1;strncpy(m_cda.message,cursor not open.,128);return 0; }// 在新的OCI方法中当SQL语句有错误时OCIStmtPrepare返回的是0不是失败 // 所以程序员在程序中一般不必处理prepare的结果 int sqlstatement::prepare(const char *fmt,...) { memset(m_cda,0,sizeof(m_cda));if (m_state 0) {m_cda.rc-1; strncpy(m_cda.message,cursor not open.\n,128); return -1;}memset(m_sql,0,sizeof(m_sql));va_list ap;va_start(ap,fmt);vsnprintf(m_sql,10000,fmt,ap);int oci_ret OCIStmtPrepare(m_handle.smthp,m_handle.errhp,(OraText*)m_sql,strlen(m_sql),OCI_NTV_SYNTAX,OCI_DEFAULT);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){err_report(); return m_cda.rc;}// 判断是否是查询语句如果是把m_sqltype设为0其它语句设为1。m_sqltype1;// 从待执行的SQL语句中截取15个字符如果这15个字符中包括了“select”就认为是查询语句char strtemp[16]; memset(strtemp,0,sizeof(strtemp)); strncpy(strtemp,m_sql,15);if ( (strstr(strtemp,select) 0) || (strstr(strtemp,Select) 0) || (strstr(strtemp,SELECT) 0) ) m_sqltype0; m_cda.rc OCI_SUCCESS; return 0; }int sqlstatement::bindin(unsigned int position,int *value) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp, m_handle.errhp, (ub4)position, value, sizeof(int),SQLT_INT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,long *value) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp, m_handle.errhp, (ub4)position, value, sizeof(long),SQLT_INT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,unsigned int *value) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp,m_handle.errhp,(ub4)position,value,sizeof(unsigned int),SQLT_INT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,unsigned long *value) {return OCIBindByPos(m_handle.smthp,m_handle.bindhp,m_handle.errhp,(ub4)position,value,sizeof(unsigned long),SQLT_INT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,char *value,unsigned int len) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp, m_handle.errhp, (ub4)position, value, len1,SQLT_STR, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,float *value) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp, m_handle.errhp, (ub4)position, value, sizeof(float),SQLT_FLT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindin(unsigned int position,double *value) {return OCIBindByPos(m_handle.smthp, m_handle.bindhp, m_handle.errhp, (ub4)position, value, sizeof(double),SQLT_FLT, NULL, NULL,NULL,0, NULL, OCI_DEFAULT); }int sqlstatement::bindout(unsigned int position,int *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(int), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindout(unsigned int position,long *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(long), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindout(unsigned int position,unsigned int *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(unsigned int), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT ); } int sqlstatement::bindout(unsigned int position,unsigned long *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(unsigned long), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindout(unsigned int position,float *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(float), SQLT_FLT, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindout(unsigned int position,double *value) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, sizeof(double), SQLT_FLT, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindout(unsigned int position,char *value,unsigned int len) {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, position, value, len1, SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindblob() {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, 1,(dvoid *) m_lob,-1, SQLT_BLOB, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::bindclob() {return OCIDefineByPos(m_handle.smthp, m_handle.defhp, m_handle.errhp, 1,(dvoid *) m_lob,-1, SQLT_CLOB, NULL, NULL, NULL, OCI_DEFAULT ); }int sqlstatement::execute() {memset(m_cda,0,sizeof(m_cda));if (m_state 0) {m_cda.rc-1; strncpy(m_cda.message,cursor not open.\n,128); return -1;}ub4 modeOCI_DEFAULT;if (m_sqltype1 m_autocommitopt1) modeOCI_COMMIT_ON_SUCCESS;int oci_ret OCIStmtExecute(m_handle.svchp,m_handle.smthp,m_handle.errhp,m_sqltype,0,NULL,NULL,mode);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){// 发生了错误或查询没有结果err_report(); return m_cda.rc;}// 如果不是查询语句就获取影响记录的行数if (m_sqltype 1){OCIAttrGet((CONST dvoid *)m_handle.smthp,OCI_HTYPE_STMT,(dvoid *)m_cda.rpc, (ub4 *)0,OCI_ATTR_ROW_COUNT, m_handle.errhp);}return 0; }int sqlstatement::execute(const char *fmt,...) {char strtmpsql[10240];memset(strtmpsql,0,sizeof(strtmpsql));va_list ap;va_start(ap,fmt);vsnprintf(strtmpsql,10000,fmt,ap);if (prepare(strtmpsql) ! 0) return m_cda.rc;return execute(); }int sqlstatement::next() { // 注意在该函数中不可随意用memset(m_cda,0,sizeof(m_cda))否则会清空m_cda.rpc的内容if (m_state 0) {m_cda.rc-1; strncpy(m_cda.message,cursor not open.\n,128); return -1;}// 如果语句未执行成功直接返回失败。if (m_cda.rc ! 0) return m_cda.rc;// 判断是否是查询语句如果不是直接返回错误if (m_sqltype ! 0){m_cda.rc-1; strncpy(m_cda.message,no recordset found.\n,128); return -1;}int oci_ret OCIStmtFetch(m_handle.smthp,m_handle.errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT);if ( oci_ret ! OCI_SUCCESS oci_ret ! OCI_SUCCESS_WITH_INFO ){err_report(); // 只有当m_cda.rc不是1405和1406的时候才返回错误1405和1406不算错// 并且返回错误的时候不要清空了m_cda.rpcif (m_cda.rc ! 1405 m_cda.rc ! 1406) {// 如果返回代码不是0,1403,1405,1406就表是next出现了其它异常// 必须关闭数据库连接让程序错误退出。if ( (m_cda.rc!0) (m_cda.rc!1403) (m_cda.rc!1405) (m_cda.rc!1406) ) m_conn-disconnect();return m_cda.rc;}}// 获取结果集成功// 如果返回的是1405或1406就把它强置为0if (m_cda.rc 1405 || m_cda.rc 1406) m_cda.rc0;// 获取影响记录的行数据OCIAttrGet((CONST dvoid *)m_handle.smthp,OCI_HTYPE_STMT,(dvoid *)m_cda.rpc, (ub4 *)0,OCI_ATTR_ROW_COUNT, m_handle.errhp);return 0; }void sqlstatement::err_report() {// 注意在该函数中不可随意用memset(m_cda,0,sizeof(m_cda))否则会清空m_cda.rpc的内容if (m_state 0) {m_cda.rc-1; strncpy(m_cda.message,cursor not open.\n,128); return;}m_cda.rc-1;strncpy(m_cda.message,call sqlstatement::err_report() failed.\n,128);if (m_handle.errhp ! NULL){if (OCIErrorGet(m_handle.errhp,1,NULL,m_cda.rc,(OraText*)m_cda.message,sizeof(m_cda.message),OCI_HTYPE_ERROR) OCI_NO_DATA){// 如果没有获取到任何错误信息就返回正确的// 这里可以用memset清空m_cda因为如果没有任何错误m_cda.rpc在next中会重新赋值m_cda.rc0; memset(m_cda.message,0,sizeof(m_cda.message)); return;}}m_conn-err_report(); }int sqlstatement::alloclob() {return OCIDescriptorAlloc((dvoid *)m_handle.envhp,(dvoid **)m_lob,(ub4)OCI_DTYPE_LOB,(size_t)0,(dvoid **)0); }void sqlstatement::freelob() {OCIDescriptorFree((dvoid *)m_lob, (ub4)OCI_DTYPE_LOB); }ub4 file_length(FILE *fp) {fseek(fp, 0, SEEK_END);return (ub4) (ftell(fp)); }int sqlstatement::filetolob(char *filename) {FILE *fp0;if ( (fp fopen(filename,rb)) 0) {m_cda.rc-1; strncpy(m_cda.message,fopen failed,128); return -1;}int iret filetolob(fp);fclose(fp);return iret; }/* 操作CLOB和BLOB内容时缓冲区的大小一般不需要修改。 */ #define LOBMAXBUFLEN 10240int sqlstatement::filetolob(FILE *fp) {ub4 offset 1;ub4 loblen 0;ub1 bufp[LOBMAXBUFLEN1];ub4 amtp;ub1 piece;sword retval;ub4 nbytes;ub4 remainder;ub4 filelen file_length(fp);if (filelen 0) return 0;amtp filelen;remainder filelen;(void) OCILobGetLength(m_handle.svchp, m_handle.errhp, m_lob, loblen);(void) fseek(fp, 0, 0);if (filelen LOBMAXBUFLEN){nbytes LOBMAXBUFLEN;}else{nbytes filelen;}memset(bufp,0,sizeof(bufp));if (fread((void *)bufp, (size_t)nbytes, 1, fp) ! 1){m_cda.rc-1; strncpy(m_cda.message,fread failed,128); return -1;}remainder - nbytes;if (remainder 0) {// exactly one piece in the file// Only one piece, no need for stream writeif ( (retval OCILobWrite(m_handle.svchp, m_handle.errhp, m_lob, amtp, offset, (dvoid *) bufp,(ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0,(sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT)) ! OCI_SUCCESS){err_report(); return m_cda.rc;}}else{// more than one pieceif (OCILobWrite(m_handle.svchp, m_handle.errhp, m_lob, amtp, offset, (dvoid *) bufp,(ub4) LOBMAXBUFLEN, OCI_FIRST_PIECE, (dvoid *)0,(sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT) ! OCI_NEED_DATA){err_report(); return m_cda.rc;}piece OCI_NEXT_PIECE;do{if (remainder LOBMAXBUFLEN){nbytes LOBMAXBUFLEN;}else{nbytes remainder; piece OCI_LAST_PIECE;}memset(bufp,0,sizeof(bufp));if (fread((void *)bufp, (size_t)nbytes, 1, fp) ! 1){m_cda.rc-1; strncpy(m_cda.message,fread failed,128); return -1;}retval OCILobWrite(m_handle.svchp, m_handle.errhp, m_lob, amtp, offset, (dvoid *) bufp,(ub4) nbytes, piece, (dvoid *)0,(sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT);remainder - nbytes;} while (retval OCI_NEED_DATA !feof(fp));}if (retval ! OCI_SUCCESS){err_report(); return m_cda.rc;}(void) OCILobGetLength(m_handle.svchp, m_handle.errhp, m_lob, loblen);return 0; }// 把LOB字段中的内容写入文件 int sqlstatement::lobtofile(char *filename) {FILE *fp0;if ( (fp fopen(filename,wb)) 0){if ( (fp fopen(filename,wb)) 0){m_cda.rc-1; strncpy(m_cda.message,fopen failed,128); return -1;}}fseek(fp, 0, 0);int iret lobtofile(fp);fclose(fp);// 如果文件在生成的过程中发生了错误就删除该文件因为它是一个不完整的文件if (iret ! 0) remove(filename); return iret; }int sqlstatement::lobtofile(FILE *fp) {ub4 offset 1;ub4 loblen 0;ub1 bufp[LOBMAXBUFLEN1];ub4 amtp 0;sword retval;OCILobGetLength(m_handle.svchp, m_handle.errhp, m_lob, loblen);if (loblen 0) return 0;amtp loblen;memset(bufp,0,sizeof(bufp));retval OCILobRead(m_handle.svchp, m_handle.errhp, m_lob, amtp, offset, (dvoid *) bufp,(loblen LOBMAXBUFLEN ? loblen : LOBMAXBUFLEN), (dvoid *)0,(sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT);switch (retval){case OCI_SUCCESS: /* only one piece */fwrite((void *)bufp, (size_t)amtp, 1, fp);break;case OCI_NEED_DATA: /* there are 2 or more pieces */fwrite((void *)bufp, amtp, 1, fp); while (1){amtp 0;memset(bufp,0,sizeof(bufp));retval OCILobRead(m_handle.svchp, m_handle.errhp, m_lob, amtp, offset, (dvoid *) bufp,(ub4) LOBMAXBUFLEN, (dvoid *)0,(sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT);fwrite((void *)bufp, (size_t)amtp, 1, fp);if (retval ! OCI_NEED_DATA) break;} break;case OCI_ERROR:err_report(); return m_cda.rc;}return 0; }
http://www.dnsts.com.cn/news/259141.html

相关文章:

  • 为中小型企业构建网站php网站开发学什么
  • 免费网站建设域名app开发一个多少钱
  • 做网站资金来源是什么电商的推广方式有哪些
  • 青岛网站推广怎么做好网站系统与网站源码的关系
  • 潍坊网站推广服务商标有哪些
  • 手表网站网站建设越来越便宜
  • 怎么做卡盟网站免费国际国内新闻
  • 公司怎么建立网站吗最炫表白网站html5源码
  • 怎么申请自己的网站邢台中北世纪城网站兼职
  • 深圳品牌做网站成都网站asp access源码购买修改
  • 泰州网站制作网站厦门建设厅查询网站首页
  • 泰州网站建设报价wordpress 懒人图库
  • 专门做网站公司长沙市住房和城乡建设局
  • 我爱深圳网站设计福建建设执业资格网站报名系统
  • seo短视频网页入口引流下载连云港网站排名优化
  • 正能量视频免费网站免下载怎样用织梦建设网站
  • 微网站制作工具网络建设工作总结
  • 做网站的html框架安庆网站建设推广
  • 电商网站首页设计建筑工程网络计划视频教程
  • 微信开放平台与个人网站怎么推广优化
  • 全国网站制作公司怎样在wordpress设置伪静态
  • 宿迁手机网站开发公司沈阳网络推广培训
  • 跟老外做网站做娱乐新闻的网站有哪些
  • 如何建设网站首页做网站公司推荐
  • 北京模板建站软件黄页引流推广网站
  • 长春 建网站网络营销是干啥的
  • 网站怎么做图片搜索梵克雅宝五花手链
  • 中国建设工程标准化协会网站赵县网站建设公司
  • 互助网站建设上海网站推广排名
  • 网络平台代理合同泉州网站建设优化公司