• 网络版shell之网络编程练习篇--telnet服务端


    网络版shell之网络编程练习篇--telnet服务端

      以前写过一个shell命令解释器,对与shell命令解释器的执行流程有了清晰的认识,这段时间学习网络编程,至于网络编程的细节以及知识点,已经在上 一遍博客中,转载了从网上摘的文章,基本概括了网络编程的主要api,而对于程序员,更重要的是解决实际问题的能力,所以练习是非常重要的,现在,我们在 一起shell命令解释器的基础上,写一个基于socket网络编程的网络版shell命令解释器,也可以称之为telnet服务端。 
    telnet服务端代码:
     

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include "my_type.h" //外部头文件 申明了一个函数体 exec_cmd()
    int main(void)
    {
        char buf[2048];//为了保持程序简短,便于阅读,省去了错误判断。
        int socket_fd;
        struct sockaddr_in netaddr;
        unsigned short int port=8000;
        socket_fd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        bzero(buf,2048);
        bzero(&netaddr,sizeof(struct sockaddr_in));//为了保持程序简短,便于阅读,省去了错误判断。
        netaddr.sin_family=AF_INET;
        netaddr.sin_port=htons(port);
        netaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        bind(socket_fd,(struct sockaddr *)&netaddr,sizeof(struct sockaddr));//在实际代码中,已加入了错误判断
        listen(socket_fd,3);
        while(1)
        {
            int connfd;
            int i=0;
            char ch=0;
            char os_chose[4];
            int len=sizeof(struct sockaddr);
            struct sockaddr_in cliaddr;
            char buf_in[2048];
            bzero(os_chose,4);
            bzero(&cliaddr,sizeof(struct sockaddr_in));
            printf("port = %d ",ntohs(netaddr.sin_port));
    start:
            connfd=accept(socket_fd,(struct sockaddr *)&cliaddr,&len);//监听端口 等待客户端连接
            printf(" accept is over, remote ip = ");        while(1)        {                strcpy(buf," chose your system : ");            write(connfd,buf,30);            strcpy(buf," [1] windons ");            write(connfd,buf,60);            strcpy(buf," [2] linux ");            write(connfd,buf,60);            read(connfd,os_chose,4);

    /*window 与linux 有一些小区别,linux中,换行会自动回车,

    而window只会换行而不会自动回车,所以如果对于从linux中获取的命令输出,

    不做处理的话,在window终端下,会呈现梯形显示 */
                if( strpbrk(os_chose,"1")!=NULL )
                {
                    ch='1';
                    printf("window ");
                    break;
                }    
                else if( strpbrk(os_chose,"2")!=NULL )
                {
                    ch='2';
                    printf(" linux ");
                    break;
                }    
                // window的telnet程序,按每个字符发送,而首字符往往不是输入的字符,可能是,没有去深究,

    直接捕获输入的前4个字符,

    然后检查是否1 或者2 来判断登陆者选择的系统类型。
            }
            strcpy(buf," telnet_shell>>");
            write(connfd,buf,20);   //输入提示符
            bzero(&buf,2048);
            while(1)
            {    
                char tmp_ch=0;
                if(connfd>=0)
                {
                    if(ch=='2')//linux的telnet客户端,以回车符作为命令的结束,与window不同,

    要想去别对待,这样服务端获取的就是一个字符串
                    {    
                        bzero(&buf,2048);
                        read(connfd,buf,2048);
                        if( exec_cmd(buf,connfd)==10 )//my_type.h  申明的函数,主要解释输入的字符串命令,执行命令后,将标准输出和错误输出都重定向到网络中。
                            goto start;
                        bzero(&buf,2048);
                        strcpy(buf," telnet_shell>>");
                        write(connfd,buf,20);
                        bzero(&buf,2048);
                    }
                    if(ch=='1')
                    { // window的telnet客户端,按单个字符发送命令,所以要对输入的单个字符重新组合。
                        read(connfd,&tmp_ch,1);
                        if(tmp_ch==''&&i==0)
                        {}    
                        else if(tmp_ch!=' ')
                        buf_in[i++]=tmp_ch;
                        else if(tmp_ch==' '&&i!=0)
                        {    
                            printf("%s ",buf_in);
                            buf_in[i]=' ';
                            buf_in[i+1]=' ';
                            buf_in[i+2]=' ';
                         if( exec_cmd(buf_in,connfd)==10 )
                             goto start;
                            bzero(&buf_in,2048);
                            strcpy(buf_in," telnet_shell>>");
                            write(connfd,buf_in,20);
                            bzero(&buf_in,2048);
                            i=0;                        
                        }
                    }    
                }    
            }
        }    
    return 0;    
    }

    my_type.h 与exec_cmd()函数

    #include "my_type.h"
    int exec_cmd(char *p,int fd)
    {
        char *argv[5];
        char cmd_data[5][10];
        char tmp_p[200];
        char *token;
        char *p_tmp;
        pid_t pid;
        int id=0,i=0,j=0;
        int pipe_fd[2];
        char buf_cmd[2048];
        memset(buf_cmd,'',2048);
        if( (pipe(pipe_fd))==-1 )
        {
            perror("pipe init error");
            return -1;
        }    
        memset(tmp_p,'',200);
        memset(cmd_data,'',10*5);
        memset(argv,'',5);
        strcpy(tmp_p,p);
        p_tmp=tmp_p;
        while( (*p_tmp)!=' ' )
        {
            if( ((*p_tmp)==' ') )
            {
                *p_tmp=' ';
        *(p_tmp+1)=' ';
                *(p_tmp+2)=' ';
                break;
            }    
            ++p_tmp;
        }    //以空格符为字符串分割符有一个缺点,就是会把字符串的末尾符号 也认为是字符串,而在exec时,无法正确执行命令,所以不管字符串末尾是否有空格,都统一在 前加入空格符。
        token=strtok(tmp_p," ");
        while(token!=NULL)
        {
            if( (*token!=' ')&&(*token!=' ')&&(*token!='') )
            strcpy(cmd_data[id++],token);
            token=strtok(NULL," ");    }    cmd_data[id-1][strlen(cmd_data[id-1])-1]='';    for(j=0;j<id-1;j++)    {         argv[j]=cmd_data[j];            }    argv[j]=(char *)NULL;    if( strcmp(argv[0],"cd")==0)    {        puts("cmd is cd ");        chdir(argv[1]);        return 0 ;    }    else if( strcmp(argv[0],"exit")==0 )    {        puts("cmd is exit ");        puts("bye bye ! ");        close(fd);        return 10;    }    if( (pid=fork())==-1)    {        perror("fork error");        exit(1);    }    if( pid==0 )    {        close(pipe_fd[0]);//通过无名管道对stdou、stderr输出重定向        dup2(pipe_fd[1],fileno(stderr));        dup2(pipe_fd[1],fileno(stdout));        execvp(argv[0],argv);        close(pipe_fd[1]);        exit(0);    }    else    {        char *buf_p=0,buf_ch=0;        int buf_i=0;        char tmp[2048];        close(pipe_fd[1]);        memset(buf_cmd,'',2048);        memset(tmp,'',2048);//读取子进程写入到管道中的信息        read(pipe_fd[0],buf_cmd,2048);        buf_p=buf_cmd;        puts(buf_cmd);//linux和window都统一起来,虽然linux对于换行符的处理是换行和自动回车,这里为了方便起见,都统一加入回车符。这样就可以在window下完美显示了。        while( buf_cmd[buf_i]!='')        {                tmp[buf_i]=buf_cmd[buf_i++];            if( buf_cmd[buf_i]==' ' )            {                tmp[buf_i-1]=' ';                tmp[buf_i++]=' ';            }        }            write(fd,tmp,2048);         waitpid(pid,NULL,NULL);        return 0;    }    }

    my_type.h文件:

    #ifndef __my_type__
    #define __my_type__
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    extern int exec_cmd(char *p,int fd);
    #endif

  • 相关阅读:
    df
    浅谈C#垃圾回收
    eclipse+ADT 进行android应用签名详解
    Android Monkey工具参数意义
    Android Monkey(转载)
    清理Win7右键菜单里“发送到”选项
    Android中LOG机制详解(上)  
    关于微博内容中的短地址ShortURL
    Android中LOG机制详解(下)
    黑盒测试用例设计方法实践(判定表驱动法)
  • 原文地址:https://www.cnblogs.com/timssd/p/4612140.html
Copyright © 2020-2023  润新知