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

建设手机行网站个人博客手机网站模板

建设手机行网站,个人博客手机网站模板,深圳市新朗建设工程有限公司网站,威特视频网站建设方案文章目录1.函数重载#xff1a;writetofile()#xff0c;Ctrue和false#xff0c;C0和非02.类和对象#xff1a;vprintf2.1 构造函数#xff1a;对成员变量初始化2.2 析构函数#xff1a;一个类只有一个#xff0c;不允许被重载3.引用#xff1a;C中取地址#x… 文章目录1.函数重载writetofile()Ctrue和falseC0和非02.类和对象vprintf2.1 构造函数对成员变量初始化2.2 析构函数一个类只有一个不允许被重载3.引用C中取地址C中引用。引用就像起别名typedef宏define。对引用的操作与对变量直接操作一样4.string类string strstrstr.c_str()5.vector容器vector与string类一样属于STL6.类继承和多态class派生类名public基类名7.socketsend/recv7.1 简单文件传输CTcpClientCTcpServer7.2 文件下载模块不建议将tcpgetfile.cpptcpfileserver.cpp反过来虽然全双工但会出现连不上服务器被上网行为审计系统拦截7.3 高性能网络服务多线程数据库连接池多线程每启一个线程都要连数据库耗资源8.进程fork()ps -ef (同-aux) | more9.信号signal, EXITjps9.1 捕捉信号ctrlc29.2 捕捉信号kill -999.3 捕捉信号kill159.4 程序后台运行两种方法ctrlc无法中止用killall book1或kill 进程号。if fork()0return 0 父进程退出1.函数重载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调用。 2.1 构造函数对成员变量初始化 CFile是类CFile()是函数。 如下两个构造函数该类对象被创建时编译系统对象分配内存空间并自动调用该构造函数由构造函数完成成员的初始化工作属于成员函数。 2.2 析构函数一个类只有一个不允许被重载 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.socketsend/recv 服务端 客户端 1.send函数。 2.recv函数。 1.socket函数 7.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; }如下传二进制文件。 7.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; }} }7.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; //理论上不会来到这里除非连接池搞乱了 }心跳报文业务不需要连接池先开启服务端。 8.进程fork()ps -ef (同-aux) | more 一个进程正在内存中运行的程序在内存里有三部分数据代码段相同堆栈段数据段不同。getpid库函数功能是获取进程编号该函数没有参数返回值是进程的编号相同程序在不同时间执行进程编号不同。 进程应用并发把socket服务端改为多进程每次accept到一个客户端连接后生成一个子进程让子进程负责与这个客户端通讯。父进程继续accept客户端连接。以下在服务端中在CTcpServer类中增加两个成员函数。 僵尸进程一个进程执行了exit系统调用退出时会向父进程发送SIGCHLD信号而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态如进程ID、终止状态等等)的进程ps显示有 default 。总结仔细处理子进程死后的信息如果不想处理就需要交给系统处理。 9.信号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的信号。 9.1 捕捉信号ctrlc2 如下在死循环之前注册下信号的处理如下让ctrlc无效。 点击Build后就会将类编译出来。 如上ctrlc无法停止只能用killjps查看进程pid。 9.2 捕捉信号kill -99 9.3 捕捉信号kill15 将如上KILL换成TERM即SIGTERM重新build project。win下信号比linux下信号少很多将当前程序打包成jar包传到linux。用如下命令行打包。 如下用压缩软件打开1.jar。 如下后有一个空格最后一行是空行。 9.4 程序后台运行两种方法ctrlc无法中止用killall book1或kill 进程号。if fork()0return 0 父进程退出 信号作用服务程序在后台运行如果想终止它杀了它不是个好办法因为没有释放资源。如果能向程序发一个信号程序收到这个信号后调用一个函数在函数中编写释放资源代码程序就可以安全体面退出。 下面 EXIT函数就是自定义函数TcpServer设为全局变量因为EXIT函数要访问它并关闭socket。
http://www.hkea.cn/news/14544691/

相关文章:

  • 网站开发要用多少钱做一个商品网站多少钱
  • 如何编辑企业网站html代码小游戏
  • 企业网站建设方案详细方案宁波建设网公众查询
  • 免费做网站平台广东省建设网站
  • 英文网站排版设计广告公司网站建设
  • 宝塔面板wordpress多站点挂机宝 可以做网站
  • 网站域名的作用免费推广店铺的网站
  • 网站模板组件电子商务网站建设含义
  • 杭州做网站需要多少钱nginx和wordpress
  • 企业如何注册网站wordpress段子模板
  • 有的域名怎样做网站期末网站设计做什么网站比较好
  • 太原百度推广制作个性商城网站网站左侧导航代码
  • 重庆建站服务商wordpress全站注明
  • 爱站网ip反域名查询宝安区做网站
  • 徐州做网站的公司企业网站系统设计与实现
  • 网站推广都有哪些微商网站
  • 电商平台网站建设网站跳转站代码
  • 移动网站 制作建设企业网站的
  • 网站改版 数据迁移wordpress付费汉化主题
  • 温州做外贸网站湖南建设局网站
  • seo竞争对手网站分析沈阳网势科技有限公司怎么样
  • wordpress图片整站如何用手机做网站
  • 郑州网站建设求职简历做网站怎么云存储
  • 网站备案号密码网站建设网站徒手整形
  • 建设邮费自己的网站 要不要购买服务器的wordpress 置顶
  • 基于asp网站开发 论文有人知道网站怎么做吗
  • dedecms三合一网站源码笑话网站源码下载
  • 网站程上传php网站开发小程序
  • 网站建设 实施计划网站建设沟通
  • 网站建设的合理建议南通网站制作公司