1.TCP glue/timeout: full duplex, unpack
FTP protocol for file transfer performance is insufficient [FTP protocol is a part of TCP/IP protocol, strictly speaking, application layer protocol, TCP communication two major bottlenecks: bandwidth, too many interactions (get server time, file list, rename, etc.). windows platform FTP installation server is cumbersome, different FTP servers use slightly different, compatibility is not good [such as dot * in ftp.list, some don't). FTP is not used internally, but FTP is used externally (because you can't deploy your own programs to other servers, others can only install FTP servers).
For example, the author of station B sends video files to the video upload server for auditing, and sends them to the video playback server through the file transfer system after auditing. [A playback server cannot respond to so many playback requests, it must be a server cluster].
Why do you want to transfer files instead of tcp messages (some data is organized as files, such as videos), because they are faster. Unpack and paste as follows:
Solve sticky package unpacking as follows: Header/Fixed Length/Separator.
Following is the first method, glue will still appear, but it can be distinguished.
The third method, Custom Delimiter, follows.
As follows in _ public.h Client.
As follows in _ public.h server, no ip is specified in the InitServer function, indicating that any ip can be connected.
The following is _ public.h defines several methods, TcpRead method calls recv function last, recv will block and wait, actual development will not wait, plus a timeout mechanism: for example, if you have not sent me a message in a minute, I will disconnect your resource release process and exit. Readn and Writen are extensions to recv and send.
As follows in _ public.h Definition solves the sticky package problem and customizes the TCP message format.
select is not a sql statement but a system call. select (non-blocking) was originally used for I/O reuse and is now used for timeout mechanisms. A process started after the client connects consumes resources, so the server actively exits the client process to release resources when the client disconnects for some reason.
The following CTcpClient::Read() does not use a timeout mechanism (timeouts are used on both the client and the server).
// This program demonstrates the use of CTcpClient class to achieve socket communication client, demo11.cpp #include "_public.h" int main(int argc,char *argv[]) { if (argc != 3) { printf("\n"); printf("Using:./demo11 ip port\n\n"); printf("Example:./demo11 118.89.50.198 5010\n\n"); printf("This program demonstrates using CTcpClient Class, implementation socket Communication client.\n\n"); return -1; } CTcpClient TcpClient; //111111111111111111111111111111111111111111111111111111111111111111111111111. Initiate a connection to the server if (TcpClient.ConnectToServer(argv[1],atoi(argv[2])) == false) { printf("TcpClient.ConnectToServer(%s,%d) failed.\n",argv[1],atoi(argv[2])); return -1; } char strRecvBuffer[1024],strSendBuffer[1024]; memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,\ "In the final round of the Premier League, Carrick played his last official match at Manchester United, meaning that the Red Devils'last championship-winning golden generation had all left."); //11111111111111111111111111111111111111111111111111112. Send strSendBuffer content to server if (TcpClient.Write(strSendBuffer)==false) { printf("TcpClient.Write() failed.\n"); return -1; } printf("send ok:%s\n",strSendBuffer); memset(strRecvBuffer,0,sizeof(strRecvBuffer)); //1111111111111111111111111111111111111111111111111111113. Receive the message returned by the server (Read below has no timeout mechanism) if (TcpClient.Read(strRecvBuffer)==false) { if (TcpClient.m_btimeout==true) printf("timeout\n"); printf("TcpClient.Read() failed.\n"); return -1; } printf("recv ok:%s\n",strRecvBuffer); return 0; }
// This program demonstrates using CTcpServer class to implement socket communication server, demo12.cpp #include "_public.h" int main(int argc,char *argv[]) { if (argc != 2) { printf("\n"); printf("Using:./demo12 port\n\n"); printf("Example:./demo12 5010\n\n"); printf("This program demonstrates using CTcpServer Class, implementation socket The server of the communication.\n\n"); return -1; } CTcpServer TcpServer; //1111111111111111111111111111111111111111111111111111111111. Server-side Initialization if (TcpServer.InitServer(atoi(argv[1])) == FALSE) { printf("TcpServer.InitServer(%s) failed.\n",argv[1]); return -1; } //1111111111111111111111111111111111111111111111111111112. Waiting for client connection if (TcpServer.Accept() == FALSE) { printf("TcpServer.Accept() failed.\n"); return -1; } char strRecvBuffer[1024],strSendBuffer[1024]; memset(strRecvBuffer,0,sizeof(strRecvBuffer)); //111111111111111111111111111111111111111111111111113. Read client's message, wait 20 seconds, timeout mechanism if (TcpServer.Read(strRecvBuffer,20)==FALSE) { printf("TcpServer.Read() failed.\n"); return -1; } printf("recv ok:%s\n",strRecvBuffer); memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"ok"); //111111111111111111111111111111111111111111111111111114. Return response content to client if (TcpServer.Write(strSendBuffer)==FALSE) { printf("TcpServer.Write() failed.\n"); return -1; } printf("send ok:%s\n",strSendBuffer); return 0; }
Add sleep below to change the timeout mechanism.
Use m_below The btimeout member (timeout is true) prints out whether or not the timeout occurred.
The server can't tell if the client is network or the program is disconnected because of its own problems, only knows that the TCP channel is abnormal.
Here is GetIP().
2. Simple file transfer: CTcpClient, CTcpServer
// This program demonstrates using CTcpClient class to realize client and file transfer of socket communication, demo13.cpp #include "_public.h" bool SendFile(int sockfd,char *filename,int filesize); //Send the contents of the file to the server 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("This program demonstrates using CTcpClient Class, implementation socket Communication client and file transfer.\n\n"); return -1; } if (access(argv[3],R_OK) != 0) //Determine whether a file exists { printf("file %s not exist.\n",argv[3]); return -1; } int uFileSize=0; char strMTime[20],strRecvBuffer[1024],strSendBuffer[1024]; memset(strMTime,0,sizeof(strMTime)); //Get the time and size of the file FileMTime(argv[3],strMTime); uFileSize=FileSize(argv[3]); //Get the size of the file // Encapsulate the information of the file into an xml message and send it to the server memset(strSendBuffer,0,sizeof(strSendBuffer)); snprintf(strSendBuffer,100,"<filename>%s</filename><mtime>%s</mtime><size>%lu</size>",argv[3],strMTime,uFileSize); CTcpClient TcpClient; //1111111111111111111111111111111111111111111111111111111111. Initiate a connection to the server if (TcpClient.ConnectToServer(argv[1],atoi(argv[2])) == false) { printf("TcpClient.ConnectToServer(%s,%d) failed.\n",argv[1],atoi(argv[2])); return -1; } //1111111111111111111111111111111111111111112. Send the xml of the file information to the server without receiving the response from the server. It is unnecessary to reduce the number of tcp interactions if (TcpClient.Write(strSendBuffer)==false) { printf("TcpClient.Write() failed.\n"); return -1; } printf("send xml:%s\n",strSendBuffer); printf("send file ..."); //111111111111111111111111111111111111111111111111111111113. Send the contents of the file to the server if (SendFile(TcpClient.m_sockfd,argv[3],uFileSize)==false) { printf("SendFile(%s) failed.\n",argv[3]); return -1; } memset(strRecvBuffer,0,sizeof(strRecvBuffer)); //1111111111111111111111111111111111111111111111111111114. Receive the response message returned by the server if (TcpClient.Read(strRecvBuffer)==false) { printf("TcpClient.Read() failed.\n"); return -1; } if (strcmp(strRecvBuffer,"ok")==0) printf("ok.\n"); else printf("failed.\n"); return 0; } //111111111111111111111111111111111111111111111111113. Send the contents of the file to the server bool SendFile(int sockfd,char *filename,int filesize) { int bytes=0; int total_bytes=0; int onread=0; char buffer[1000]; FILE *fp=NULL; if ( (fp=fopen(filename,"rb")) == NULL ) { printf("fopen(%s) failed.\n",filename); return false; } while (true) { memset(buffer,0,sizeof(buffer)); if ((filesize-total_bytes) > 1000) onread=1000; //Read 1000 bytes at a time else onread=filesize-total_bytes; bytes=fread(buffer,1,onread,fp); if (bytes > 0) { if (Writen(sockfd,buffer,bytes) == false) { printf("Writen() failed.\n"); fclose(fp); fp=NULL; return false; } } total_bytes = total_bytes + bytes; if ((int)total_bytes == filesize) break; } fclose(fp); return true; }
// This program demonstrates the use of CTcpServer class to achieve socket communication server and file transfer, demo14.cpp #include "_public.h" bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename); //Receive the contents of the file 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 rename printf("This program demonstrates using CTcpServer Class, implementation socket Server side of communication and file transfer.\n\n"); return -1; } CTcpServer TcpServer; //1111111111111111111111111111111111111111111111111111111111. Server-side Initialization if (TcpServer.InitServer(atoi(argv[1])) == false) { printf("TcpServer.InitServer(%s) failed.\n",argv[1]); return -1; } //1111111111111111111111111111111111111111111111111111112. Waiting for client connection if (TcpServer.Accept() == false) { printf("TcpServer.Accept() failed.\n"); return -1; } //11111111111111111111111111111111111111111113. Read client's message, wait 20 seconds 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. Receive the contents of the file 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"); } //1111111111111111111111111111111111111111111111111111115. After receiving ok, return the response content to the client if (TcpServer.Write(strSendBuffer)==false) { printf("TcpServer.Write() failed.\n"); return -1; } printf("send:%s\n",strSendBuffer); return 0; } //1111111111111111111111111111111111111111111111111111114. Receive the contents of the file bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename) { int ufilesize=0; char strmtime[20]; memset(strmtime,0,sizeof(strmtime)); // Get the time and size of the file to be received GetXMLBuffer(strRecvBuffer,"mtime",strmtime); GetXMLBuffer(strRecvBuffer,"size",&ufilesize); FILE *fp=NULL; if ( (fp=fopen(strfilename,"wb")) ==NULL) { printf("create %s failed.\n",strfilename); return false; } int total_bytes=0; int onread=0; char buffer[1000]; while (true) { memset(buffer,0,sizeof(buffer)); if ((ufilesize-total_bytes) > 1000) onread=1000; //Know how much the file will read next based on its size else onread=ufilesize-total_bytes; if (Readn(sockfd,buffer,onread) == false) { printf("Readn() failed.\n"); fclose(fp); fp=NULL; return false; } fwrite(buffer,1,onread,fp); //Read 1 byte at a time onread times total_bytes = total_bytes + onread; if ((int)total_bytes == ufilesize) break; } fclose(fp); // Reset the original time of the file after reading, not the local receive generation time UTime(strfilename,strmtime); return true; }
Download the binary file as follows.
3. File upload module: multi-process, | wc
One server: processes both sending files and receiving data. Two clients: one sending file and one receiving file. Here's the client process. Logging in tells the server how to transfer some information, such as the srvpath parameter.
The following okfilename is empty by default, okfilename is meaningful when ptype=1, and andchild is empty by default. If timetvl is disconnected by the switch for more than 60 seconds, network administrators will force the TCP connection to be disconnected for idle time of 60 seconds, timetvl will sleep, and 1 second read and write will cause disk pressure. ip cpc smat
//This is a general function module, which uses TCP protocol to send files to the client, tcpputfile.cpp. #include "_public.h" struct st_arg { char ip[31]; // Server-side IP address. int port; // Server-side port. int ptype; // Processing method of file after successful sending: 1 - Keep the file; 2-Delete files; 3-Move to the backup directory. char clientpath[301]; // The root directory where local files are stored. char clientpathbak[301]; // After the file is successfully sent, the root directory of the local file backup is valid when ptype==3. char srvpath[301]; // Root directory where server-side files are stored. bool andchild; // Whether to send files from subdirectories at all levels in the clientpath directory, true-Yes; false-no. char matchname[301]; // Match file names to be sent, such as'*.TXT,*.XML', in uppercase. char okfilename[301]; // A list of successful file names has been sent. int timetvl; // Time interval for scanning local directory files in seconds. } starg; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message vector<struct st_fileinfo> vlistfile,vlistfile1; vector<struct st_fileinfo> vokfilename,vokfilename1; bool LoadListFile(); // Load files from the clientpath directory into the vlistfile container bool LoadOKFileName(); // Load okfilename file contents into vokfilename container // Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 bool CompVector(); bool WriteToOKFileName(); // Write the contents of the vokfilename1 container into the okfilename file first, overwriting the old okfilename file bool AppendToOKFileName(struct st_fileinfo *stfileinfo); // If ptype==1, append the file records collected successfully to the okfilename file CTcpClient TcpClient; CLogFile logfile; bool _tcpgetfile(); void EXIT(int sig); void _help(char *argv[]); bool _xmltoarg(char *strxmlbuffer); // Parsing xml into parameter starg structure bool ClientLogin(const char *argv); // logon server bool ActiveTest(); // Send heartbeat message to server bool _tcpputfiles(); // Implement the function of sending files 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("Failed to open log file(%s). \n",argv[1]); return -1; } if (_xmltoarg(argv[2])==false) return -1; while (true) { ClientLogin(argv[2]); //Connect to the server and log in //Implements the function of sending files, regardless of the success or failure of the return, and communication errors will be reflected in ActiveTest() _tcpputfiles(); if (vlistfile.size()==0) //Do heartbeat and sleep when you are free. If you don't add a new file under the directory generates a new heartbeat sleep, no need { //Send a heartbeat message to the server. Communication failures will be checked in this function. Re-login to the previous ClientLogin function will automatically reconnect ActiveTest(); sleep(starg.timetvl); } } return 0; } void EXIT(int sig) { logfile.Write("Program exits, sig=%d\n\n",sig); TcpClient.Close(); exit(0); } //11111111111111111111111111111111111111111111111111111111111111111111111 void _help(char *argv[]) { printf("\n"); printf("Using:/htidc/public/bin/tcpputfiles logfilename xmlbuffer\n\n"); printf("Sample:/htidc/public/bin/tcpputfiles /log/shqx/tcpputfiles_surfdata.log \"<ip>172.16.0.15</ip><port>5010</port><ptype>1</ptype><clientpath>/data/shqx/sdata/surfdata</clientpath><clientpathbak>/data/shqx/sdata/surfdatabak</clientpathbak><srvpath>/data/shqx/tcp/surfdata</srvpath><andchild>true</andchild><matchname>SURF_*.TXT,*.DAT</matchname><okfilename>/data/shqx/tcplist/tcpputfiles_surfdata.xml</okfilename><timetvl>10</timetvl>\"\n\n\n"); printf("This program is a common function module of the data center, using TCP The protocol sends the file to the server.\n"); printf("logfilename A log file for running this program.\n"); printf("xmlbuffer The parameters for running this program are as follows:\n"); printf("ip Server-side IP Address.\n"); printf("port Server-side port.\n"); printf("ptype Processing after successful file sending:1-Keep files; 2-Delete files; 3-Move to the backup directory.\n"); printf("clientpath The root directory where local files are stored.\n"); printf("clientpathbak After the file is successfully sent, the root directory of the local file backup, when ptype==3 Valid by default.\n"); printf("srvpath Root directory where server-side files are stored.\n"); printf("andchild Whether to send clientpath Files in subdirectories at all levels of the directory, true-Yes; false-No, the default is false. \n"); printf("matchname How to match the file name to be sent, such as\"*.TXT,*.XML\",Be careful to capitalize.\n"); printf("okfilename Sent list of successful filenames, empty by default.\n"); printf("timetvl Time interval for scanning local directory files, in seconds, at 1-50 Between.\n\n\n"); } //11111111111111111111111111111111111111111111111111 parses xml into a parameter starg structure 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.port==0) { 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,"clientpathbak",starg.clientpathbak); if ((starg.ptype==3)&&(strlen(starg.clientpathbak)==0)) { logfile.Write("clientpathbak 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.ptype==1)&&(strlen(starg.okfilename)==0)) { logfile.Write("okfilename is null.\n"); return false; } GetXMLBuffer(strxmlbuffer,"timetvl",&starg.timetvl); if (starg.timetvl==0) { logfile.Write("timetvl is null.\n"); return false; } if (starg.timetvl>50) starg.timetvl=50; //tcp connections over 60 seconds are easily disconnected by switches return true; } //111111111111111111111111111111111111111111111111111111111111111111111111111 Logon Server bool ClientLogin(const char *argv) { if (TcpClient.m_sockfd>0) return true; //>0 means no reconnection, socket shut down m_if communication fails Sockfd set to -1 //m_sockfd and m_state connection status is the same, greater than 0 does not need to reconnect int ii=0; while (true) { if (ii++>0) sleep(20); // Enter the cycle for the first time without hibernation //Tcpputfile. Reconnect every 20 seconds after CPP client fails to connect to the server // Initiate a connection to the server 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)); // clienttype 1 indicates that this client sends files and 2 indicates that the client receives server-side files strcpy(strSendBuffer,argv); strcat(strSendBuffer,"<clienttype>1</clienttype>"); // logfile.Write("strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (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("strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx break; } logfile.Write("login(%s,%d) ok.\n",starg.ip,starg.port); return true; } //11111111111111111111111111111111111111111111111111111111111111 11 send heartbeat message to server bool ActiveTest() { memset(strRecvBuffer,0,sizeof(strRecvBuffer)); memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"<activetest>ok</activetest>"); // logfile.Write("strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (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("strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx if (strcmp(strRecvBuffer,"ok") != 0) { TcpClient.Close(); return false; } return true; } //11111111111111111111111111111111111111111111111111111111111 11 Implement File Sending Function bool _tcpputfiles() { if (LoadListFile()==false) // Load files from the clientpath directory into the vlistfile container { logfile.Write("LoadListFile() failed.\n"); return false; } if (starg.ptype==1) { LoadOKFileName(); // Load the contents of the okfilename file into the container vokfilename // Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 CompVector(); WriteToOKFileName(); // Write the contents of the vokfilename1 container into the okfilename file first, overwriting the old okfilename file vlistfile.clear(); vlistfile.swap(vlistfile1); // Copy the contents of the vlistfile1 container into the vlistfile container } for (int ii=0;ii<vlistfile.size();ii++) //Send new or changed files from client to server { logfile.Write("put %s ...",vlistfile[ii].filename); if (SendFile(&logfile,TcpClient.m_sockfd,&vlistfile[ii])==false) //Send the file to the server { logfile.Write("RecvFile() failed.\n"); TcpClient.Close(); return false; } logfile.WriteEx("ok.\n"); if (starg.ptype==2) REMOVE(vlistfile[ii].filename); // Delete Files if (starg.ptype==3) // Dump to backup directory { char strfilenamebak[301]; memset(strfilenamebak,0,sizeof(strfilenamebak)); strcpy(strfilenamebak,vlistfile[ii].filename); //logfile.Write("1%s\n",strfilenamebak); UpdateStr(strfilenamebak,starg.clientpath,starg.clientpathbak,false); // Be careful with the third parameter //logfile.Write("2%s\n",strfilenamebak); if (RENAME(vlistfile[ii].filename,strfilenamebak)==false) { logfile.Write("RENAME %s to %s failed.\n",vlistfile[ii].filename,strfilenamebak); return false; } } if (starg.ptype==1) AppendToOKFileName(&vlistfile[ii]); //If ptype==1, append the file records collected successfully to the okfilename file } return true; } //1111111111111111111111111111111111111111111 Loads files in the clientpath directory into the vlistfile container bool LoadListFile() { vlistfile.clear(); CDir Dir; //dir lists local file directories and loads the container // Note that if the total number of files in the directory exceeds 5000, the incremental file sending function will be problematic if (Dir.OpenDir(starg.clientpath,starg.matchname,50000,starg.andchild,false)==false) { logfile.Write("Dir.OpenDir(%s) Failed.\n",starg.clientpath); return false; } struct st_fileinfo stfileinfo; while (true) { memset(&stfileinfo,0,sizeof(struct st_fileinfo)); if (Dir.ReadDir()==false) break; strcpy(stfileinfo.filename,Dir.m_FullFileName); strcpy(stfileinfo.mtime,Dir.m_ModifyTime); stfileinfo.filesize=Dir.m_FileSize; vlistfile.push_back(stfileinfo); // logfile.Write("vlistfile filename=%s,mtime=%s\n",stfileinfo.filename,stfileinfo.mtime); } return true; } //1111111111111111111111111111111111111111111111 Load okfilename file contents into vokfilename container bool LoadOKFileName() { vokfilename.clear(); CFile File; // Note: If the program is the first collection, okfilename does not exist, it is not an error, so it also returns 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; } //1111111111111111 Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 bool CompVector() { vokfilename1.clear(); vlistfile1.clear(); for (int ii=0;ii<vlistfile.size();ii++) { int jj=0; for (jj=0;jj<vokfilename.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 (jj==vokfilename.size()) { vlistfile1.push_back(vlistfile[ii]); } } return true; } //11111111111111 Writes the contents of the vokfilename1 container into the okfilename file first, overwriting the previous old okfilename file bool WriteToOKFileName() { CFile File; if (File.Open(starg.okfilename,"w") == false) { logfile.Write("File.Open(%s) failed.\n",starg.okfilename); return false; } for (int ii=0;ii<vokfilename1.size();ii++) { File.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",vokfilename1[ii].filename,vokfilename1[ii].mtime); } return true; } //1111111111111111111111111111 If ptype==1, append the file records collected successfully to the okfilename file bool AppendToOKFileName(struct st_fileinfo *stfileinfo) { CFile File; if (File.Open(starg.okfilename,"a") == false) { logfile.Write("File.Open(%s) failed.\n",starg.okfilename); return false; } File.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",stfileinfo->filename,stfileinfo->mtime); return true; }
Server-side process: After receiving a connection request, receive a login report, Wait for the file description information message (file name, file size, file time) until the client receives the file according to the message, writes it locally and sends back a confirmation to the client after receiving it, and continues to wait for the file information. The server is multi-process, multi-threaded and lazy to handle global variable problems, because the server program does not need to share any variables.
//This is a general function module, which uses TCP protocol to implement file transfer server, tcpfileserver.cpp multi-process. #include "_public.h" struct st_arg { char ip[31]; // Server-side IP address. int port; // Server-side port. int ptype; // Processing method of file after successful sending: 1 - Keep the file; 2-Move to the backup directory; 3-Delete the file. char clientpath[301]; // The root directory where local files are stored. char clientpathbak[301]; // After the file is successfully sent, the root directory of the local file backup is valid when ptype==2. char srvpath[301]; // Root directory where server-side files are stored. char srvpathbak[301]; // After the file is successfully received, the root directory of the server-side file backup is valid when ptype==2. bool andchild; // Whether to send files from subdirectories at all levels in the clientpath directory, true-Yes; false-no. char matchname[301]; // Match file names to be sent, such as'*.TXT,*.XML', in uppercase. char okfilename[301]; // A list of successful file names has been sent. int timetvl; // Time interval for scanning local directory files in seconds. } starg; bool _xmltoarg(char *strxmlbuffer); CTcpServer TcpServer; CLogFile logfile; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message int clienttype=0; bool ClientLogin(); // Waiting for login bool ListFile(); // Lists the files in the srvpath directory and returns them to the client. void FathEXIT(int sig); // Functions called on program exit void ChldEXIT(int sig); void RecvFilesMain(); // Receive File Main Function void SendFilesMain(); // Send File Main Function int main(int argc,char *argv[]) { if (argc != 3) { printf("\n"); printf("Using:/htidc/public/bin/tcpfileserver logfilename port\n"); printf("Example:/htidc/public/bin/tcpfileserver /log/shqx/tcpfileserver.log 5010\n\n"); printf("This program is a common function module, which uses TCP/IP A server that transfers files.\n"); printf("logfilename Log file name.\n"); printf("port For file transfer TCP Port.\n"); return -1; } CloseIOAndSignal(); signal(SIGINT,FathEXIT); signal(SIGTERM,FathEXIT); // Open program run log, this is a multi-process program shared log file, log cannot automatically switch the third parameter to fill false 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]); if (TcpServer.InitServer(atoi(argv[2])) == false) { logfile.Write("TcpServer.InitServer(%s) failed.\n",argv[2]); exit(-1); } while (true) { if (TcpServer.Accept() == false) // Waiting for client connection { logfile.Write("TcpServer.Accept() failed.\n"); continue; } if (fork() > 0) // New Client Connection { TcpServer.CloseClient(); continue; // The parent process closes the sock connection it just established and returns to Accept to continue listening } // The process that enters the child process below signal(SIGINT,ChldEXIT); signal(SIGTERM,ChldEXIT); TcpServer.CloseListen(); // Subprocess needs to turn off sock listening // Waiting for client to log in. Now the login is just a greeting, the client adds more parameters such as assigning a user name and password, the server can judge the user name and password and the client ip if (ClientLogin() == false) ChldEXIT(0); if (clienttype==1) RecvFilesMain(); // Receive file main function // 1 send to client and receive to server if (clienttype==2) SendFilesMain(); // Send File Main Function ChldEXIT(0); } return 0; } //1111111111111111111111111111111111111111111111111111111111111111111111 void FathEXIT(int sig) // Functions called when the parent process exits { if (sig > 0) { signal(sig,SIG_IGN); logfile.Write("catching the signal(%d).\n",sig); } TcpServer.CloseListen(); kill(0,15); //Send 15 signal to child process to notify exit logfile.Write("fileserver EXIT.\n"); exit(0); } void ChldEXIT(int sig) // Functions called when a child process exits { if (sig > 0) signal(sig,SIG_IGN); TcpServer.CloseClient(); // Subprocess receives 15 signal to shut down socket for client connection exit(0); // Sign out } //111111111111111111111111111111111111111111111111111111111111111111111111111111111 Waiting for Login bool ClientLogin() { // More parameters can be added to determine the client username, password, ip memset(strRecvBuffer,0,sizeof(strRecvBuffer)); memset(strSendBuffer,0,sizeof(strSendBuffer)); if (TcpServer.Read(strRecvBuffer,20) == false) { logfile.Write("1 TcpServer.Read() failed.\n"); return false; } // logfile.Write("1 strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx GetXMLBuffer(strRecvBuffer,"clienttype",&clienttype); if ( (clienttype==1) || (clienttype==2) ) strcpy(strSendBuffer,"ok"); else strcpy(strSendBuffer,"failed"); // logfile.Write("1 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpServer.Write(strSendBuffer) == false) { logfile.Write("1 TcpServer.Write() failed.\n"); return false; } logfile.Write("%s login %s.\n",TcpServer.GetIP(),strSendBuffer); if (strcmp(strSendBuffer,"failed") == 0) return false; _xmltoarg(strRecvBuffer); // Parse out the parameters return true; } //11111111111111111111111111111111111111111111111111111111111111 Receive File Primary Function void RecvFilesMain() { while (true) { memset(strRecvBuffer,0,sizeof(strRecvBuffer)); memset(strSendBuffer,0,sizeof(strSendBuffer)); if (TcpServer.Read(strRecvBuffer,80) == false) { logfile.Write("2 TcpServer.Read() failed.\n"); ChldEXIT(-1); } // logfile.Write("2 strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx if (strstr(strRecvBuffer,"activetest")!=0) // Processing heartbeat messages { strcpy(strSendBuffer,"ok"); // logfile.Write("2 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpServer.Write(strSendBuffer) == false) { logfile.Write("2 TcpServer.Write() failed.\n"); ChldEXIT(-1); } continue; } struct st_fileinfo stfileinfo; memset(&stfileinfo,0,sizeof(struct st_fileinfo)); // Get the time and size of the file to be received GetXMLBuffer(strRecvBuffer,"filename",stfileinfo.filename); GetXMLBuffer(strRecvBuffer,"filesize",&stfileinfo.filesize); GetXMLBuffer(strRecvBuffer,"mtime",stfileinfo.mtime); // Replace clientpath with srvpath in the file name, with care for the third parameter UpdateStr(stfileinfo.filename,starg.clientpath,starg.srvpath,false); if (RecvFile(&logfile,TcpServer.m_connfd,&stfileinfo)== false) // Receive the contents of the file { logfile.Write("RecvFile() failed.\n"); ChldEXIT(-1); } logfile.Write("recv %s ok.\n",stfileinfo.filename); } } //111111111111111111111111111111111111111111111111111111111111111111111111111111111111 Send File Primary Function void SendFilesMain() { while (true) { memset(strRecvBuffer,0,sizeof(strRecvBuffer)); if (TcpServer.Read(strRecvBuffer,80) == false) { logfile.Write("3 TcpServer.Read() failed.\n"); ChldEXIT(-1); } // logfile.Write("3 strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx if (strstr(strRecvBuffer,"activetest")!=0) //Processing heartbeat messages { memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"ok"); // logfile.Write("3 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpServer.Write(strSendBuffer) == false) { logfile.Write("3 TcpServer.Write() failed.\n"); ChldEXIT(-1); } continue; } if (strcmp(strRecvBuffer,"<list>")==0) //Processing Get File List Messages { if (ListFile()==false) { logfile.Write("ListFile() failed.\n"); ChldEXIT(-1); } continue; } if (strncmp(strRecvBuffer,"<filename>",10)==0) //Retrieve Document Message { // Get the time and size of the file to be received 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); // Send file to client if (SendFile(&logfile,TcpServer.m_connfd,&stfileinfo)==false) ChldEXIT(-1); logfile.Write("put %s ...ok.\n",stfileinfo.filename); if (starg.ptype==2) REMOVE(stfileinfo.filename); // Delete server-side files if (starg.ptype==3) // Backup server-side files { char strfilenamebak[301]; memset(strfilenamebak,0,sizeof(strfilenamebak)); strcpy(strfilenamebak,stfileinfo.filename); UpdateStr(strfilenamebak,starg.srvpath,starg.srvpathbak,false); // Be careful with the third parameter if (RENAME(stfileinfo.filename,strfilenamebak)==false) { logfile.Write("RENAME %s to %s failed.\n",stfileinfo.filename,strfilenamebak); ChldEXIT(-1); } } } } } //111111111111111111111111111111111111111111111111111111111111111111111111111 parses xml into a parametric starg structure bool _xmltoarg(char *strxmlbuffer) { memset(&starg,0,sizeof(struct st_arg)); 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; } //111111111111111111111111111111111111111111111111111111111111111111 Lists the files under the srvpath directory and returns them to the client bool ListFile() { CDir Dir; // Note that if the total number of files in the directory exceeds 5000, the incremental file sending function will be problematic if (Dir.OpenDir(starg.srvpath,starg.matchname,50000,starg.andchild,false)==false) { logfile.Write("Dir.OpenDir(%s) Failed.\n",starg.srvpath); return false; } // Return the total number of files to the client first memset(strSendBuffer,0,sizeof(strSendBuffer)); sprintf(strSendBuffer,"<totalfile>%d</totalfile>",Dir.m_vFileName.size()); // logfile.Write("4 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpServer.Write(strSendBuffer) == false) { logfile.Write("4 TcpServer.Write() failed.\n"); return false; } while (true) //Return file information bar to client { if (Dir.ReadDir()==false) break; memset(strSendBuffer,0,sizeof(strSendBuffer)); sprintf(strSendBuffer,"<filename>%s</filename><mtime>%s</mtime><filesize>%d</filesize>",Dir.m_FullFileName,Dir.m_ModifyTime,Dir.m_FileSize); // logfile.Write("5 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpServer.Write(strSendBuffer) == false) { logfile.Write("5 TcpServer.Write() failed.\n"); return false; } } return true; }
The implementation of the client reconnection mechanism means that when the communication link is disconnected, do not quit the ClientLogin() to automatically reconnect, and multiprocess gdb debugging is inconvenient, so write a log.
UpdataStr is typically used to replace two spaces with one
3.1 Test performance: tmp. Store startup client scripts in Sh
Start uploading the file as put below. Txt. The TMP file is not transferred.
This is not a good way to check out the database on the server side and compare it with the information on the client side.
The following methods do not need to connect to the database, and are highly stable. Loading xml files in memory enables data lookup and judgment faster than tables.
4. File download module: multi-threaded
File download enables tcpputfile.cpp, tcpfileserver.cpp, in turn, does not recommend that although full duplex, there will be unreachable servers blocked by the online behavior audit system. The following is the record that the message returned by the server is stored directly in the vlistfile container, and the listfilename is not needed.
//This is a generic function module that uses TCP protocol to get files from client tcpgetfile.cpp #include "_public.h" struct st_arg { char ip[31]; // Server-side IP address. int port; // Server-side port. int ptype; // Processing method for files after successful file acquisition: 1 - Keep files; 2-Delete files; 3-Move to the backup directory. char clientpath[301]; // The root directory where local files are stored. char srvpath[301]; // Root directory where server-side files are stored. char srvpathbak[301]; // After successful file acquisition, the root directory of the server-side file backup is valid when ptype==3. bool andchild; // Whether to get files from subdirectories at all levels under the srvpath directory, true-Yes; false-no. char matchname[301]; // Match the filenames you want to get, such as'*.TXT,*.XML', in uppercase. char okfilename[301]; // A list of successful file names was obtained. No need for listfilename, the message returned by the server is placed directly in the container int timetvl; // Time interval for scanning local directory files in seconds. } starg; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message vector<struct st_fileinfo> vlistfile,vlistfile1; vector<struct st_fileinfo> vokfilename,vokfilename1; bool LoadListFile(); // Load files from the server-side srvpath directory into the vlistfile container bool LoadOKFileName(); // Load okfilename file contents into vokfilename container // Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 bool CompVector(); bool WriteToOKFileName(); // Write the contents of the vokfilename1 container into the okfilename file first, overwriting the old okfilename file bool AppendToOKFileName(struct st_fileinfo *stfileinfo); // If ptype==1, append the file records collected successfully to the okfilename file CTcpClient TcpClient; CLogFile logfile; bool _tcpgetfiles(); void EXIT(int sig); void _help(char *argv[]); bool _xmltoarg(char *strxmlbuffer); // Parsing xml into parameter starg structure bool ClientLogin(const char *argv); // logon server bool ActiveTest(); // Send heartbeat message to server bool _tcpgetfiles(); // Implement File Acquisition Function 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("Failed to open log file(%s). \n",argv[1]); return -1; } if (_xmltoarg(argv[2])==false) return -1; //Parsing xml into parameter starg structure while (true) { ClientLogin(argv[2]); // Connect to the server and log in // Implement file acquisition function, _ tcpgetfiles() does not close socket due to communication failure, _ The vlistfile container is not empty when the tcpgetfiles function returns //Loop to ClientLogin to determine login, ClientLogin to not determine if there is a problem with the socket will not go to login again, to _ tcpgetfiles Dead Loop _tcpgetfiles(); if (vlistfile.size()==0) { ActiveTest(); // Send heartbeat message to server sleep(starg.timetvl); } } return 0; } void EXIT(int sig) { logfile.Write("Program exits, sig=%d\n\n",sig); TcpClient.Close(); exit(0); } //111111111111111111111111111111111111111111111111111111111111111111111111111111 Display Program Help 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 \"<ip>172.16.0.15</ip><port>5010</port><ptype>1</ptype><clientpath>/data/shqx/sdata/surfdata</clientpath><srvpath>/data/shqx/tcp/surfdata</srvpath><srvpathbak>/data/shqx/tcp/surfdatabak</srvpathbak><andchild>true</andchild><matchname>SURF_*.TXT,*.DAT</matchname><okfilename>/data/shqx/tcplist/tcpgetfiles_surfdata.xml</okfilename><timetvl>10</timetvl>\"\n\n\n"); printf("This is a generic function module that uses TCP Client for protocol acquisition files.\n"); printf("logfilename A log file for running this program.\n"); printf("xmlbuffer The parameters for running this program are as follows:\n"); printf("ip Server-side IP Address.\n"); printf("port Server-side port.\n"); printf("clientpath Root directory where client files are stored.\n"); printf("srvpath Root directory where server-side files are stored.\n"); printf("ptype Service-side file handling after successful file acquisition:1-Keep files; 2-Delete files; 3-Move to the backup directory.\n"); printf("srvpathbak After successful file acquisition, the root directory of the server-side file backup, when ptype==3 Valid by default.\n"); printf("andchild Whether to get srvpath Files in subdirectories at all levels of the directory, true-Yes; false-No, the default is false. \n"); printf("matchname The matching method for the filename to be obtained, such as\"*.TXT,*.XML\",Be careful to capitalize.\n"); printf("okfilename A list of successful filenames was obtained, which is empty by default.\n"); printf("timetvl Time interval for scanning local directory files, in seconds, at 1-50 Between.\n\n\n"); } //1111111111111111111111111111111111111111111111111111111 parses xml into a parameter starg structure 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.port==0) { 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.ptype==3)&&(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.ptype==1)&&(strlen(starg.okfilename)==0)) { logfile.Write("okfilename is null.\n"); return false; } GetXMLBuffer(strxmlbuffer,"timetvl",&starg.timetvl); if (starg.timetvl==0) { logfile.Write("timetvl is null.\n"); return false; } if (starg.timetvl>50) starg.timetvl=50; return true; } //1111111111111111111111111111111111111111111111111111111111111 Logon Server bool ClientLogin(const char *argv) { if (TcpClient.m_sockfd>0) return true; int ii=0; while (true) { if (ii++>0) sleep(20); // Enter the cycle for the first time without hibernation // Initiate a connection to the server 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,"<clienttype>2</clienttype>"); // logfile.Write("1 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (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); // xxxxxx break; } logfile.Write("login(%s,%d) ok.\n",starg.ip,starg.port); return true; } //11111111111111111111111111111111111111111111111111111111111 11 send a heartbeat message to the server bool ActiveTest() { memset(strRecvBuffer,0,sizeof(strRecvBuffer)); memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"<activetest>ok</activetest>"); // logfile.Write("2 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (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); // xxxxxx if (strcmp(strRecvBuffer,"ok") != 0) { TcpClient.Close(); return false; } return true; } //111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 Implement File Acquisition Function bool _tcpgetfiles() { // Load files from the server-side srvpath directory into the vlistfile container if (LoadListFile()==false) { logfile.Write("LoadListFile() failed.\n"); TcpClient.Close(); return false; } if (starg.ptype==1) { // Load the contents of the okfilename file into the container vokfilename LoadOKFileName(); // Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 CompVector(); WriteToOKFileName(); // Write the contents of the vokfilename1 container into the okfilename file first, overwriting the old okfilename file vlistfile.clear(); vlistfile.swap(vlistfile1); // Copy the contents of the vlistfile1 container into the vlistfile container } for (int ii=0;ii<vlistfile.size();ii++) // Get new or changed files one by one from the server { memset(strSendBuffer,0,sizeof(strSendBuffer)); // Send the server file information that will be retrieved (downloaded) sprintf(strSendBuffer,"<filename>%s</filename><filesize>%d</filesize><mtime>%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; } // File information already knows that this message is redundant, but in order to be compatible with SendFile and RecvFile functions, there is no performance impact. if (TcpClient.Read(strRecvBuffer) == false) { logfile.Write("3 TcpClient.Read() failed.\n"); TcpClient.Close(); return false; } // logfile.Write("3 strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx // Replace clientpath with srvpath in the file name, with care for the third parameter struct st_fileinfo stfileinfo; memset(&stfileinfo,0,sizeof(struct st_fileinfo)); strcpy(stfileinfo.filename,vlistfile[ii].filename); strcpy(stfileinfo.mtime,vlistfile[ii].mtime); stfileinfo.filesize=vlistfile[ii].filesize; UpdateStr(stfileinfo.filename,starg.srvpath,starg.clientpath); logfile.Write("get %s ...",stfileinfo.filename); // ptype=1 is incremental, does nothing to the server, and keeps oklistfile as client if (RecvFile(&logfile,TcpClient.m_sockfd,&stfileinfo)== false) // Receive the contents of the file { logfile.Write("RecvFile() failed.\n"); TcpClient.Close(); return false; } logfile.WriteEx("ok.\n"); // If ptype==1, append the file records collected successfully to the okfilename file if (starg.ptype==1) AppendToOKFileName(&vlistfile[ii]); } return true; } //11111111111111111111111111111111111111111111 11 Load files from the srvpath directory on the server side into the vlistfile container bool LoadListFile() { vlistfile.clear(); memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"<list>"); //Send <list> to the service side as you would a nlist command to the ftp service side // 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 message is the total number of files int totalfile=0; GetXMLBuffer(strRecvBuffer,"totalfile",&totalfile); struct st_fileinfo stfileinfo; for (int ii=0;ii<totalfile;ii++) //Receive file list message by loop and parse it into vlistfile container { 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); // xxxxxx GetXMLBuffer(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; } //11111111111111111111111111111111111111111111111111111111 Load okfilename file contents into vokfilename container bool LoadOKFileName() { vokfilename.clear(); CFile File; // Note: If the program is the first collection, okfilename does not exist, it is not an error, so it also returns 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; } //11111111111111111111111111 Compare the files in the vlistfile container with those in the vokfilename container to get two containers // 1. File vokfilename1 that exists in vlistfile and has been successfully collected // 2. There is a new file or a file that needs to be re-collected in vlistfile1 bool CompVector() { vokfilename1.clear(); vlistfile1.clear(); for (int ii=0;ii<vlistfile.size();ii++) { int jj=0; for (jj=0;jj<vokfilename.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 (jj==vokfilename.size()) { vlistfile1.push_back(vlistfile[ii]); } } /* for (int ii=0;ii<vokfilename1.size();ii++) { logfile.Write("vokfilename1 filename=%s,mtime=%s\n",vokfilename1[ii].filename,vokfilename1[ii].mtime); } for (int ii=0;ii<vlistfile1.size();ii++) { logfile.Write("vlistfile1 filename=%s,mtime=%s\n",vlistfile1[ii].filename,vlistfile1[ii].mtime); } */ return true; } //111111111111111 Writes the contents of the vokfilename1 container into the okfilename file first, overwriting the previous old okfilename file bool WriteToOKFileName() { CFile File; if (File.Open(starg.okfilename,"w",false) == false) // Note that do not use buffering when opening files { logfile.Write("File.Open(%s) failed.\n",starg.okfilename); return false; } for (int ii=0;ii<vokfilename1.size();ii++) { File.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",vokfilename1[ii].filename,vokfilename1[ii].mtime); } return true; } //1111111111111111111 If ptype==1, append the file records collected successfully to the okfilename file 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</filename><mtime>%s</mtime>\n",stfileinfo->filename,stfileinfo->mtime); return true; }
Dual Channel: Content written in by oneself must not be read out by oneself (two channels). Both tcpputfile.cpp and tcpgetfile.cpp are single process equivalent to two clients, can be combined into a single process program, add a clienttype parameter to the xml parameter, clienttype=1 call_tcpputfile(), =2 call_tcpputfile(), =2 call_ tcpgetfile(). Alternatively, multithreading can support multiple tasks (one task is taken from server a directory and the other from server b directory). In fact, configuring two lines of scripts (one a directory and one b directory) in get.sh is enough. There is no need to integrate multiprocess and multithreading.
4.1 Test performance: tcpfileserver. The CPP multi-process program starts more than 200 processes (some required by system files), servers have 1G of memory and can only access 50 clients
Replicate 10 rows to replace 01 digits, then complete the first 10 rows to replace 10 digits.
4.2 Change server to multithreaded: TcpServer when new client is connected. M_ The value connfd changes, such as m_after the first client connects Connfd=10, m_after the second client connects Connfd=11, =10 This parameter was passed to the thread pth_ Mains. There is no reservation for main main program 10, it is unknown, only the thread knows, main main program only knows 11
If (int) is changed in (long) below, an error from int* to int will be reported for loss of precision.
There's a problem: Thread pth_main() must shut down its socket such as 10 when it exits. If it does not matter, the main program does not know to shut down at all. If the thread exits itself, it can close the sockets, but if it sends a signal to the whole program, the thread will not receive the signal, and an exit will all go back. These sockets are not closed yet.
So one solution is to put all client socket connections in a container, vector < int > vclientfd, and push in AddClient(). When a thread exits, it needs to delete the socket from the container before closing the socket, which is RemoveClient(), and closing the socket in the container when the EXIT() program exits. File transfer server multiprocesses are appropriate but some resources need to be shared using multithreads.
//This is a general function module, which uses TCP protocol to implement file transfer server, tcpfileserver1.cpp multithreading. #include "_public.h" struct st_arg { int clienttype; char ip[31]; // Server-side IP address. int port; // Server-side port. int ptype; // Processing method of file after successful sending: 1 - Keep the file; 2-Move to the backup directory; 3-Delete the file. char clientpath[301]; // The root directory where local files are stored. char clientpathbak[301]; // After the file is successfully sent, the root directory of the local file backup is valid when ptype==2. char srvpath[301]; // Root directory where server-side files are stored. char srvpathbak[301]; // After the file is successfully received, the root directory of the server-side file backup is valid when ptype==2. bool andchild; // Whether to send files from subdirectories at all levels in the clientpath directory, true-Yes; false-no. char matchname[301]; // Match file names to be sent, such as'*.TXT,*.XML', in uppercase. char okfilename[301]; // A list of successful file names has been sent. int timetvl; // Time interval for scanning local directory files in seconds. }; bool _xmltoarg(char *strxmlbuffer,struct st_arg *starg); //Parsing xml into parameter starg structure CLogFile logfile; bool ClientLogin(int clientfd,struct st_arg *starg); // Waiting for login bool ListFile(int clientfd,struct st_arg *starg); // Lists the files in the srvpath directory and returns them to the client. void EXIT(int sig); // Functions called on program exit void *pth_main(void *arg); // Main function of communication thread with client bool RecvFilesMain(int clientfd,struct st_arg *starg); // Receive File Main Function bool SendFilesMain(int clientfd,struct st_arg *starg); // Send File Main Function vector<int> vclientfd; // Container for client connected socket s void AddClient(int clientfd); // Add the client's new socket to the vclientfd container void RemoveClient(int clientfd); // Close the client's socket and remove it from the vclientfd container. 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("This program is a common function module, which uses TCP/IP A server that transfers files.\n"); printf("This program uses a multi-threaded server, the multi-process server program is tcpfileserver.cpp. \n"); printf("logfilename Log file name.\n"); printf("port For file transfer TCP Port.\n"); return -1; } CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT); // Open program run log, this is a multi-process program, log can not be switched automatically 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; //Define as a local variable if (TcpServer.InitServer(atoi(argv[2])) == false) { logfile.Write("TcpServer.InitServer(%s) failed.\n",argv[2]); return -1; } AddClient(TcpServer.m_listenfd); //Save listenfd to vclientfd on the server side while (true) { if (TcpServer.Accept() == false) //Waiting for client connection { logfile.Write("TcpServer.Accept() failed.\n"); continue; } pthread_t pthid; //Clients connect to create a first-line route, and the socket parameters are passed in below to communicate with newly connected clients // int4 bytes, long8 bytes, * pointer 8 bytes, TcpServer.m_connfd defines an integer int if (pthread_create(&pthid,NULL,pth_main,(void*)(long)TcpServer.m_connfd)!=0) { //Subthreads such as the main thread end logfile.Write("The thread creation failed and the program exited. n"); close(TcpServer.m_connfd); EXIT(-1); } logfile.Write("%s is connected.\n",TcpServer.GetIP()); AddClient(TcpServer.m_connfd); //Save each client's socket to vclientfd } return 0; } //11111111111111111111111111111111111111111111111111111111111111 void EXIT(int sig) { signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN); if (sig>0) signal(sig,SIG_IGN); logfile.Write("tcpfileserver1 exit,sig=%d...\n",sig); // Close all socket s in the vclientfd container to release resources for (int ii=0;ii<vclientfd.size();ii++) { close(vclientfd[ii]); } exit(0); } //11111111111111111111111111111111111111111111111111111111111111111 Waiting for login bool ClientLogin(int clientfd,struct st_arg *starg) { int ibuflen=0; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message memset(strRecvBuffer,0,sizeof(strRecvBuffer)); memset(strSendBuffer,0,sizeof(strSendBuffer)); //Previously used TcpServer.Read, now TcpRead, there is no TcpServer object in the thread //TcpServer.Read also calls TcpRead if (TcpRead(clientfd,strRecvBuffer,&ibuflen,20) == false) { logfile.Write("1 TcpRead() failed.\n"); return false; } // logfile.Write("1 strRecvBuffer=%s\n",strRecvBuffer); // xxxxxx GetXMLBuffer(strRecvBuffer,"clienttype",&starg->clienttype); if ( (starg->clienttype==1) || (starg->clienttype==2) ) strcpy(strSendBuffer,"ok"); else strcpy(strSendBuffer,"failed"); // logfile.Write("1 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (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; // Parse out the parameters _xmltoarg(strRecvBuffer,starg); return true; } //11111111111111111111111111111111111111111111111111111111111111 Receive File Primary Function bool RecvFilesMain(int clientfd,struct st_arg *starg) { int ibuflen=0; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message 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 // Processing heartbeat messages if (strstr(strRecvBuffer,"activetest")!=0) { strcpy(strSendBuffer,"ok"); // logfile.Write("2 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpWrite(clientfd,strSendBuffer) == false) { logfile.Write("2 TcpWrite() failed.\n"); return false; } continue; } struct st_fileinfo stfileinfo; memset(&stfileinfo,0,sizeof(struct st_fileinfo)); // Get the time and size of the file to be received GetXMLBuffer(strRecvBuffer,"filename",stfileinfo.filename); GetXMLBuffer(strRecvBuffer,"filesize",&stfileinfo.filesize); GetXMLBuffer(strRecvBuffer,"mtime",stfileinfo.mtime); // Replace clientpath with srvpath in the file name, with care for the third parameter UpdateStr(stfileinfo.filename,starg->clientpath,starg->srvpath,false); // Receive the contents of the file if (RecvFile(&logfile,clientfd,&stfileinfo)== false) { logfile.Write("RecvFile() failed.\n"); return false; } logfile.Write("recv %s ok.\n",stfileinfo.filename); } return true; } //11111111111111111111111111111111111111111111111111111111111111111 Send File Primary Function bool SendFilesMain(int clientfd,struct st_arg *starg) { int ibuflen=0; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message 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 // Processing heartbeat messages if (strstr(strRecvBuffer,"activetest")!=0) { memset(strSendBuffer,0,sizeof(strSendBuffer)); strcpy(strSendBuffer,"ok"); // logfile.Write("3 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpWrite(clientfd,strSendBuffer) == false) { logfile.Write("3 TcpWrite() failed.\n"); return false; } continue; } // Processing Get File List Messages if (strcmp(strRecvBuffer,"<list>")==0) { if (ListFile(clientfd,starg)==false) { logfile.Write("ListFile() failed.\n"); return false; } continue; } // Retrieve Document Message if (strncmp(strRecvBuffer,"<filename>",10)==0) { // Get the time and size of the file to be received 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); // Send file to client if (SendFile(&logfile,clientfd,&stfileinfo)==false) return false; logfile.Write("put %s ...ok.\n",stfileinfo.filename); // Delete server-side files if (starg->ptype==2) REMOVE(stfileinfo.filename); // Backup server-side files if (starg->ptype==3) { char strfilenamebak[301]; memset(strfilenamebak,0,sizeof(strfilenamebak)); strcpy(strfilenamebak,stfileinfo.filename); UpdateStr(strfilenamebak,starg->srvpath,starg->srvpathbak,false); // Be careful with the third parameter if (RENAME(stfileinfo.filename,strfilenamebak)==false) { logfile.Write("RENAME %s to %s failed.\n",stfileinfo.filename,strfilenamebak); return false; } } } } return true; } //11111111111111111111111111111111111111111111111111111111111111 parses xml into the parameter starg structure 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; } //1111111111111111111111111111111111111111111111111111111 lists the files under the srvpath directory and returns them to the client. bool ListFile(int clientfd,struct st_arg *starg) { int ibuflen=0; char strRecvBuffer[TCPBUFLEN+10]; // Buffer to receive message char strSendBuffer[TCPBUFLEN+10]; // Buffer for sending message CDir Dir; // Note that if the total number of files in the directory exceeds 5000, the incremental file sending function will be problematic if (Dir.OpenDir(starg->srvpath,starg->matchname,50000,starg->andchild,false)==false) { logfile.Write("Dir.OpenDir(%s) Failed.\n",starg->srvpath); return false; } // Return the total number of files to the client first memset(strSendBuffer,0,sizeof(strSendBuffer)); sprintf(strSendBuffer,"<totalfile>%d</totalfile>",Dir.m_vFileName.size()); // logfile.Write("4 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpWrite(clientfd,strSendBuffer) == false) { logfile.Write("4 TcpWrite() failed.\n"); return false; } // Return file information bar to client while (true) { if (Dir.ReadDir()==false) break; memset(strSendBuffer,0,sizeof(strSendBuffer)); sprintf(strSendBuffer,"<filename>%s</filename><mtime>%s</mtime><filesize>%d</filesize>",Dir.m_FullFileName,Dir.m_ModifyTime,Dir.m_FileSize); // logfile.Write("5 strSendBuffer=%s\n",strSendBuffer); // xxxxxx if (TcpWrite(clientfd,strSendBuffer) == false) { logfile.Write("5 TcpWrite() failed.\n"); return false; } } return true; } //Main function of the communication thread with the client in 111111111111111111111111111111111111111111111111111111111111111111111 void *pth_main(void *arg) { int clientfd=(long) arg; // The arg parameter is the socket of the new client pthread_detach(pthread_self()); struct st_arg starg; memset(&starg,0,sizeof(struct st_arg)); // Waiting for client to log in if (ClientLogin(clientfd,&starg) == false) { RemoveClient(clientfd); pthread_exit(0); } // Receive File Main Function if (starg.clienttype==1) { if (RecvFilesMain(clientfd,&starg) == false) { RemoveClient(clientfd); pthread_exit(0); } } // Send File Main Function if (starg.clienttype==2) { if (SendFilesMain(clientfd,&starg) == false) { RemoveClient(clientfd); pthread_exit(0); } } RemoveClient(clientfd); pthread_exit(0); } //11111111111111111111111111111111111111111111111111 11 Add client new socket s to vclientfd container void AddClient(int clientfd) { vclientfd.push_back(clientfd); } //11111111111111111111111111111111111111111111111 Close the client's socket and remove it from the vclientfd container void RemoveClient(int clientfd) { for (int ii=0;ii<vclientfd.size();ii++) { if (vclientfd[ii]==clientfd) { close(clientfd); vclientfd.erase(vclientfd.begin()+ii); return; } } }