首页 > 用户发贴区 > 编程问题提问区 > socket通讯程序问题
2007
07-12

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>


#define BACKLOG 10
#define cmd_length 20


//=============服务器端命令集=============
int cmd_gettime(int fd)
{
    system(“date”);
    //如何将服务端的命令输出,向客户端输出


    return 1; 
   
}


int cmd_netstart(int fd)
{
    system(“/etc/netstart “);
    send(fd, “system service has reloaded !\n”, 26, 0);
    return 1; 
   
}


int cmd_help(int fd)
{  
    int i;
    char cmd[4][50];
   
    strcpy(cmd[0],”getdate    ->取服务器时间”);
    strcpy(cmd[1],”netstart    ->重启系统服务”);
    strcpy(cmd[2],”help         ->系统帮助”    );
    strcpy(cmd[3],”discon      ->退出连接”    );
   
    for (i=0; i<4; i++)
        send(fd, cmd[i], 50, 0);
    return 1;   
   
}


int cmd_disconnect(int fd)
{
    close(fd);
    waitpid(-1, NULL, WNOHANG);
    exit(0);
}
/*=============服务程序=============
    根据客户端传送的指令,执行相应程序*/
int run_service(int fd)
{
    char cmd[cmd_length+1]={0};
    int i;
   
    for (;;)
    {
        if (recv(fd, cmd, cmd_length, 0)== -1)
        {
            cmd[0]=’\0′;
            continue;
        }   
        else
        {
            i= 0;
            while (cmd[i]!=’\0′)
            {
                cmd[i]=toupper(cmd[i]);
                i++;
            }
            switch(cmd)
            {
                case ‘GETTIME’ : cmd_gettime(fd);  
                case ‘NETSTART’: cmd_netstart(fd);
                case ‘HELP’    : cmd_help(fd);
                case ‘DISCONN’ : cmd_disconnect(fd);
            }
            if (send(fd, cmd, cmd_length, 0)== -1)
                perror(“send error! \n”);
        }
    }
}


int main(int argc, char *argv[])
{
      int SERVPORT;
      int sockfd, client_fd;
      int sin_size;
      struct sockaddr_in my_addr;
      struct sockaddr_in remote_addr;


      if (argc >1)
      {
           if ((SERVPORT=atoi(argv[1]))<0) SERVPORT= 3333;
      }
      else
           SERVPORT= 3333;


      if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
      {
           perror(“socket create error ! \n”);
           exit(1);
      }
     
      my_addr.sin_family=AF_INET;
      my_addr.sin_port=htons(SERVPORT);
      my_addr.sin_addr.s_addr = INADDR_ANY;
      bzero(&(my_addr.sin_zero),8);


      if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
      {
          perror(“bind error ! \n”);
          exit(1);
      }
      if (listen(sockfd, BACKLOG) == -1)
      {
          perror(“listen error ! \n”);
          exit(1);
      }
     
      while(1)
      {
          sin_size = sizeof(struct sockaddr_in);
          if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size))==-1)
          {
               perror(“accept error! \n”);
               continue;
          }
          
          printf(“received a connection from %s \n”, inet_ntoa(remote_addr.sin_addr));
          if (!fork())
          {
               run_service(client_fd);
          }
          close(client_fd);
      }   
}


socket通讯程序问题》有 6 条评论

  1. xiaoz 说:

                switch(cmd)
                {
                    case ‘GETTIME’ : cmd_gettime(fd);  
                    case ‘NETSTART’: cmd_netstart(fd);
                    case ‘HELP’    : cmd_help(fd);
                    case ‘DISCONN’ : cmd_disconnect(fd);
                }

    这段有问题。

    少了break,并且switch里面好像只能有整数类型和字符类型。

  2. lensing01 说:

    再请教:如何将服务端的命令输出,向客户端输出

  3. xiaoz 说:

    /*=============服务程序=============
        根据客户端传送的指令,执行相应程序*/
    int run_service(int fd)
    {
        char cmd[cmd_length+1]={0};
        int i;
        int opt=-1;   

        for (;;)
        {
            if (recv(fd, cmd, cmd_length, 0)== -1)
            {
                cmd[0]=’\0′;
                continue;
            }   
            else
            {
                i= 0;
                while (cmd[i]!=’\0′)
                {
                    cmd[i]=toupper(cmd[i]);
                    i++;
                }
            if(strcmp(cmd,”GETTIME”) == 0)
                opt=0;
            else if(strcmp(cmd,”NETSTART”) == 0)
                opt=1;
            else if(strcmp(cmd,”HELP”) == 0)
                opt=2;
            else if(strcmp(cmd,”DISCONN”) == 0)
                opt=3;
                switch(opt)
                {
                    case 0 : cmd_gettime(fd);break;  
                    case 1 : cmd_netstart(fd);break;
                    case 2 : cmd_help(fd);break;
                    case 3 : cmd_disconnect(fd);break;
                }
                if (send(fd, cmd, cmd_length, 0)== -1)
                    perror(“send error! \n”);
            }
        }
    }

  4. xstar 说:

    使用管道来获取命令行输出!
    另外,Socket编程时最要使用select来读写数据。
    下面修改后的代码,父进程退出部分没有写!还有一些信号处理也没写!另外发送数据的时候应该检测sockfd是否可写,这个也需要用select来实现。
    [code]
    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>

    #include <errno.h>

    #define BACKLOG  10
    #define CMDLEN  256
    #define BUFSIZE  (16*1024)
    #define SVRPORT  3333
    #define CMDSIZE 4

    int  running = 1;
    int  errno;

    typedef struct tagCMD {
     char cmd[ CMDLEN ];
     int (*execmd)( int fd );
    } CMD;

    int cmd_gettime( int fd );
    int cmd_netstart( int fd );
    int cmd_help( int fd );
    int cmd_exit( int fd );

    //=============服务器端命令集=============

    CMD SYSCMD[ CMDSIZE ] = {
     { "gettime",  cmd_gettime  },
     { "netstart", cmd_netstart },
     { "help",     cmd_help     },
     { "exit",     cmd_exit     }
    };

    void execcmd( char *cmd, int fd )
    {
     int cnt;

     for( cnt = 0; cnt < CMDSIZE; cnt++ ) {
      if( strcmp( cmd, SYSCMD[ cnt ].cmd ) == 0 ) {
       SYSCMD[ cnt ].execmd( fd );
       break;
      }
     }
    }

    int cmd_gettime( int fd )
    {
      FILE *fp;
      char line[ BUFSIZE ];
      char *pch;

      fp = popen( "date", "r" );

      if( (FILE *)0 == fp ) return -1;

      pch = fgets( line, sizeof( line ), fp );

     if( pch != (char *)0 ) {
      printf( "%s[%d]: %s\n", __FILE__, __LINE__, line );
      send( fd, line, strlen( line ), 0 );
     } else {
      printf( "%s[%d]: Error\n", __FILE__, __LINE__ );
      send( fd, "error", strlen( "error" ), 0 );
     }

      pclose( fp );

      return 0;
    }

    int cmd_netstart( int fd )
    {
      system( "/etc/netstart" );

      send( fd, "system service has reloaded!\n", strlen( "system service has reloaded!\n" ), 0 );

      return 0;
    }

    int cmd_help( int fd )

      int i;
      char cmd[4][50];

      strcpy( cmd[0], "gettime  ->取服务器时间" );
      strcpy( cmd[1], "netstart ->重启系统服务" );
      strcpy( cmd[2], "help     ->系统帮助"    );
      strcpy( cmd[3], "exit     ->退出连接"    );
     
      for( i=0; i<4; i++ ) {
       send( fd, cmd[i], strlen( cmd[ i ] ), 0 );
      }

      return 0; 
     
    }

    int cmd_exit( int fd )
    {
     running = 0;

     send( fd, "exit\n", strlen( "exit\n" ), 0 );

     return 0;
    }
    /*=============服务程序=============*/
    int run_service( int fd )
    {
     char cmd[ BUFSIZE ]={0};
     int ret;
     fd_set fd_recv;
     int recvsize               = 0;
     struct timeval tm          = { 0 };

     tm.tv_sec                  = 3600 * 24;

     while( running ) {
      FD_ZERO( &fd_recv );
      FD_SET( fd, &fd_recv );

      ret = select( fd + 1, &fd_recv, NULL, NULL, &tm );

      if ( ( ret == -1 ) && ( errno == EINTR ) ) {  /* interrupted by signal */
       continue;
      } else if ( ret == -1 ) {                     /* real select error */
       break;
      } else if ( ret == 0 ) {                      /* timeout */
       continue;
      }

      if( FD_ISSET( fd, &fd_recv ) ) {
       if( ( recvsize = recv( fd, cmd, BUFSIZE, 0 ) ) <= 0 ){
        break;
       }
       execcmd( cmd, fd );
      }
     }
    }

    int main( int argc, char *argv[] )
    {
     int svr_port;
     int listen_fd;
     int sock_fd;
     int addrlen;
     int ret;
     struct sockaddr_in listen_addr;
     struct sockaddr_in remote_addr;

     svr_port = SVRPORT;
     if ( (argc != 2) && (argc != 1) ) {
      perror( "error\n" );
      return 0;
     }

     if ( argc = 2 ) {
      if( atoi( argv[ 1 ] ) > 0 ) svr_port = atoi( argv[ 1 ] );
     }

     if ( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1) {
      perror("Socket Create Error!\n");

      exit( -1 );
     }

     listen_addr.sin_family      = AF_INET;
     listen_addr.sin_port        = htons( svr_port );
     listen_addr.sin_addr.s_addr = htonl( INADDR_ANY );
     bzero( &(listen_addr.sin_zero), 8 );

     if ( bind( listen_fd, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr) ) == -1 ) {
      perror("bind error ! \n");
      close( listen_fd );

      exit( -1 );
     }

     if ( listen( listen_fd, BACKLOG ) == -1 ) {
      perror("listen error ! \n");
      close( listen_fd );

      exit( -1 );
     }

     while( running ) {
      addrlen = sizeof( struct sockaddr_in );
      if ( ( sock_fd = accept( listen_fd, (struct sockaddr*)&remote_addr, &addrlen ) ) == -1 ) {
       perror("accept error! \n");
       continue;
      }

      printf("Client: %s\n", inet_ntoa(remote_addr.sin_addr));

      ret = fork();

      if ( ret == -1 ) {
       perror( "fork() error\n" );
       close( listen_fd );
       close( sock_fd );

       exit( -1 );
      } else if( ret == 0 ) {
       close( listen_fd );
       run_service( sock_fd );
       close( sock_fd );

       exit( 0 );
      }
      close( sock_fd );
      waitpid( ret, NULL, 0);
     }

     close( listen_fd );

     return 0;
    }
    [/code]

  5. lensing01 说:

    感谢大虾的修改,程序中有几处还望指教:
    1、typedef struct tagCMD {
             char cmd[ CMDLEN ];
             int (*execmd)( int fd );
       } CMD;
       int (*execmd)(int fd),中*execmd是什么,整句如何理解

    2、printf( “%s[%d]: %s\n”, __FILE__, __LINE__, line );
       __FILE__, __LINE__意义是什么,man中没有找到解释

    3、fd_set fd_recv;
       fd_set 类型在man没有解释

  6. xstar 说:

    1、int (*execmd)(int fd);
        execmd是个函数指针,指向的函数的返回类型是int型的,并带一个int型参数。
        通过赋值可以调用任何同类型的函数。比如cmd_exit等。
    2、__FILE__和__LINE__是编译器定义的宏,表示当前文件名和当前行,这个在调试代码的时候可以方便定位代码行。
    3、fd_set在不同系统里的实现似乎不一样的,有些将其实现为一个数组,有些将其按位实现。
    你可以查看一下FD_ISSET等宏定义。这些在man中是有的。
    select函数检查的是文件描述符是否可读写,可读写则置相应的位。

留下一个回复