网络编程:CMD命令
要求:
写一个客户端程序和服务器程序,客户端程序连接上服务器之后,通过敲命令和服务器进行交互,支持的交互命令包括:
- pwd:显示服务器应用程序启动时的当前路径。
- cd:改变服务器应用程序的当前路径。
- ls:显示服务器应用程序当前路径下的文件列表。
- quit:客户端进程退出,但是服务器端不能退出,第二个客户可以再次连接上服务器端。
客户端向服务端发送交互命令,服务端将查询的结果返回给客户端
开干
客户端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 1024
int tcp_client(char *address, int port)
{
int socket_fd;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
inet_pton(AF_INET, address, &server_addr.sin_addr);
socklen_t server_len = sizeof(server_addr);
int connect_rt = connect(socket_fd, (struct sockaddr *)&server_addr, server_len);
if(connect_rt < 0)
{
perror("connect failed");
return -1;
}
return socket_fd;
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
perror("usage: cmd_client <IPaddress> <port>");
return -1;
}
int port = atoi(argv[2]);
printf("argv1:%s\n",argv[1]);
int socket_fd = tcp_client(argv[1], port);
char recv_line[MAXLINE],send_line[MAXLINE];
int n;
fd_set readmask;
fd_set allreads;
FD_ZERO(&allreads);
FD_SET(0, &allreads);
FD_SET(socket_fd, &allreads);
for(;;)
{
readmask = allreads;
int rc = select(socket_fd+1, &readmask, NULL, NULL, NULL);
if(rc <= 0)
{
perror("select failed");
return -1;
}
if(FD_ISSET(socket_fd, &readmask))
{
n = read(socket_fd, recv_line, MAXLINE);
if(n < 0)
{
perror("read error");
return -1;
}
else if(n == 0)
{
printf("server closed");
break;
}
recv_line[n] = 0;
fputs(recv_line, stdout);
fputs("\n",stdout);
}
if(FD_ISSET(STDIN_FILENO, &readmask))
{
if(fgets(send_line, MAXLINE, stdin) != NULL)
{
int i = strlen(send_line);
if(send_line[i - 1] == '\n')
{
send_line[i - 1] = 0;
}
if(strncmp(send_line, "quit", strlen(send_line)) == 0)
{
if(shutdown(socket_fd, 1))
{
perror("shutdown failed");
return -1;
}
}
size_t rt = write(socket_fd, send_line, strlen(send_line));
if(rt < 0)
{
perror("write failed");
return -1;
}
}
}
}
exit(0);
}
客户端的代码主要考虑的是使用 select 同时处理标准输入和套接字。select 如果发现标准输入有事件,读出标准输入的字符,就会通过调用 write 方法发送出去。如果发现输入的是 quit,则调用 shutdown 方法关闭连接的一端。
如果 select 发现套接字流有可读事件,则从套接字中读出数据,并把数据打印到标准输出上;如果读到了 EOF,表示该客户端需要退出,直接退出循环,通过调用 exit 来完成进程的退出。
服务端程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERV_PORT 43211
#define LISTENQ 1024
static int count;
static void sig_int(int signo) {
printf("\nreceived %d datagrams\n", count);
exit(0);
}
char *run_cmd(char *cmd)
{
char *data = malloc(16384);
bzero(data, sizeof(data));
FILE *fdp;
const int max_buffer = 256;
char buffer[max_buffer];
fdp = popen(cmd, "r");
char *data_index = data;
if (fdp)
{
while(!feof(fdp))
{
if(fgets(buffer, max_buffer, fdp) != NULL)
{
int len = strlen(buffer);
memcpy(data_index, buffer, len);
data_index += len;
}
}
pclose(fdp);
}
return data;
}
int main(int argc, char *argv[])
{
int listenfd;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERV_PORT);
int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if(rt1 < 0)
{
perror("bind failed");
return -1;
}
int rt2 = listen(listenfd, LISTENQ);
if(rt2 < 0)
{
perror("listen failed");
return -1;
}
signal(SIGPIPE, SIG_IGN);
int connfd;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
char buf[256];
count = 0;
while(1)
{
if((connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_len)) < 0)
{
perror("accept failed");
return -1;
}
while(1)
{
bzero(buf, sizeof(buf));
int n = read(connfd, buf, sizeof(buf));
if(n < 0)
{
perror("error read message");
continue;
}
else if(n == 0)
{
printf("client closed ");
close(connfd);
break;
}
count++;
buf[n] = 0;
if(strncmp(buf, "ls", n) == 0)
{
char *result = run_cmd("ls");
if(send(connfd, result, strlen(result), 0) < 0)
{
return 1;
}
free(result);
}
else if(strncmp(buf, "pwd", n) == 0)
{
char buf[256];
char *result = getcwd(buf, 256);
if(send(connfd, result, strlen(result), 0) < 0)
{
return 1;
}
}
else if(strncmp(buf, "cd ", 3) == 0)
{
char target[256];
bzero(target, sizeof(target));
memcpy(target, buf+3, strlen(buf) - 3);
if(chdir(target) == -1)
{
printf("change dir failed, %s\n",target);
}
}
else
{
char *error = "error: unknow input type";
if(send(connfd, errno, strlen(errno), 0) < 0)
{
return 1;
}
}
}
}
exit(0);
}
服务器端程序需要两层循环,第一层循环控制多个客户端连接,第二层循环控制和单个连接的数据交互
在第一层循环里通过 accept 完成了连接的建立,获得连接套接字。在第二层循环里,先通过调用 read 函数从套接字获取字节流。这里处理的方式是反复使用了 buf 缓冲,每次使用之前记得都要调用 bzero 完成初始化,以便重复利用。如果读取数据为 0,则说明客户端尝试关闭连接,这种情况下,需要跳出第二层循环,进入 accept 阻塞调用,等待新的客户连接到来
在读出客户端的命令之后,就进入处理环节。通过字符串比较命令,进入不同的处理分支。C 语言的 strcmp 或者 strncmp 可以帮助我们进行字符串比较,
如果命令的格式有错,需要把错误信息通过套接字传给客户端。
对于“pwd”命令,通过调用 getcwd 来完成的,getcwd 是一个 C 语言的 API,可以获得当前的路径。
对于“cd”命令,通过调用 chdir 来完成的,cd 是一个 C 语言的 API,可以将当前目录切换到指定的路径。
对于“ls”命令,通过了 popen 的方法,执行了 ls 的 bash 命令,把 bash 命令的结果通过文件字节流的方式读出,再将该字节流通过套接字传给客户端。
运行结果
网络编程:CMD命令的更多相关文章
- windows查看网络常用cmd命令
一.ping 主要是测试本机TCP/IP协议配置正确性与当前网络现状. ping命令的基本使用格式是: ping IP地址/主机名/域名 [-t] [-a] [-n count] [-l size] ...
- C# 网络与Cmd命令
网络命令行: 1 - ping 2 - ipconfig 本机网络配置情况 3 - net 4 - arp 网络网卡物理/ip地址对应用 5 - tracert 列举数据报到达目标地所经过的网关 6 ...
- 03.windows系统重新分配ip的cmd命令
网络重启CMD命令 ipconfig /release --- 释放ip搜索 ipconfig /renew --- 重新获得
- Python网络编程03 /缓存区、基于TCP的socket循环通信、执行远程命令、socketserver通信
Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命令.socketserver通信 目录 Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命 ...
- Windows最常用的几个网络CMD命令总结
Windows最常用的几个网络CMD命令总结 http://www.cnblogs.com/sbaicl/archive/2013/03/05/2944001.html 一.ping 主要是测试本机T ...
- 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?
本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言 老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...
- Windows最常用的8个网络CMD命令总结
一,ping 它是用来检查网络是否通畅或者网络连接速度的命令.作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都有唯一确定的IP ...
- 网络编程学习笔记-linux常用的网络命令
网络参数设置命令 所有时刻如果你想要做好自己的网络参数设置,包括IP参数.路由参数和无线网络等,就得要了解下面这些相关的命令才行.其中Route及ip这两条命令是比较重要的.当然,比较早期的用法,我们 ...
- 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题
目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...
- 猫哥网络编程系列:HTTP PEM 万能调试法
注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
随机推荐
- 高效开发助手:深入了解Hutool工具库
一.关于Hutool 1.1 简介 Hutool是一个功能丰富且易用的Java工具库,通过诸多实用工具类的使用,旨在帮助开发者快速.便捷地完成各类开发任务. 这些封装的工具涵盖了字符串.数字.集合. ...
- 使用Visual Studio 调式NDK so 库时,调试工具无法显示vector内容
最近在研究C++开发安卓端so库,demo使用xamarin.android作为载体来验证算法库文件的准确性.调试过程中发现vector中的内容无法显示集合详细.如下图 研究了半天(参考链接2.3), ...
- Typecho 引入 DPlayer
想在文章中插入视频,尝试 iframe 和 video 标签后发现 m3u8 流会触发下载无法播放,用 hls 该问题后,碰到了 403 forbbiden.联想到前些天新浪图床加 referrer ...
- jmespath 使用及案例
什么是jmespath jmespath 是python里面的一个库 主要在httprunner框架里使用 2.使用语法 列表: with_jmespath(jmes_path,var_name) m ...
- 关于我第二周学习kotlin这门语言
有关kotlin的知识点: 在学习lambda之前,我们先了解一下什么是lambda,简答来说就是一小段代码块,并且我们可以将这个代码块在函数之间传递,这是函数式编程的一个重要特性. 通常我们会需要一 ...
- Web前端入门第3问:前端需要学习哪些技术?
Web前端开发技术学习路径 基础知识 必备 HTML+CSS+JavaScript ,就目前来看,这三板斧是入门前端开发的门槛,无论如何都是逃不掉了. 进阶知识 必须会一门主流的前端框架,比如:Rea ...
- JMeter 定义 User 随机数变量无效
Jmeter 定义 User 随机数变量无效 随机数方法: RandomString10 ${__RandomString(10,ABCDEFGHIJKLMNOPQRSTUVWXYZ)} Random ...
- docker build 镜像时,无法访问网络
前言 在使用 docker build 命令构建 Docker 镜像时遇到无法联网的情况,可能会有多种情况的发生. 检查主机网络设置 检查你的主机是否配置了代理服务器或防火墙,这可能会阻止 Docke ...
- WebSocket 的产生
HTTP 不断轮询 怎么样才能在用户不做任何操作的情况下,网页能收到消息并发生变更. 最常见的解决方案是,网页的前端代码里不断定时发 HTTP 请求到服务器,服务器收到请求后给客户端响应消息. 这种方 ...
- 对于 emlog pro 目前 avatar 头像不显示的问题,暂时使用这个方法解决
avatar 头像 cdn 不稳定,目前 emlog 官方还没有放出更新包.因此,现在使用 JS 的方式暂时解决. 代码如下 <script> const avaUrl = 'https: ...