Задержка сервера на системную команду в C - PullRequest
0 голосов
/ 25 января 2020

У меня есть две программы: одна выступает в роли сервера, а другая - в качестве клиента. Предполагается, что они действуют так, как будто вы подключаетесь к удаленной системе, используя s sh. Клиент отправляет команду, а сервер выполняет команду и печатает вывод на сервер. Хотя мой код делает именно это, на выходе после первой команды есть задержка. Например, если клиент отправляет date, сервер вернет дату. Если клиент отправит date снова, он напечатает message was received, но не выводит. При третьем вводе от клиента вторая дата будет выполнена и напечатана на клиенте Here is the message:date и так далее. Любые идеи будут по-настоящему оценены.

Сервер:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_PINS 1
void error(const char *msg){
     perror(msg);
     exit(1);
}

void exec_comm(int sock,int nerror,char buff[]){
     dup2(sock,1);
     dup2(nerror,2);
     if(system(buff)==-1){
          printf("command not found\n");
     }
}
int main(int argc, char *argv[]){
  int sockfd, newsockfd, portno, pid;
  socklen_t clilen;
  char buffer[256];
  char* comm[20],*cbuff;
  struct sockaddr_in serv_addr, cli_addr;
  int n,i,done=0,correct=0;
  char str[INET_ADDRSTRLEN];
  char* args,*pins[MAX_PINS]={"1234"},pin[10];
  FILE* fd;
  int nerror;
     if (argc < 2){
       fprintf(stderr, "No port provided\n");
       exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0)
     error("ERROR opening socket");
     memset((char *) &serv_addr, 0, sizeof(serv_addr));
     portno = atoi(argv[1]);
     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)
     error("ERROR on binding");

          listen(sockfd, 5);
          clilen = sizeof(cli_addr);
          newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
          if (newsockfd < 0)
          error("ERROR on accept");
          if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
          fprintf(stderr, "Could not convert byte to address\n");
          exit(1);
          }
          fprintf(stdout, "The client address is :%s\n", str);
while(1){
               bzero(buffer, 256);
               n = read(newsockfd, buffer, 255);
               sscanf(buffer,"%s\n",buffer);
               printf("The message that was read was:\t%s\n",buffer);
               if (n < 0) error("ERROR reading from socket");
               fprintf(fd,"%s\n",buffer);
               if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
                    printf("Exiting...\n");
                    done=1;
                    break;
               }
               exec_comm(newsockfd,nerror,buffer);
               printf("Here is the message: %s\n", buffer);
               n = write(newsockfd, "message received", 17);
               if (n < 0) error("ERROR writing to socket");
          }

     fclose(fd);
     close(newsockfd);
     close(sockfd);
     return 0;
}

Клиент:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg){
     perror(msg);
     exit(0);
}

int main(int argc, char *argv[]){
     int sockfd, portno, n;
     struct sockaddr_in serv_addr;
     struct hostent *server;
     char buffer[256];
     if (argc < 3){
          fprintf(stderr, "usage %s hostname port\n", argv[0]);
          exit(0);
     }
     portno = atoi(argv[2]);
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0)
     error("ERROR opening socket");
     server = gethostbyname(argv[1]);
     if (server == NULL){
          fprintf(stderr, "ERROR, no such host\n");
          exit(0);
     }
     bzero((char *) &serv_addr, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     bcopy((char *)server->h_addr,
     (char *)&serv_addr.sin_addr.s_addr,server->h_length);
     serv_addr.sin_port = htons(portno);
     if (connect(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
     error("ERROR connecting");
     n = write(sockfd, stdin, sizeof(int));
     if (n < 0)
     error("ERROR writing to socket");
     do{
          printf("Please enter the message: ");

          bzero(buffer, 256);
          fgets(buffer, 255, stdin);
          if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
               printf("Exiting...\n");
               n = write(sockfd, buffer, strlen(buffer));
               if (n < 0)
               error("ERROR writing to socket");
               close(sockfd);
               break;
          }
          n = write(sockfd, buffer, strlen(buffer));
          if (n < 0)
          error("ERROR writing to socket");
          bzero(buffer, 256);
          n = read(sockfd, buffer, 255);
          if (n < 0)
          error("ERROR reading from socket");
          printf("%s\n", buffer);
     }while(1);

     return 0;
}

1 Ответ

0 голосов
/ 26 января 2020
n = write(sockfd, buffer, strlen(buffer));

Это ваша проблема прямо здесь. Звонки на номер write не приводят к отдельным различимым сообщениям, по одному сообщению на вызов. Они приводят к единому однородному потоку (это «поток» в SOCK_STREAM) байтов без разделителей.

У вас есть новые строки, которые разделяют команды, что хорошо и все, но read понятия не имеет о новых строках Он просто будет ждать, пока буфер не заполнится, или не пройдет достаточно времени, или что-то еще. У вас есть нет контроль над ним.

У вас есть два способа исправить это:

  1. Прочитать символ за символом (передать длину 1) и остановиться, как только вы увидите новую строку. Соберите символы в буфере, затем выполните его.
  2. Отправьте длину каждого сообщения перед самим сообщением в записи фиксированной длины, чтобы сервер мог безопасно прочитать длину, а затем использовать ее для чтения. само сообщение.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...