Linux--网络编程-ftp(TCP)网络通信-文件交互

项目要求:实现以下内容

远程控制:

1、查看服务器当前路径文件 ls

3、进入、退出服务器文件夹 cd

4、上传文件到服务器 put xxx

本地控制:

1、查看本地(客户端)文件 lls

2、进入客户端文件夹 lcd

3、获取服务器的文件 get xxx

服务器:解析指令(创建子进程、对接客户端)

1、创建套接字socket

2、绑定bind ip+端口号

3、listen监听

4、accept接受客户端请求,返回值小于0报错

4.1有客户端接入调用fork创建子进程,返回值小于0报错;==0对客户端进行读操作

4.2对读取出来的数据做判断(ls、get、cd、put)

4.2.1get:open打开文件,read文件,send文件到客户端

4.2.2 ls:popen文件,fread读取文件,send发送文件到客户端

5、可system运行一个副服务器,来执行指令与执行结果的存储

6、多个客户端接入实现

客户端:发指令

1、socket创建套接字

2、connect连接服务器

3、连接上以后获取用户的输入,对输入的信息进行处理
问:socket是如何实现数据传输?

服务器:

注意返回的值是进行数据通信的文件描述!!是新的!!说人话就是,定义个int cfd = accept(),这个cfd就是数据传输的通道!!

客户端:connect

使用到的函数:

1.strcmp把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

它的原型如下:

cpp 复制代码
#include <stdio.h>
#include <string.h>
int strcmp(const char *str1, const char *str2);

参数说明:

  • str1:第一个要比较的字符串。
  • str2:第二个要比较的字符串。

返回值:

  • 如果str1str2相等,则返回0。

  • 如果str1小于str2,则返回负数。

  • 如果str1大于str2,则返回正数。

  • strcmp()函数首先将str1字符串的第一个字符的ACSII值减去str2第一个字符的ACSII值(自左向右逐个字符相比,直到出现不同的字符或遇'\0'为止)

    若差值为零则继续比较下去;若差值不为零,则返回差值。

    特别注意:strcmp可用于比较两个字符串常量或比较数组和字符串常量,不能比较数字等其他形式的参数。

2.strstr在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。

它的原型如下:

cpp 复制代码
#include <stdio.h>
#include <string.h>
char *strstr(const char *haystack, const char *needle);
复制代码
参数说明:
  • haystack:要在其中查找子串的主字符串。
  • needle:要查找的子串。

返回值:

  • 如果找到子串,则返回指向首次出现位置的指针。
  • 如果未找到子串,则返回NULL。
  1. strtok 分解字符串 str 为一组字符串,delim 为分隔符。

它的原型如下:

cpp 复制代码
#include <stdio.h>
#include <string.h>
char *strtok(char *str, const char *delim);
复制代码
参数说明:
  • str:要被分解为一组小字符串的原始字符串。在第一次调用时,应传入需要被切割的字符串的首地址;后续调用时,应传入NULL,以便从上次的位置继续分割。
  • delim:一个包含多个分隔符的字符串。这些字符将被用作分隔符,将str分割成多个子串。

返回值:

  • 该函数返回被分解出的第一个子串的首地址。如果没有更多的子串可以提取,则返回NULL。

使用示例:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    char sub[] = ", ";
    char *result;

    result = strtok(str, sub);
    while (result != NULL) {
        printf("%s", result);
        result = strtok(NULL, sub);
    }
    return 0;
}

结果:

cpp 复制代码
Hello
World!
  1. chdir函数 用户将当前的工作目录改变成以参数路径所指的目录。

它的原型如下:

cpp 复制代码
#include <unistd.h>

int chdir(const char *path);

参数说明:

  • path:指向一个以空字符结尾的字符串,该字符串包含要切换到的新目录的路径名。

返回值:

  • 若成功则返回0,否则返回-1,并设置errno为错误原因。

注意:这个函数只影响当前进程的工作目录,不会影响其他进程。

例如,以下代码将当前工作目录更改为"/home/user":

cpp 复制代码
if (chdir("/home/user") == -1) {
    perror("Error changing directory");
}

5.fflush函数 更新缓存区

函数说明:调用fflush()会将缓冲区中的内容写到stream所指的文件中去.若stream为NULL,则会将所有打开的文件进行数据更新。

fflush(stdin):刷新缓冲区,将缓冲区内的数据清空并丢弃。

fflush(stdout):刷新缓冲区,将缓冲区内的数据输出到设备,强制打印。

cpp 复制代码
#include <stdio.h>
int fflush(FILE *stream);

参数:

  • stream:指向要刷新的文件流的指针。

返回值:

  • 成功:返回0;
  • 失败:返回EOF(通常是-1)。

项目代码:

congfig.h

cpp 复制代码
#define LS   0  
#define GET  1
#define PWD  2

#define IFGO 3

#define LCD  4
#define LLS  5
#define CD   6
#define PUT  7

#define QUIT   8 
#define DOFILE 9


struct Msg
{
       int type;
       char cmd[1024];
       char secondBuf[128];
};

服务器:

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "congfig.h"
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

// transfor type

int get_cmd_type(char *cmd)
{
	if(!strcasecmp("ls",cmd))		return LS;//bijiao hanshu
	if(!strcasecmp("quit",cmd))		return QUIT;
	if(!strcasecmp("pwd",cmd))		return PWD;

	if(strstr(cmd,"cd")!=NULL)		return CD;
	if(strstr(cmd,"get")!=NULL)		return GET;
	if(strstr(cmd,"put")!=NULL)		return PUT;




	return 0;
}



//get input comd
char *getDesDir(char *cmsg)
{

	char *p;
	p = strtok(cmsg," ");
	p = strtok(NULL," ");
	return p;
}

//processing command
void msg_handler(struct Msg msg,int fd)
{
	char cmdBuf[1024] = {0};
	char *file = NULL;
	int fdfile;


	printf("from client cmd is %s\n",msg.cmd);

	int ret = get_cmd_type(msg.cmd); 
//transfor cmd type


	switch(ret){

		case LS:
		case PWD:
			msg.type = 0;
			FILE *r = popen(msg.cmd,"r");
			fread(msg.cmd,sizeof(msg.cmd),1,r);
			write(fd,&msg,sizeof(msg));

			break;


		case CD:
			msg.type = 1;
			char *dir = getDesDir(msg.cmd);
			printf("the target file is:%s\n",dir);
			chdir(dir);//system fun
			break;

		case GET:
			file = getDesDir(msg.cmd);
			if(access(file,F_OK) == -1){
				strcpy(msg.cmd,"file not found");
				write(fd,&msg,sizeof(msg));

			}else{

				msg.type = DOFILE;
				fdfile = open(file,O_RDWR);
				read(fdfile,cmdBuf,sizeof(cmdBuf));
				close(fdfile);

				strcpy(msg.cmd,cmdBuf);
				write(fd,&msg,sizeof(msg));

			}
			break;
		case PUT:

			fdfile = open(getDesDir(msg.cmd),O_RDWR|O_CREAT,0600);
			write(fdfile,msg.secondBuf,strlen(msg.secondBuf));
			close(fdfile);
			break;
		case QUIT:
			printf("disconnect\n");
			exit(-1);







	}


//	return 0;
}




int main(int argc,char **argv)
{
	int s_fd;
	char readbuf[128];
	int nread;
	int mark=0;

//	char msg[1024]={0};
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	struct Msg msg;

	if(argc!=3){
		printf("param is not good\n");
		exit(-1);
	}

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

	//1.socket
	s_fd=socket(AF_INET,SOCK_STREAM,0);
	if(s_fd==-1){
		perror("socket");
		exit(-1);
	}
	//2.bind
	s_addr.sin_family=AF_INET;
	s_addr.sin_port=htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);

	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	//3.listen
	listen(s_fd,10);
	//4.accept
	int clen=sizeof(struct sockaddr_in);
	while(1){
		int c_fd=accept(s_fd,(struct sockaddr*)&c_addr,&clen);
		if(c_fd==-1){
			perror("accept");
		}
		printf("connect\n");
		mark++;
		sleep(2);
		printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));

		if(fork()==0){
			while(1){
				//5.read
				memset(msg.cmd,0,sizeof(msg.cmd));
				nread=read(c_fd,&msg,sizeof(msg));
				if(nread== 0){
					perror("read");
					printf("connet not");
					exit(-1);
				}else if(nread > 0){
					msg_handler(msg,c_fd);//send msg to func
				}
			}
			break;
		}	
	}
	return 0;
}

客户端:

cpp 复制代码
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <arpa/inet.h>
#include<string.h>
#include <unistd.h>
#include"congfig.h"
#include <fcntl.h>

char *getdir(char *cmd)
{
	char *p;
	p = strtok(cmd, " ");
	p = strtok(NULL," ");

	return p;
}

int get_cmd_type(char *cmd)
{
	if(strstr(cmd,"lcd"))      return LCD;

	if(!strcmp("quit",cmd))    return QUIT;
	if(!strcmp("ls",cmd))      return LS;
	if(!strcmp("lls",cmd))     return LLS;
	if(!strcmp("pwd",cmd))     return LS;

	if(strstr(cmd,"cd"))       return CD;
	if(strstr(cmd,"get"))      return GET;
	if(strstr(cmd,"put"))      return PUT;

	return -1;
}


int cmd_handler(struct Msg msg,int fd)
{
	char *dir = NULL;
	char buf[32];
	int ret;
	int filefd;

	ret = get_cmd_type(msg.cmd);
	switch(ret){

		case LS:
		case CD:
		case PWD:
			msg.type = 0;
			write(fd,&msg,sizeof(msg));
			break;

		case GET:
			msg.type = 2;
			write(fd,&msg,sizeof(msg));
			break;

		case PUT:
			strcpy(buf,msg.cmd);
			dir = getdir(buf);

			if(access(dir,F_OK) == -1){
				printf("%s not exsit\n",dir);
			}else{
				filefd = open(dir,O_RDWR);
				read(filefd,&msg.secondBuf,sizeof(msg.secondBuf));
				close(filefd);

				write(fd,&msg,sizeof(msg));
			}
			break;

		case LLS:
			system("ls");
			break;

		case LCD:
			dir = getdir(msg.cmd);
			chdir(dir);
			break;

		case QUIT:
			strcpy(msg.cmd,"quit");
			write(fd,&msg,sizeof(msg));
			close(fd);
			exit(-1);

	}
	return ret;
}

void handler_server_message(int c_fd,struct Msg msg)
{
	int n_read;
	struct Msg msgget;
	int newfilefd;

	n_read = read(c_fd,&msgget,sizeof(msgget));

	if(n_read == 0){
		printf("server is out,qiut\n");
		exit(-1);
	}

	else if(msgget.type == DOFILE){

		char *p = getdir(msg.cmd);
		newfilefd = open(p,O_RDWR|O_CREAT,0600);
		write(newfilefd,msgget.cmd,strlen(msgget.cmd));
		putchar('>');
		fflush(stdout);
	}
	else{
		printf("-----------------------");
		printf("\n%s\n",msgget.cmd);
		printf("-----------------------");

		putchar('>');
		fflush(stdout);
	}

}

int main(int argc,char **argv)
{
	int c_fd;
	struct sockaddr_in c_addr;
	struct Msg msg;

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

	if(argc != 3 ){
		printf("鍙傛暟涓嶅!\n");
		exit(-1);
	}

	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		perror("socket");
		exit(-1);
	}

	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);

	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(-1);
	}
	printf("连接成功.......\n");
	int mark = 0;
	while(1){

		memset(msg.cmd,0,sizeof(msg.cmd));
		if(mark == 0)    printf(">");

		gets(msg.cmd);

		if(strlen(msg.cmd) == 0){
			if(mark == 1){
				printf(">");
			}
			continue;
		}
		mark = 1;

		int ret = cmd_handler(msg,c_fd);

		if(ret > IFGO){
			putchar('>');
			fflush(stdout);
			continue;
		}
		if(ret == -1){
			printf("command not\n");
			printf(">");
			fflush(stdout);
			continue;
		}
		handler_server_message(c_fd,msg);  
	}

	return 0;
}

运行结果:

相关推荐
XH华10 分钟前
Linux系统第二章:常见的Linux指令(上)
linux·运维·服务器
M158227690559 小时前
跨协议互通利器|SG-PN-EIP (S)-220 Profinet 转 EtherNet/IP 网关,打通欧美 PLC 通讯壁垒
网络·网络协议·tcp/ip
FoldWinCard10 小时前
D5 Linux 网络及端口命令
linux·运维·服务器
零涂毕业设计11 小时前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
tedcloud12312 小时前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
霸道流氓气质12 小时前
KMS 密钥管理服务(Key Management Service)原理与实践
linux·服务器·数据库
SakitamaX12 小时前
LVS(Linux Virtual Server)概念详解
linux·运维·lvs
小张同学a.12 小时前
Linux系统管理
linux·运维
阿龙的工作记录12 小时前
深入理解Linux设备驱动模型
linux·嵌入式硬件·工作记录
代码村新手13 小时前
Linux的基本指令
linux·运维·服务器