TCP客户端无法在C中正确处理断开的服务器连接

TCP客户端无法在C中正确处理断开的服务器连接,c,sockets,tcp,network-programming,client-server,C,Sockets,Tcp,Network Programming,Client Server,我使用TCP创建了自己的ftp服务器/客户端(一个非常简单的版本)。有5个可能的命令:ls remote、ls local、get、put和exit。此外,我在服务器代码中使用了多处理,以便能够通过使用fork()同时处理多个客户机。除了我注意到的一件事之外,一切都正常工作:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我检查发送调用的返回值是否小于0,然后关闭套接字,并调用exit(-1)终止进程;然而,这导致我的客户被绞死 我的客户: #include <

我使用TCP创建了自己的ftp服务器/客户端(一个非常简单的版本)。有5个可能的命令:ls remote、ls local、get、put和exit。此外,我在服务器代码中使用了多处理,以便能够通过使用fork()同时处理多个客户机。除了我注意到的一件事之外,一切都正常工作:我在正确处理损坏的服务器连接时遇到问题。例如,如果服务器发送消息时出现问题,我检查发送调用的返回值是否小于0,然后关闭套接字,并调用exit(-1)终止进程;然而,这导致我的客户被绞死

我的客户:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdio.h>

void readDirectory();

void syserr(char* msg) 
{ perror(msg); 
  exit(-1); 
}

int main(int argc, char* argv[])
{
  int sockfd, portno, n;
  struct hostent* server;
  struct sockaddr_in serv_addr;
  char buffer[256], temp[256];

  if(argc < 3) {
    fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
    return 1;
  }

    portno = atoi(argv[2]);


  server = gethostbyname(argv[1]);
  if(!server) {
    fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
    return 2;
  }

  sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(sockfd < 0) syserr("can't open socket");

  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
  serv_addr.sin_port = htons(portno);

  if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    syserr("can't connect to server");

  printf("Connection to %s:%s established. Now awaiting commands...\n\n\n", argv[1], argv[2]);


  do{
     printf("%s:%s> ", argv[1], argv[2]); //prompt user for command
     fgets(buffer, 255, stdin);
     n = strlen(buffer);

    if(n>0 && buffer[n-1] == '\n')
      buffer[n-1] = '\0';


    if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
      uint32_t size;
      uint32_t commandSize = strlen(buffer);

       //convert to network form
       commandSize = htonl(commandSize);

       n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server 
       if(n < 0) syserr("can't send to server");

       n = send(sockfd, buffer, strlen(buffer), 0); // send command to server 
       if(n < 0) syserr("can't send to server");

       n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
       if(n < 0) syserr("can't receive from server");

       size = ntohl(size);
       int currentSize = 0;
       printf("Files at the server: %s\n", argv[1]);

        while(currentSize < size){
            memset(&buffer[0], 0, sizeof(buffer));
            n = recv(sockfd, buffer, 255, 0); // recieve directory from server 
            if(n < 0) syserr("can't recieve server");

            currentSize = currentSize + n;

            printf("%s", buffer);
        }
    }
    else if(strcmp(buffer, "ls-local") == 0){ //display files from local directory
        printf("Files at the client: \n");
       readDirectory();
    }
    else if(strncmp(buffer, "get ", 4) == 0){ //downlaod file from server


       if(strlen(buffer) < 5){ // no file was entered
          printf("%s\n", "ERROR...missing filename: get <filename>");
        }
       else{
          uint32_t fileSize;
          uint32_t commandSize = strlen(buffer);


          //convert to network form
          commandSize = htonl(commandSize);

          n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
          if(n < 0) syserr("can't send to server");

          n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
          if(n < 0) syserr("can't send to server");

           n = recv(sockfd, &fileSize, sizeof(fileSize), 0); // get size of file 
                  if(n < 0) syserr("can't receive from server");

          fileSize = ntohl(fileSize);

          if(fileSize == -1){
              printf("%s\n", "File does not exist");
           }
           else{   // file exists
               int totalBytes = 0;
               int bytesWritten = 0;

                // get file name
                char *fileName = strtok(buffer, " ");
                fileName = strtok(NULL, " ");

                memcpy(temp, fileName, strlen(fileName)); //copy filename into temp
                temp[strlen(fileName)] = '\0';


              //create new file with given name
              FILE *fpNew = fopen(fileName, "w");

              if(fpNew){

                  while(totalBytes < fileSize){
                      //receieve the bytes
                      n = recv(sockfd, buffer, sizeof(buffer), 0);
                      if(n < 0) syserr("can't receive from server");

                      //write the bytes
                      int b = fwrite(buffer, 1, n, fpNew);

                      if (b < 0)
                      syserr("error writing file");

                      if(n == 0){ // error reading on server side 
                        break;
                      }

                      totalBytes = n + totalBytes;
                      bytesWritten = b + bytesWritten;

                    }

                    fclose(fpNew);
                     if(bytesWritten == fileSize) // all bytes read/written to file successfully
                       printf("Retrieval of file %s: successful.\n", temp);
                     else
                       printf("Retrieval of file %s: unsuccessful.\n", temp);

                 }
                 else{
                       syserr("couldnt open file for writing.");
                 }
           }
        }
     }
     else if(strncmp(buffer, "put ", 4) == 0){ // upload file to server
          if(strlen(buffer) < 5){
          printf("%s\n", "ERROR...missing filename: get <filename>");
        }
        else{
            uint32_t commandSize = strlen(buffer);
            uint32_t  status;

            memcpy(temp, buffer, strlen(buffer)); //copy buffer into temp
            temp[strlen(buffer)] = '\0';

            // get name of file
            char *fileName = strtok(temp, " ");
            fileName = strtok(NULL, " ");
            int bytes;

            FILE *fp = fopen(fileName, "r"); // open the file

            if(fp){  // file exists and opened
                int totalBytes = 0;
                  //convert to network form
                commandSize = htonl(commandSize);

                n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
                if(n < 0) syserr("can't send to server");

                n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
                if(n < 0) syserr("can't send to server");

                // get file size
                fseek(fp, 0L, SEEK_END);
                int fileSize = ftell(fp);

               // send the file size
               uint32_t size = htonl(fileSize);

               n = send(sockfd, &size, sizeof(size), 0);
               if(n < 0) syserr("can't send to server");

               //go back to beginning of file
               fseek(fp, 0, SEEK_SET);

               while(totalBytes < fileSize){  // while there are more bytes...

                  bytes = fread(buffer, 1, sizeof(buffer), fp); // read bytes fromt he file

                  if(bytes < 0){
                    syserr("Error reading the file.");
                  }

                  totalBytes = totalBytes + bytes;

                   //send the bytes
                   n = send(sockfd, buffer, bytes, 0);
                   if(n < 0) syserr("can't send to server");


                  if(bytes == 0){ //error reading
                   break;
                  }

                }

               fclose(fp);

               //recieve the final status
                n = recv(sockfd, &status, sizeof(status), 0);
                  if(n < 0) syserr("can't receive from server");

                 status = ntohl(status); 

              if(totalBytes == fileSize && status == 1){ // successful on both ends
               printf("Upload of file %s: successful.\n", fileName);
              }
              else{
                 printf("Upload of file %s: unsuccessful.\n", fileName);
              }

          }
           else{
              printf("%s\n", "File does not exist");
           }
        }
     }else if(strcmp(buffer, "exit") == 0){
      uint32_t commandSize = strlen(buffer);
          //convert to network form
          commandSize = htonl(commandSize);

          n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
          if(n < 0) syserr("can't send to server");

          n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
          if(n < 0) syserr("can't send to server");

     }
     else{
       if(strcmp(buffer, "exit") != 0)
         printf("Error...invalid command.\nValid commands: ls-remote, ls-local, get <filename>, put <filename>, exit\n");
     }
   }while (strcmp(buffer, "exit") != 0);

   printf("Connection to server %s:%s terminated, BYE now!\n", argv[1], argv[2]);
   close(sockfd);
   return 0;
 }

void readDirectory(){
  DIR *d = opendir(".");
  struct dirent *dir;
    if (d)
      {
        while((dir = readdir(d))!= NULL)
        {
          printf("%s\n", dir->d_name);
        }
      closedir(d);
    }
    else{
       syserr("Error...could not get files from directory.");
    }
  }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
void readDirectory();
void syserr(字符*msg)
{perror(msg);
出口(-1);
}
int main(int argc,char*argv[])
{
int sockfd,端口号,n;
结构主机*服务器;
服务地址中的结构sockaddr\u;
字符缓冲区[256],临时缓冲区[256];
如果(argc<3){
fprintf(stderr,“用法:%s\n”,argv[0]);
返回1;
}
portno=atoi(argv[2]);
server=gethostbyname(argv[1]);
如果(!服务器){
fprintf(stderr,“错误:没有这样的主机:%s\n”,argv[1]);
返回2;
}
sockfd=套接字(AF_INET、SOCK_STREAM、IPPROTO_TCP);
如果(sockfd<0)syserr(“无法打开套接字”);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr=*((_addr*)服务器中的结构->h_addr);
serv_addr.sin_port=htons(端口号);
if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
syserr(“无法连接到服务器”);
printf(“已建立到%s:%s的连接。正在等待命令…\n\n\n”,argv[1],argv[2]);
做{
printf(“%s:%s>”,argv[1],argv[2]);//提示用户输入命令
fgets(缓冲区,255,标准输入);
n=strlen(缓冲区);
如果(n>0&&buffer[n-1]='\n')
缓冲区[n-1]='\0';
if(strcmp(buffer,“ls remote”)==0{//显示服务器目录中的文件
uint32_t尺寸;
uint32\u t commandSize=strlen(缓冲区);
//转换为网络形式
commandSize=htonl(commandSize);
n=send(sockfd,&commandSize,sizeof(commandSize),0);//将命令的大小发送到服务器
如果(n<0)syserr(“无法发送到服务器”);
n=send(sockfd,buffer,strlen(buffer),0);//向服务器发送命令
如果(n<0)syserr(“无法发送到服务器”);
n=recv(sockfd,&size,sizeof(size),0);//接收目录的大小
如果(n<0)syserr(“无法从服务器接收”);
尺寸=ntohl(尺寸);
int currentSize=0;
printf(“服务器上的文件:%s\n”,argv[1]);
while(当前大小<大小){
memset(&buffer[0],0,sizeof(buffer));
n=recv(sockfd,buffer,255,0);//从服务器接收目录
如果(n<0)syserr(“无法接收服务器”);
currentSize=currentSize+n;
printf(“%s”,缓冲区);
}
}
else if(strcmp(buffer,“ls local”)==0){//显示本地目录中的文件
printf(“客户端的文件:\n”);
readDirectory();
}
else if(strncmp(buffer,“get”,4)==0){//download来自服务器的文件
如果(strlen(buffer)<5){//没有输入文件
printf(“%s\n”,“错误…缺少文件名:get”);
}
否则{
uint32_t文件大小;
uint32\u t commandSize=strlen(缓冲区);
//转换为网络形式
commandSize=htonl(commandSize);
n=send(sockfd,&commandSize,sizeof(commandSize),0);//将命令的大小发送到服务器
如果(n<0)syserr(“无法发送到服务器”);
n=send(sockfd,buffer,strlen(buffer),0);//向服务器发送命令
如果(n<0)syserr(“无法发送到服务器”);
n=recv(sockfd,&fileSize,sizeof(fileSize),0);//获取文件大小
如果(n<0)syserr(“无法从服务器接收”);
fileSize=ntohl(fileSize);
如果(文件大小==-1){
printf(“%s\n”,“文件不存在”);
}
否则{//文件存在
int totalBytes=0;
int字节数=0;
//获取文件名
char*fileName=strtok(缓冲区“”);
fileName=strtok(NULL,“”);
memcpy(临时,文件名,strlen(文件名));//将文件名复制到临时
临时文件[strlen(文件名)]='\0';
//创建具有给定名称的新文件
FILE*fpNew=fopen(文件名,“w”);
如果(fpNew){
while(总字节<文件大小){
//接收字节
n=recv(sockfd,buffer,sizeof(buffer),0);
如果(n<0)syserr(“无法从服务器接收”);
//写入字节
intb=fwrite(缓冲区,1,n,fpNew);
if(b<0)
syserr(“错误写入文件”);
如果(n==0){//在服务器端读取时出错
打破
}
totalBytes=n+totalBytes;
字节写入=b+字节写入;
}
fclose(fpNew);
if(bytesWrited==fileSize)//成功读取/写入文件的所有字节
printf(“检索文件%s:成功。\n”,临时文件);
其他的
printf(“检索文件%s:不成功。\n”,临时文件);
}
否则{
syserr(“无法打开文件进行写入”);
}
}
}
}
else if(strncmp(缓冲区,“put”,4)=0){//将文件上载到服务器
if(strlen(缓冲区)<5){
printf(“%s\n”,“错误…缺少文件名:get”);
}
否则{
uint32\u t commandSize=strlen(缓冲区);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <dirent.h>

void syserr(char *msg){
 perror(msg); exit(-1); 
}
void errorHandling(char *msg, int newsockfd){
 close(newsockfd);
 perror(msg); exit(-1); 
}
uint32_t directorySize();
void handle_client(int newsockfd);


int main(int argc, char *argv[])
{
  int sockfd, newsockfd, portno;
  struct sockaddr_in serv_addr, clt_addr;
  socklen_t addrlen;

  if(argc < 1) { 
    fprintf(stderr,"Usage: %s <port>\n", argv[0]);
    return 1;
  } 
  if(argc == 1){
    argv[1] = "5555";
  }

  portno = atoi(argv[1]);

  sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  if(sockfd < 0) syserr("can't open socket"); 

  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_port = htons(portno);

  if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) 
    syserr("can't bind");
  printf("bind socket to port %d...\n", portno);

  listen(sockfd, 5); 


for(;;){

  printf("wait on port %d...\n", portno);
  addrlen = sizeof(clt_addr); 
  newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
  if(newsockfd < 0) syserr("can't accept"); 

   pid_t pid = fork();

   if(pid < 0){
    syserr("Error can't fork");
   }
   else if(pid == 0){ // child process
     close(sockfd);
     handle_client(newsockfd);
     close(newsockfd);
     break;
   }
   else{ // parent
     close(newsockfd);
     continue;
   } 

  }
  return 0;
}

uint32_t directorySize(int newsockfd){
    DIR *d = opendir(".");
    struct dirent *dir;
    uint32_t count = 0;

    if (d)
      {
        while((dir = readdir(d))!= NULL)
        {
         //count++;
            count = strlen(dir->d_name) + count + 1;
        }
      closedir(d);
    }
    else{
       errorHandling("Error...could not get files from directory.", newsockfd);
     }

    return count;
  }
  void handle_client(int newsockfd){

    // receieve command size from client
  uint32_t commandSize;
  int n;
  char buffer[256];

  while(1){
  n = recv(newsockfd, &commandSize, sizeof(commandSize), 0); // receive size of command
  if(n < 0) errorHandling("can't receive from client", newsockfd); 

  commandSize = ntohl(commandSize);

  //recieve command
  n = recv(newsockfd, buffer, commandSize, 0); 
  if(n < 0) errorHandling("can't receive from client", newsockfd); 

  else buffer[n] = '\0';


  if(strcmp(buffer, "ls-remote") == 0){  //display files from server directory

      // get the size of the directory
      uint32_t size = htonl(directorySize(newsockfd));

      n = send(newsockfd, &size, sizeof(size), 0); // send size of directory
      if(n < 0) errorHandling("can't send to client", newsockfd); 


      DIR *d = opendir(".");
      struct dirent *dir;

      if(d){
          while((dir = readdir(d))!= NULL){
              memset(&buffer[0], 0, sizeof(buffer));
             strcpy(buffer, dir->d_name);
             buffer[strlen(buffer)] = '\n';

             // send file/folder names
             n = send(newsockfd, buffer, strlen(buffer), 0);
            if(n < 0) 
              errorHandling("can't receive from client", newsockfd); 

       }

        closedir(d);

    }
    else{
       errorHandling("Error...could not get files from directory.", newsockfd);
    }

}
 else if (strncmp(buffer, "get", 3) == 0){  // if command is get
    char *fileName = strtok(buffer, " "); // "get"
    fileName = strtok(NULL, " "); // the name of the file
    FILE *fp = fopen(fileName, "r");

    if(fp){  // if file exists
        int totalBytes = 0;
        int bytes;

        // get the size of the file
        fseek(fp, 0L, SEEK_END);
        int fileSize = ftell(fp);

        // send the file size
         uint32_t size = htonl(fileSize);

         n = send(newsockfd, &size, sizeof(size), 0);
         if(n < 0) errorHandling("can't send to client", newsockfd); 


         //go back to beginning of file
         fseek(fp, 0, SEEK_SET);

         while(totalBytes < fileSize){ // while there are more bytes to read...

           // read the bytes into the buffer
           bytes = fread(buffer, 1, sizeof(buffer), fp);
           if(bytes < 0){
            errorHandling("Eorror reading bytes on server side", newsockfd);
           }

            //send the bytes
            n = send(newsockfd, buffer, bytes, 0);
            if(n < 0) errorHandling("can't send to client", newsockfd); 

            if(bytes == 0) // error reading file; bytes should have been > 0
                break;

            totalBytes = totalBytes + bytes;  
        }

         fclose(fp);
    }
     else{
      // tell client file doesnt exist by sending -1
        uint32_t dne = htonl(-1);
        n = send(newsockfd, &dne, sizeof(dne), 0);
        if(n < 0) errorHandling("can't send to client", newsockfd); 

     }
  }
  else if (strncmp(buffer, "put", 3) == 0){ // upload a file
      int totalBytes = 0;
      int bytesWritten = 0;
      int b = 0;
      uint32_t fileSize, status;

      n = recv(newsockfd, &fileSize, sizeof(fileSize), 0);// receive the size of file 
      if(n < 0) errorHandling("can't receive from client", newsockfd); 

      fileSize = ntohl(fileSize);

       // get file name
       char *fileName = strtok(buffer, " ");
       fileName = strtok(NULL, " ");

       //create new file with given name
        FILE *fpNew = fopen(fileName, "w");

          if(fpNew){
            while(totalBytes < fileSize){
                n = recv(newsockfd, buffer, sizeof(buffer), 0);
                  if(n < 0) errorHandling("can't receive from client", newsockfd); 

                 if(n == 0){ //bad file transfer on client side
                    break;
                 }

                 //write the bytes 
                 b = fwrite(buffer, 1, n, fpNew);

                 if(b < n){ // error writing to file
                    break;
                 }
                 totalBytes = totalBytes + n; // bytes recived
                 bytesWritten = bytesWritten + b; //bytes written

             }     

                  fclose(fpNew);

                  if(bytesWritten != fileSize){ // not all bytes written
                    status = htonl(-1); 
                  }
                  else{
                    status = htonl(1);
                  }

                  // send the status
                  n = send(newsockfd, &status, sizeof(status), 0);
                   if(n < 0) errorHandling("can't send client", newsockfd); 
          }
          else{
            errorHandling("could not open file for writing.", newsockfd);
          }

      } 
       else{ // command is exit
            printf("%s\n", "closing connection");
            close(newsockfd); // close the connection
            break;

        }

      }

   }
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");