IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 基于Linux的客户端与服务端的传输和信息交互 -> 正文阅读

[系统运维]基于Linux的客户端与服务端的传输和信息交互

基于Linux的客户端与服务端的传输和信息交互,利用socket网络来构建服务端和客户端的网络请求,在服务端接收到客户端的连接请求的时候创建进程用于,服务端与多个客户端之间的连接,在头文件中穿件用于网络传输数据的结构体,其中包括具体的命令(cmd),传输文件时文件中的内容(context),以及用于判断在传输后是否需要创建文件的标志位;利用字符串处理函数来分解指令,获得具体指令,再根据指令的类型来选择需要执行的代码,实现服务端与客户端之间的文件传输和信息交互;

头文件中包含宏定义各个指定,和数据传输过程中的结构体:
parament.h

#define LS 1
#define CD 2
#define PWD 3
#define LLS 4
#define LCD 5
#define DOWNLOAD 6
#define UPLOAD 7
#define QUIT 8


struct command{
	char cmd[128];          //具体命令
	char context[1024];    //用于存放服务端传送给客户端的具体内容
    int flag;	          //客户端需要穿件文件的标记位
};


服务端:

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include<arpa/inet.h>
#include <netinet/in.h>
#include<string.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "parament.h"

int getCmdType(char *cmd)                //获取命令类型,并返回宏定义的整形数,用于取命令中switch
{
	if(strcmp("ls",cmd) == 0){
		return LS;
	}
	if(strcmp("quit",cmd) == 0){
		return QUIT;
	}
	if(strcmp("pwd",cmd) == 0){
		return PWD;
	}
	if(strstr(cmd,"cd") != NULL){
		return CD;
	}
	if(strstr(cmd,"download") != NULL){
		return DOWNLOAD;
	}
	if(strstr(cmd,"upload") != NULL){
		return UPLOAD;
	}

	return 0;
	
}


char * cmdDetail(char *cmd)                //利用字符串处理函数将命令细节提取出来
{
	char *temp;
	temp = strtok(cmd," ");
	temp = strtok(NULL," ");
	return temp;	
	
}

void comHandler(struct command Cmd,int fd)      //命令处理函数,参数为从客户端传过来的数据和用于连接的文件描述符
{
	 int ret = getCmdType(Cmd.cmd);            //首先获取命令类型
	 char filename[128];                      
	 int filefd;                               

	 switch(ret){                            //判断指令
		case LS:                             //显示服务端文件
		case PWD:                            //显示服务端当前路径
			Cmd.flag = 0;                    //这个标记为是用于客户端判断是否需要穿件文件(download),服务端会发送过来数据
			FILE *f = popen(Cmd.cmd,"r");    //因为需要将内容在客户端打印出来,所以使用popen将执行结果放入FILE流中
			fread(Cmd.context,1,sizeof(Cmd.context),f);     //将结果放置到数据传输结构体的具体内容中
			write(fd,&Cmd,sizeof(Cmd));                     //将传输结构体发送到客户端
			printf("you get my path or file\n");      //在服务端打印提示信息
			
			break;
		case CD:                            //服务端进入文件夹
			Cmd.flag =0;                    //该操作不需要客户端创建文件
			strcpy(filename,cmdDetail(Cmd.cmd));    //获取客户端发送过来的命令中具体路径
			chdir(filename);                  //利用chdir进入文件夹
			printf("into %s\n",filename);    //打印提示命令
			break;
	 	case DOWNLOAD:                      //客户端需要从服务端下载文件
			                 
			strcpy(filename,cmdDetail(Cmd.cmd));   //获取具体文件名

			if(access(filename,F_OK) == -1){       //判断是否有该文件
				Cmd.flag = -1;                   //没有该文件设置标志位为-1
				strcpy(Cmd.cmd,"server No such file"); //将传输数据的结构体输入信息发送给客户端
				write(fd,&Cmd,sizeof(Cmd));
			}else{
				Cmd.flag = 1;                     //需要服务端发送文件信息到客户端,所以需要把结构体标志位置1  
				filefd = open(filename,O_RDWR);   //以可读可写方式打开文件
				read(filefd,Cmd.context,sizeof(Cmd.context));  //读取文件信息到传输的结构体中的具体内容中
				close(filefd);                    //关闭文件

				write(fd,&Cmd,sizeof(Cmd));      //发送信息到客户端
					
			}
			printf("put file to %d client success\n",fd);

			break;
		case UPLOAD:                                     //从客户端传输过来的文件
			Cmd.flag = 0;                                
			strcpy(filename,cmdDetail(Cmd.cmd));
			filefd = open(filename,O_CREAT|O_RDWR,0666);
			write(filefd,Cmd.context,sizeof(Cmd.context));
			close(filefd);
			printf("get file from %d client success\n",fd);

			break;

		case QUIT:                              //客户端退出
			Cmd.flag = 0;
			printf("client fd quit\n");
			exit(-1);
			break;
		case 0:                               //发送错误命令
			printf("command is wrong\n");
			break;
	 }

}


int main()
{

	int s_fd;

	int bind_ret;
	int listen_ret;

	int nread;
	struct sockaddr_in s_addr;

	struct sockaddr_in c_addr;

	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));

        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(8899);

        inet_aton("192.168.191.3",&s_addr.sin_addr);

	//socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);   

	if(s_fd ==-1){
		perror("socket");
		exit(-1);
	}

	//bind
	bind_ret = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	if(bind_ret == -1){
		perror("bind");
		exit(-1);
	}

	//listen
	listen_ret = listen_ret = listen(s_fd,10);

	if(listen_ret == -1){
		perror("listen");
		exit(-1);
	}
	//accept
	int  c_addr_len = sizeof(struct sockaddr_in);      //以上为socket经典操作
	int c_fd;
	struct command readBuf;                   //定义一个命令结构体
	while(1){                              //创建一个死循环让服务端一直接受客户端连接
		c_fd= accept(s_fd,(struct sockaddr *)&c_addr,&c_addr_len);    //获取到一个客户端连接

		if(c_fd == -1){
			perror("accept error:");
		}
		printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));

		if(fork() == 0){                        //当有一个客户端连接上时创建一个子进程
			while(1){                           //子进程中不断读取客户端发送过来的信息并做相应处理
				memset(readBuf.cmd,0,sizeof(readBuf.cmd));
				nread = read(c_fd,&readBuf,sizeof(readBuf));
				if(nread == 0){
					printf("client out\n");
					break;
				}else if(nread >0){
					printf("from client:%s  message:%s",inet_ntoa(c_addr.sin_addr),readBuf.cmd);
					comHandler(readBuf,c_fd);
				}
			}	
		}
	}
	
	close(c_fd);
	close(s_fd);

	return 0;

}

客户端:

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>         
#include <sys/socket.h>
//#include<linux/in.h>
#include<arpa/inet.h>
#include <netinet/in.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "parament.h"


int FLAG;  //该全局变量用于客户端在发送完数据之后是否需要接受服务端的数据
int getCmdType(char *cmd)
{
        if(strcmp("ls",cmd) == 0){
                return LS;
        }
        if(strcmp("quit",cmd) == 0){
                return QUIT;
        }
	if(strcmp("lls",cmd) == 0){
		return LLS;
	}
	if(strstr("lcd",cmd) != NULL){
		return LCD;
	}
        if(strcmp("pwd",cmd) == 0){
                return PWD;
        }
        if(strstr(cmd,"cd") != NULL && strstr(cmd,"lcd") == NULL){
                return CD;
        }
        if(strstr(cmd,"download") != NULL){
                return DOWNLOAD;
        }
        if(strstr(cmd,"upload") != NULL){
                return UPLOAD;
        }

        return 0;

}


char * cmdDetail(char *cmd)
{
        char *temp;
        temp = strtok(cmd," ");
        temp = strtok(NULL," ");
        return temp;

}

void cmdHandler(struct command Cmd,int fd)
{
	int CMD = getCmdType(Cmd.cmd);
	char ret[128] = {'\0'};
	int filefd;

	switch(CMD){
		case LS:
		case PWD:
		case CD:
			FLAG = 1;            //需要打印路径,文件名,所以需要在发送完数据之后再接受服务端发送过来的数据
			write(fd,&Cmd,sizeof(Cmd));
			break;
		case DOWNLOAD:
			FLAG=1;             //下载服务端中的某个文件
			write(fd,&Cmd,sizeof(Cmd));
			break;
		case UPLOAD:            //将某个文件传输给服务端
			FLAG=0;
			strcpy(ret,cmdDetail(Cmd.cmd));
			if(access(ret,F_OK) == -1){   //判断客户端是否有该文件
				printf("client No such file\n");
			}
			filefd = open(ret,O_RDWR);
			memset(Cmd.context,0,sizeof(Cmd.context));
			read(filefd,Cmd.context,sizeof(Cmd.context));
			write(fd,&Cmd,sizeof(Cmd));
			break;
		case LLS:            //客户端展示文件夹中的文件
			FLAG=0;
			system("ls");
			break;
		case LCD:           //客户端进入某个文件夹
			FLAG=0;
			strcpy(ret,cmdDetail(Cmd.cmd));
			chdir(ret);
			break;
		case QUIT:        //客户端退出
			FLAG=0;
			strcpy(Cmd.cmd,"quit");
			write(fd,&Cmd,sizeof(Cmd));
			close(fd);
			exit(-1);
			break;
	}
	
}

void cmdFromServerhandler(struct command recv,int fd)         //客户端在发送完消息后有的命令需要接受服务端的内容所以需要该函数
{
	int nread = read(fd,&recv,sizeof(recv));
	int filefd;

	if(recv.flag == 1){                    //结构体中的标记位为1,所以需要创建文件来写入客户端传入的数据
		char *filename = cmdDetail(recv.cmd);
		filefd = open(filename,O_CREAT|O_RDWR,0666);
		write(filefd,recv.context,sizeof(recv.context));

	}else{                           //否则打印传输过来的结构体中的具体数据
		printf("=============================\n");
		printf("%s\n",recv.context);
		printf("=============================\n");
	}

}

int main(int argc,char **argv)
{

	int c_fd;

	int connect_ret;

	struct command sendBuf;
	struct command receBuf;


	struct sockaddr_in c_addr;

	memset(&c_addr,0,sizeof(struct sockaddr_in));

        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(atoi(argv[2]));

        inet_aton(argv[1],&c_addr.sin_addr);

	//socket
	c_fd = socket(AF_INET,SOCK_STREAM,0);   

	if(c_fd ==-1){
		perror("socket");
		exit(-1);
	}

	//connect
	connect_ret = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));
	if(connect_ret == -1){
	    perror("connect");
	    exit(-1);
	}else{
		printf("connect success");
	}
        
	while(1){
		printf("please input command:");
		memset(sendBuf.cmd,0,sizeof(sendBuf.cmd));
		gets(sendBuf.cmd);                       //输入命令到结构体cmd中

		cmdHandler(sendBuf,c_fd);                       //调用处理函数
		if(FLAG == 0){                                  //根据全局变量判断是否需要处理服务端发送过来的数据
			continue;
		}
		cmdFromServerhandler(receBuf,c_fd);             //服务端发送过来的数据处理函数
	}

	return 0;

}

代码中的注意事项:
在输入命令的时候由于需要加上空格所以使用gets()进行输入,scanf()会直接将空格之后的内容忽略掉;
strtok在使用的时候注意不能直接对常量字符串进行操作,需要把常量字符串转换为字符数组的形式;
项目效果:
在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 21:50:43  更:2021-08-07 21:51:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:17:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码