Weather APP: File Transfer System (tcpput/getfile.cpp client, tcpfileserver.cpp)

Posted by MathewByrne on Mon, 20 Dec 2021 23:32:58 +0100

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; }
  }
}

Topics: C++ Linux socket