网络版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 \n",ntohs(netaddr.sin_port));
start:
        connfd=accept(socket_fd,(struct sockaddr *)&cliaddr,&len);//监听端口 等待客户端连接
        printf(" accept is over, remote ip = \n ");        while(1)        {                strcpy(buf," chose your system : \r\n");            write(connfd,buf,30);            strcpy(buf,"\r [1] windons \n");            write(connfd,buf,60);            strcpy(buf,"\r [2] linux \n");            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 \n");
                break;
            }    
            else if( strpbrk(os_chose,"2")!=NULL )
            {
                ch=‘2‘;
                printf(" linux \n");
                break;
            }    
            // window的telnet程序,按每个字符发送,而首字符往往不是输入的字符,可能是\0,没有去深究,

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

然后检查是否1 或者2 来判断登陆者选择的系统类型。
        }
        strcpy(buf,"\r\ntelnet_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,"\rtelnet_shell>>");
                    write(connfd,buf,20);
                    bzero(&buf,2048);
                }
                if(ch==‘1‘)
                { // window的telnet客户端,按单个字符发送命令,所以要对输入的单个字符重新组合。
                    read(connfd,&tmp_ch,1);
                    if(tmp_ch==‘\0‘&&i==0)
                    {}    
                    else if(tmp_ch!=‘\n‘)
                    buf_in[i++]=tmp_ch;
                    else if(tmp_ch==‘\n‘&&i!=0)
                    {    
                        printf("%s \n",buf_in);
                        buf_in[i]=‘ ‘;
                        buf_in[i+1]=‘ ‘;
                        buf_in[i+2]=‘\n‘;
                     if( exec_cmd(buf_in,connfd)==10 )
                         goto start;
                        bzero(&buf_in,2048);
                        strcpy(buf_in,"\rtelnet_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,‘\0‘,2048);
    if( (pipe(pipe_fd))==-1 )
    {
        perror("pipe init error");
        return -1;
    }    
    memset(tmp_p,‘\0‘,200);
    memset(cmd_data,‘\0‘,10*5);
    memset(argv,‘\0‘,5);
    strcpy(tmp_p,p);
    p_tmp=tmp_p;
    while( (*p_tmp)!=‘\n‘ )
    {
        if( ((*p_tmp)==‘\r‘) )
        {
            *p_tmp=‘ ‘;
    *(p_tmp+1)=‘\r‘;
            *(p_tmp+2)=‘\n‘;
            break;
        }    
        ++p_tmp;
    }    //以空格符为字符串分割符有一个缺点,就是会把字符串的末尾符号\r\n也认为是字符串,而在exec时,无法正确执行命令,所以不管字符串末尾是否有空格,都统一在\r\n前加入空格符。
    token=strtok(tmp_p," ");
    while(token!=NULL)
    {
        if( (*token!=‘ ‘)&&(*token!=‘\n‘)&&(*token!=‘\0‘) )
        strcpy(cmd_data[id++],token);
        token=strtok(NULL," ");    }    cmd_data[id-1][strlen(cmd_data[id-1])-1]=‘\0‘;    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 ! \n");        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,‘\0‘,2048);        memset(tmp,‘\0‘,2048);//读取子进程写入到管道中的信息        read(pipe_fd[0],buf_cmd,2048);        buf_p=buf_cmd;        puts(buf_cmd);//linux和window都统一起来,虽然linux对于换行符的处理是换行和自动回车,这里为了方便起见,都统一加入回车符。这样就可以在window下完美显示了。        while( buf_cmd[buf_i]!=‘\0‘)        {                tmp[buf_i]=buf_cmd[buf_i++];            if( buf_cmd[buf_i]==‘\n‘ )            {                tmp[buf_i-1]=‘\r‘;                tmp[buf_i++]=‘\n‘;            }        }            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

时间: 2024-08-04 03:31:07

网络版shell之网络编程练习篇--telnet服务端的相关文章

网络编程(浏览器客户端-自定义服务端)

1 package netTest; 2 /* 3 * 演示客户端和服务端 4 * 1 客户端:浏览器 5 * 服务端:自定义 6 * tomcat 服务器所作的事情:用printwriter out 把网页数据全打到客户端去, 7 * 而浏览器可以解析 数据. 8 * telnet 远程登录:windows 提供的远程登录的工具,它可以去连接网络中的任意一台主机(dos命令行下连接) 9 * 可以对主机进行命令式的配置.(客户端软件) 10 */ 11 import java.net.*; 1

《C#网络编程高级篇之网页游戏辅助程序设计(扫描版)》

<C#网络编程高级篇之网页游戏辅助程序设计>通过编写C#网络编程语言中具有代表性的实例,向读者深入细致地讲解了如何利用C#语言进行网页游戏辅助程序设计.本书通过大量的代码引导读者一步步学习和掌握C#的网络应用编程的方法和网页游戏辅助程序的设计技术. <C#网络编程高级篇之网页游戏辅助程序设计>涉及的领域包括多线程编程技术.socket套接字编程.tcp协议编程.http协议编程.远程控制技术.木马技术.模拟键盘和鼠标技术.网页游戏辅助程序设计技术等. <C#网络编程高级篇之网

万物互联之~网络编程深入篇

深入篇¶ 上节回顾:5种IO模型 | IO多路复用 and 万物互联之-网络编程加强篇 官方文档:https://docs.python.org/3/library/internet.html 1.概念回顾¶ 1.1.TCP三次握手¶ 画一张图来通俗化讲讲TCP三次握手: 用代码来说,大概过程就是: 1.2.TCP四次挥手¶ 画图通俗讲下TCP四次挥手: 用代码来说,大概过程就是: 其实这个也很好的解释了之前的端口占用问题,如果是服务端先断开连接,那么服务器就是四次挥手的发送方,最后一次消息是得

centos6.6 yum安装telnet服务端和客户端

查看telent是否安装: rpm -qa | grep telnet 查看yum源上telnet有哪些软件可安装: yum search telnet telnet服务端:telnet-server telnet客户端:telnet 安装 注意,需要root权限来安装 yum -y install telnet-server yum -y install telnet 安装服务端之后其他设备就可以telnet这台设备了(这台设备有telnet服务) 安装服务端之后这台设备就可以telnet其他

socket编程,简单多线程服务端测试程序

socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.accept.recv.send等函数的介绍,今天写了一个CUI界面的测试程序(依赖MFC)作为补充.程序功能简介如下: 1:一个线程做监听用. 2:监听线程收到客户端连接后,创建新线程接收客户端数据.所有对客户端线程将加入容器,以便管理. 3:服务端打印所有客户端发来的信息. 4:服务端CUI界面输入数字

Android版网络办公系统应用客户端+服务端

该项目源码是Android版网络办公系统应用客户端+服务端,也是一个简单的网上办公系统的Android客户端,项目有服务端和客户端部分的源码的,客户端开发环境eclipse  AVD版本 4.0服务器 phpStudy 2013集成环境 Apache+php5.3+ISAPI模式 phpStudy 2013集成环境绿色版下载http://www.phpstudy.net/phpstudy/phpStudy2013d.zip官网   http://www.phpstudy.net/ android

CentOS 7.4安装telnet服务端

CentOS 7.4安装telnet服务端 安装xinetd服务 # yum -y install xinetd 安装telnet-server # yum -y install telnet-server telnet 修改telnet-server配置文件 [[email protected] ~]# cat /etc/xinetd.d/telnet # default: yes # description: The telnet server servestelnet sessions;

C# Socket网络编程精华篇

几个和Socket编程紧密相关的概念: TCP/IP层次模型 当然这里我们只讨论重要的四层 01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用.http协议在应用层运行. 02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP 提供传输保证. 03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP.IGMP.RIP.OSPF.IP(v4,v6)等

socket网络编程——操作篇

一.问题思考 问1.网络通信应用在什么场合?通信的前提是什么? 答1.主要应用在不同主机进程间的互相通信,同一主机的进程也可以使用网络进行通信.通信的前提是如何标识通信进程的唯一,由于不同主机的进程极有可能具有相同的PID,因此,在网络中单单靠PID是无法准确进行标识进程身份的,TCP/IP协议族网络层的IP地址可以唯一的标识连入网络的主机. 问2.socket编程重点是什么? 答2.掌握基于TCP.UDP的S/C架构的编程要点:掌握网络通信方式之间的区别和应用场合. 问3.什么是网络模型? 答