最近在学习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]='\0';
    fputs(receiveline,stdout);
    if(strcmp(receiveline,"bye\n")==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\n" );
    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\n" , serverAddress );
    exit( 1 );
  }
  if( connect( sockfd , (struct sockaddr *)&servaddr , sizeof( servaddr ) ) < 0 ) {
    printf( "connect error\n" );
    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\n")==0) return LOGIN;
    if(STATE>0)
    {
        if(strcmp(clientmsg,"bye\n")==0) return BYE;
    }
    if(STATE==LOGIN)
    {
        //Default password is 123456
        if(strcmp(clientmsg,"123456\n")==0) return PASS;
        else return DENY;
    }
    if(STATE==PASS)
    {
        if(strcmp(clientmsg,"shutdown\n")==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\n");
        return -1;
    }
    else
    {
        printf("Bind successfully!!!\n");
    }
    //对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!\n");
    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]='\0';
            //printf("%s",receivebuffer);
            int clientChoice=getClientChoice(receivebuffer);
        //    模拟操作过程
            if(clientChoice==LOGIN)
            {
                STATE=LOGIN;
                sendMsg(connectfd,buffer,"Please input your password :\n");
            }
            else if(clientChoice==PASS&&STATE==LOGIN)
            {
                STATE=PASS;
                sendMsg(connectfd,buffer,"Welcome to my Telnet Server...\n");
            }
            else if(clientChoice==SHUTDOWN&&STATE==PASS)
            {
                myshutdown();
                sendMsg(connectfd,buffer,"Remote computer is going to shutdown...\n");
            }
            else if (clientChoice==BYE)
            {
                sendMsg(connectfd,buffer,"bye\n");
                break;
            }
            else if(clientChoice==DENY)
            {
                sendMsg(connectfd,buffer,"Fail to login ,please check your password\n");
            }
            else if(clientChoice==ERROR)
            {
                sendMsg(connectfd,buffer,"wrong,Check your input...\n");
            }
        }
        close(connectfd);
    }
    close(listenfd); //虽然因为上面有while(true),这行永远都执行不了,但是时刻注意关闭socket连接应该是个好习惯。
    return 0;
}

模拟一个简单的基于tcp的远程关机程序(转)的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统

    本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...

  2. 通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解

    首先感谢张队@geffzhang公众号转发了上一篇文章,希望广大.neter多多推广dapr,让云原生更快更好的在.net这片土地上落地生根. 目录:一.通过Dapr实现一个简单的基于.net的微服务 ...

  3. 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流

    在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接 ...

  4. 通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪

    Dapr提供了一些开箱即用的分布式链路追踪解决方案,今天我们来讲一讲如何通过dapr的configuration来实现非侵入式链路追踪的 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系 ...

  5. 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

    并发编程概述   前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...

  6. 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr

    目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...

  7. 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务

    我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...

  8. 通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格

    多运行时是一个非常新的概念.在 2020 年,Bilgin Ibryam 提出了 Multi-Runtime(多运行时)的理念,对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华.那到 ...

  9. 通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署

    之前所有的演示都是在docker for windows上进行部署的,没有真正模拟生产环境,今天我们模拟真实环境在公有云上用linux操作如何实现istio+dapr+电商demo的部署. 目录:一. ...

随机推荐

  1. Xcache3.2.0不支持php7.0.11

    编译安装xcache3.2.0时在make这一步报错: AUTOCHECK missing : "arg_flags" "cache_size" AUTOCHE ...

  2. 爬虫系列(四) 用urllib实现英语翻译

    这篇文章我们将以 百度翻译 为例,分析网络请求的过程,然后使用 urllib 编写一个英语翻译的小模块 1.准备工作 首先使用 Chrome 浏览器打开 百度翻译,这里,我们选择 Chrome 浏览器 ...

  3. 2017年JavaScript框架---Top5

    前言 个人观点,供您参考 观点源自作者的使用经验和日常研究 排名基于框架的受欢迎度, 语法结构, 易用性等特性 希望大家能够基于此视频找到最适合自己的框架 下面介绍的都是严格的前端框架和库 前言 To ...

  4. 高效使用hive

    工作中常常使用hive.熟练使用hvie的配置參数能够更加高效的使用Hive Hive option: hive -f   script.hql : 从文件script.hql中的读取hql运行 hi ...

  5. 301 和 302 对 SEO 的影响

    网站优化中,经常会面临网站链接修改或改变的事情,其中一个解决办法就是使用网站跳转的方式,处理变化的链接,下面讲述301和302跳转对SEO的影响. 301(永久移动) 请求的网页已被永久移动到新位置. ...

  6. C 中 main 函数的參数

          看到不同的人写出的 C 或者 C++ 程序时,可能会出现不一样的 main 函数的定义,以下的几种定义方式都是对的: int main(void) int main(int argc) i ...

  7. DeepLearning to digit recognizer in kaggle

    DeepLearning to digit recongnizer in kaggle 近期在看deeplearning,于是就找了kaggle上字符识别进行练习.这里我主要用两种工具箱进行求解.并比 ...

  8. 【HDOJ 1009】 CRB and String

    [HDOJ 1009] CRB and String 每组两个串s t 仅仅由小写字母组成 问从s能不能变成t 改变的操作为选一个字符 在后面加上一个与所选字符不同的字符 这样的操作能够做无数次 问能 ...

  9. luogu1969 积木大赛

    题目大意 搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成n块高度为 0 的积木).接下来每次操作,可以选择一段连 ...

  10. POJ2689 Prime Distance 质数筛选

    题目大意 求区间[L, R]中距离最大和最小的两对相邻质数.R<2^31, R-L<1e6. 总体思路 本题数据很大.求sqrt(R)的所有质数,用这些质数乘以j, j+1, j+2... ...