网络版shell之网络编程练习篇--telnet服务端
2013-06-25 17:25
288 查看
以前写过一个shell命令解释器,对与shell命令解释器的执行流程有了清晰的认识,这段时间学习网络编程,至于网络编程的细节以及知识点,已经在上一遍博客中,转载了从网上摘的文章,基本概括了网络编程的主要api,而对于程序员,更重要的是解决实际问题的能力,所以练习是非常重要的,现在,我们在一起shell命令解释器的基础上,写一个基于socket网络编程的网络版shell命令解释器,也可以称之为telnet服务端。
telnet服务端代码:
my_type.h 与exec_cmd()函数
my_type.h文件:
阅读(1538) | 评论(0) | 转发(0) |
0
上一篇:Linux下Socket编程【作者不详】
下一篇:规范链表操作
相关热门文章
自己用的ubuntu环境搭建(一)...
Twisted用户验证之服务端详解...
一次tuxedo重启服务失败的处理...
打印struct in_addr / sockadd...
Redis源码简要分析
test123
编写安全代码——小心有符号数...
使用openssl api进行加密解密...
一段自己打印自己的c程序...
sql relay的c++接口
GCC编译命令
推荐系统常用算法
C++Primer笔记 第八章 标准IO...
c语言中的#号和##号的作用...
gstreamer插件开发-------sink...
给主人留下些什么吧!~~
评论热议
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; } |
#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; } } |
#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 |
0
上一篇:Linux下Socket编程【作者不详】
下一篇:规范链表操作
相关热门文章
自己用的ubuntu环境搭建(一)...
Twisted用户验证之服务端详解...
一次tuxedo重启服务失败的处理...
打印struct in_addr / sockadd...
Redis源码简要分析
test123
编写安全代码——小心有符号数...
使用openssl api进行加密解密...
一段自己打印自己的c程序...
sql relay的c++接口
GCC编译命令
推荐系统常用算法
C++Primer笔记 第八章 标准IO...
c语言中的#号和##号的作用...
gstreamer插件开发-------sink...
给主人留下些什么吧!~~
评论热议
相关文章推荐
- 网络版shell之网络编程练习篇--telnet服务端
- 网络版shell之网络编程练习篇--telnet服务端
- 黑马程序员-网络编程TCP练习(服务端)
- JavaSE_网络编程_TCP_练习4_与浏览器和服务端交互
- 26-网络编程-14-网络编程(TCP协议-练习-文本转换服务端)
- 27-网络编程-18-网络编程(TCP协议-练习-上传图片服务端)
- 27-网络编程-19-网络编程(TCP协议-练习-服务端多线程技术)
- Dave Python 练习十八 -- 网络编程
- 26-网络编程-11-网络编程(TCP协议-服务端)
- Dave Python 练习十九 -- 网络客户端编程
- Java基础-网络编程(自定义浏览器-Tomcat服务端)
- linux下网络编程2:服务端和客户端进行TCP通信实例
- 网络编程(33)—— 使用AF_UNIX构建本地通信的socket服务端和客户端
- Java基础知识网络编程(TCP练习)
- 网络编程 客户端 服务端 函数 流程 图示 来自深入理解计算机系统一书 P704
- Android网络编程之搭建一个属于你自己的简单servlet服务端。
- JAVA SOCKET网络编程,服务端接收多个客户端连接的实现
- java例程练习(网络编程[简单UDP通信试验])
- shell 编程实例练习(二)
- Java基础---Java---网络编程---TCP的传输、客户端和服务端的互访、建立一个文本转换器、编写一个聊天程序