我试图在服务器上运行shell命令,并希望将它们打印到客户端shell中。。
这意味着当我在客户机shell中键入一个命令时,该命令应该转到服务器并在服务器内部执行,然后将输出返回给客户机
但iam现在面临的唯一问题是,当我在客户机程序中运行“Date,hostname etc”等命令时,它会显示预期的输出(客户机->服务器->客户机)。但当我运行“ls”时,它只显示文件夹中的第一个文件。。
举个例子,如果我把五个文件放在一个文件夹中,它只显示文件夹中第一个文件的名称
客户端程序

#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

#define PORT 1300
#define HOST "127.0.0.1"
#define MAXLINE 1024

main() {
  register int s,len;
  struct sockaddr_in pin;
  struct hostent *hp;
  char buff[MAXLINE + 1];

   if ((hp=gethostbyname(HOST)) == 0) {
      perror("gethostbyname");
      exit(1);
    }

   bzero(&pin, sizeof(pin));
   pin.sin_family = AF_INET;
   pin.sin_addr.s_addr= ((struct in_addr *) (hp->h_addr)) -> s_addr;
   pin.sin_port=htons(PORT);

   if ((s=socket(AF_INET,SOCK_STREAM,0)) < 0) {
      perror("client:socket");
      exit(1);
   }

   if (connect(s,(struct sockaddr *) &pin,sizeof(pin)) < 0) {
      perror("client:connect");
      exit(1);
   }
   char out[20];
   strcpy(out,"exit");
   while(1){
       bzero(buff,MAXLINE+1);
       printf("Message> ");
       scanf("%s",buff);

    if(strcmp(out,buff) == 0){
        exit(1);
    }
       send(s,buff,strlen(buff)+1, 0);

       bzero(buff,MAXLINE+1);
       read(s,buff,MAXLINE);
       printf("Received>");
       puts(buff);
  }
  close(s);
}

这是我的服务器程序
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <time.h>
#include<string.h>

#define PORT 1300
#define MAXLINE 4096
#define COMMAND_LEN 20
#define DATA_SIZE 1512


main() {

register int s,ns;
int len;
struct sockaddr_in sin,pin;
char buff[MAXLINE + 1];
time_t  ticks;
struct tm * timeinfo;
FILE *pf;
char command[COMMAND_LEN];
char data[DATA_SIZE];

   bzero(&sin, sizeof(sin));
   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr= htonl(INADDR_ANY);
   sin.sin_port=htons(PORT);



   if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      perror("server: socket");
      exit(1);
   }

   if (bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0) {
      perror("server:bind");
      exit(1);
   }

   if (listen(s,5) <0) {
       perror("server: listen");
       exit(1);
    }

    for(; ;) {
        if ((ns = accept(s, (struct sockaddr *)&pin, &len)) < 0) {
           perror("server: accept");
           exit(1);
         }
       while(1){

       bzero(buff,MAXLINE+1);
       read(ns,buff,MAXLINE);
       pf=popen(buff,"r");
        if(!pf)
        {
            fprintf(stderr,"could not open for output. \n");
        }

        fgets(data,DATA_SIZE,pf);
        send(ns,data,strlen(data)+1,0);

        //puts(buff);
       //send(ns,buff,strlen(buff)+1,0);
       }
    }

    close(ns);
    close(s);
}

我试着改变缓冲区大小,但问题仍然存在。。。
这就是我在服务器端更改代码段的方法
bzero(buff,MAXLINE+1);
       read(ns,buff,MAXLINE);
       pf=popen(buff,"r");
        if(!pf)
        {
            fprintf(stderr,"could not open for output. \n");
        }
        while(NULL!=fgets(data,DATA_SIZE,pf)){
        send(ns,data,strlen(data)+1,0);
        }
        if(pclose(pf)!=0)
            fprintf(stderr,"Error:failed to close command stream \n");
        * data ='\0';
        //puts(buff);
       send(ns,data,1,0);

在客户端我把它改成
下面的代码就在main方法下面
智力密度=0,单位为磅;
字符*p;
此部分在客户程序中,如图所示
 while(! idone)
            {
            ibytes = read (s,buff,MAXLINE);
            for (p=buff;(ibytes--);p++)
            {
                if(! *p)
                {idone=1;break;}
                putc(*p,stdout);
            }

现在,当我运行“ls”命令时,它仍然只显示一个文件,现在在执行上述更改之后,它甚至不运行“date,hostname…”这样的命令

最佳答案

在客户端,

   read(s,buff,MAXLINE);

无法保证获取服务器发送的所有数据。实际上,它可以在返回1字节后返回。您必须在服务器端为邮件添加一个标题,然后确保在接收到整个邮件之前一直read
更不用说在服务器端执行一个fgets()意味着您只从popen()中读取一行并发送它。你需要一直做fgets()直到结束。
更不用说你从来没有用pclose关闭pf。
所以,现在在评论中,你试着解决第2点和第3点。pclose的位置不对,但除此之外,您还有第1点的问题。在“结果”完成之前,你不知道要在客户端上读多少。所以我们必须制定一个协议。
因此,现在注释中的代码将用一个换行符和一个ls\0的每一行发送回来。让我们改变一下。只发送可打印文本,直到完成所有操作,然后发送\0
while ( NULL != fgets(data, DATA_SIZE,pf)) {
  send( ns, data, strlen( data), 0) ;  // not strlen() +1
}
if ( pclose( pf) != 0 ) { perror("Error") ; }  // outside the while loop

* data= '\0' ;
send( ns, data, 1, 0 ) ;  // send a null

现在客户机可以整天进行read()操作,直到得到\0为止,它知道有更多的数据。当然要小心一些问题。在打印每条消息之前,必须将\0添加到客户端缓冲区。当您在消息中查找\0时,必须确保没有发现它超过了发送字节数的末尾。
这里的关键是,您必须查看read()的返回值,看看实际得到的字节数。
int idone= 0, ibytes ;
char * p;

while ( ! idone )
{
  ibytes= read(s,buff,MAXLINE);
  for ( p= buff ; ( ibytes -- ) ; p ++ )
  {
    if ( ! * p ) { idone= 1 ;  break ; }
    putchar( * p) ;
  }
}

关于c - 客户端和服务器通信,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20437327/

10-16 20:21