• 模拟一个简单的基于tcp的远程关机程序(转)


    最近在学习unix网络编程,现在正在学习tcp的通信。其实,只要建立起了tcp通信,操作远端的计算机就不是什么问题了。正向telnet一样,也是基于tcp/IP协议的。所以这个实验,也算是对telnet功能的一种简单的模拟。

    但是,值得注意的问题是关机涉及到系统权限,所以要给运行在Server端的程序以足够的权限,这样才可以在接收到Client端的关机请求时,执行关机。

    将会模拟如下执行过程:

    1. 执行 mytelnet 跟上参数telnet服务器 IP地址 127.0.0.1

    2. 输入login 向服务器请求登录,随之服务器会要求输入密码

    3. 输入一个错误的登录密码 123 

    4. 服务器验证不通过,所以返回Fail to login ,please check your password

    5. 再次输入密码,这次输入正确的密码123456

    6. 服务器验证通过,此时客户端可以执行基于telnet的远程操控

    7. 输入操控命令,例如关机命令shutdown 

    8. 服务器将会执行shutdown 操作。

    在编译时使用如下的命令:

    Server:

    sudo gcc server.c -o server //足够的权限

    sudo chmod u+s server 

    ./server

    Client:

    gcc client.c -o mytelnet

    ./mytelnet 10.3.1.210

    Client端:

    复制代码
    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #define MAXLINE 4096
    void clientWork(FILE* fp , int sockfd)
    {
      char sendline[MAXLINE],receiveline[MAXLINE];
      int n;
      while(fgets(sendline,MAXLINE,fp)!=NULL)
      {
        write(sockfd,sendline,strlen(sendline));
        n=read(sockfd,receiveline,MAXLINE);
        receiveline[n]='';
        fputs(receiveline,stdout);
        if(strcmp(receiveline,"bye ")==0) break;
      }
    }
    int main( int argc , char * * argv )
    {
      int sockfd , n ;
      char recvline[ MAXLINE + 1];
      struct sockaddr_in servaddr;
      if( ( sockfd = socket( AF_INET , SOCK_STREAM , 0 ) ) < 0 ) {
        printf( "socket error " );
        exit( 1 );
      }
      memset( &servaddr , 0 , sizeof( servaddr ) );
      servaddr.sin_family = AF_INET;
      servaddr.sin_port = htons( 2000 );//指定Server端的端口号
      char * serverAddress=argv[1];
      //判断指定的ip地址是否有错误
      if( inet_pton( AF_INET ,serverAddress , &servaddr.sin_addr ) <= 0 ) {
        printf( "inet_pton error for %s " , serverAddress );
        exit( 1 );
      }
      if( connect( sockfd , (struct sockaddr *)&servaddr , sizeof( servaddr ) ) < 0 ) {
        printf( "connect error " );
        exit( 1 );
      }
      //从Terminal中读取用户输入的指令
      clientWork(stdin,sockfd);
      close(sockfd);
      return 0;
    }
    复制代码

    Server端:

    复制代码
    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #define MAXSIZE 1024
    #define LOGIN 1    //登录Server
    #define BYE 2    //离开Server
    #define PASS 3    //合法登录
    #define DENY 4 //非法登录
    #define SHUTDOWN 5 //执行关机
    #define ERROR -1 //非法信息
    //记录状态信息
    static int STATE=0;
    int getClientChoice(char * clientmsg)
    {
        if(strcmp(clientmsg,"login ")==0) return LOGIN;
        if(STATE>0)
        {
            if(strcmp(clientmsg,"bye ")==0) return BYE;
        }
        if(STATE==LOGIN)
        {
            //Default password is 123456
            if(strcmp(clientmsg,"123456 ")==0) return PASS;
            else return DENY;
        }
        if(STATE==PASS)
        {
            if(strcmp(clientmsg,"shutdown ")==0) return SHUTDOWN;
            else ERROR;    
        }
        return ERROR;
    };
    //发送消息
    void sendMsg(int sockfd,char * buffer,char * msg)
    {
        char buffer2[MAXSIZE];
        snprintf(buffer2,sizeof(buffer2),"%s",msg);
        write(sockfd,buffer2,sizeof(buffer2));
    }
    //定义关机函数
    void myshutdown()
    {
        //系统在一分钟后关机
        system("shutdown -t 1");
    }
    int main(int argc , char * * argv )
    {
        char buffer[MAXSIZE];
        int listenfd=socket(AF_INET,SOCK_STREAM,0);//定义socket,指向ipv4地址的字节流套接口
        
        struct sockaddr_in serverAddr;
        memset(&serverAddr,0,sizeof(serverAddr));//sockAddr_in 进行初始化
        serverAddr.sin_family=AF_INET;
        serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
        serverAddr.sin_port=htons(2000);
        if(bind(listenfd,(struct sockaddr *) &serverAddr,sizeof(serverAddr))==-1)
        {
            printf("There is an error during binding ");
            return -1;
        }
        else
        {
            printf("Bind successfully!!! ");
        }
        //对listenfd进行监听,从最初建立时的主动套接口(用于进行connect的套接口)转化为被动套接口(接受连接)
        listen(listenfd,100);//第二个参数为套接口排队的最大连接个数
        int connectfd;
        socklen_t addrlen;
        struct sockaddr_in connectAddr;
        memset(&connectAddr,0,sizeof(connectAddr));
        printf("Be ready to accept a connection! ");
        while(1)
        {
            connectfd=accept(listenfd,(struct sockAddr * )&connectAddr,&addrlen);//接受client端一个请求的socket
            char receivebuffer[MAXSIZE];
            int revbuflen;
            while(1)
            {
                revbuflen = read(connectfd,receivebuffer,MAXSIZE);
                receivebuffer[revbuflen]='';
                //printf("%s",receivebuffer);
                int clientChoice=getClientChoice(receivebuffer);
            //    模拟操作过程
                if(clientChoice==LOGIN)
                {
                    STATE=LOGIN;
                    sendMsg(connectfd,buffer,"Please input your password : ");
                }
                else if(clientChoice==PASS&&STATE==LOGIN)
                {
                    STATE=PASS;
                    sendMsg(connectfd,buffer,"Welcome to my Telnet Server... ");
                }
                else if(clientChoice==SHUTDOWN&&STATE==PASS)
                {
                    myshutdown();
                    sendMsg(connectfd,buffer,"Remote computer is going to shutdown... ");
                }
                else if (clientChoice==BYE)
                {
                    sendMsg(connectfd,buffer,"bye ");
                    break;
                }
                else if(clientChoice==DENY)
                {
                    sendMsg(connectfd,buffer,"Fail to login ,please check your password ");
                }
                else if(clientChoice==ERROR)
                {
                    sendMsg(connectfd,buffer,"wrong,Check your input... ");
                }
            }
            close(connectfd);
        }
        close(listenfd); //虽然因为上面有while(true),这行永远都执行不了,但是时刻注意关闭socket连接应该是个好习惯。
        return 0;
    }
    复制代码
  • 相关阅读:
    webpack介绍 安装 常用命令
    npm常用命令
    jQuery 实现点击页面其他地方隐藏菜单
    :after伪类+content内容生成经典应用举例
    几分钟前 几小时前 几天前... 7个阶段
    JS — 获取4个不重复的随机验证码
    JS — 数组去重(4种方法)
    Spring IOC原理简析
    浅谈Linux下的五种I/O模型
    大型分布式网站架构技术总结
  • 原文地址:https://www.cnblogs.com/kwseeker-bolgs/p/4357215.html
Copyright © 2020-2023  润新知