客户端和服务器通信

时间:2013-12-07 03:48:04

标签: c shell communication

我试图在服务器上运行shell命令,并希望它们在客户端shell中打印..

这意味着当我在客户端shell中键入命令时,该命令应该转到服务器并在服务器内执行并将输出返回给客户端

但是现在面临的唯一问题是我运行的命令如"日期,主机名等"在客户端程序中,它显示预期的输出(客户端 - >服务器 - >客户端)。但是当我跑步的时候" 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);

并且在客户端我将其更改为 下面的代码就在主要方法

之下

int idone = 0,ibytes;             char * p;

此部分位于客户端程序中,如图所示

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

现在当我运行&#34; ls&#34;命令它仍然只显示一个文件,现在完成上述更改后,它甚至不会运行像&#34; date,hostname ...&#34;

这样的命令

1 个答案:

答案 0 :(得分:3)

在客户端,

   read(s,buff,MAXLINE);

无法保证获取服务器发送的所有数据。实际上它可以在返回1个字节后返回。您将不得不在服务器端为消息添加标题,然后确保在收到整个消息之前继续read

更不用说在服务器端执行一个fgets()意味着您只读取popen()中的一行并发送它。你需要继续做fgets()直到EOF。

更不用说你永远不会用pclose关闭pf。

所以,现在在评论中你试图解决第2点和第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) ;
  }
}