Linux基于socket 和 tcp协议的FTP文件传输系统

Linux 基于server和client的FTP文件项目

功能需求:

  • 远程操作:
    ①获取服务器的文件: get xxx
    ②显示服务器有哪些文件: ls
    ③进入服务器某文件夹: cd xxx
    ④上传文件到服务器: put xxx
    ⑤打印当前服务器路径: pwd
    ⑥退出服务器: quit
  • 本地操作:
    ①查看客户端本地文件: lls
    ②进入客户端文件夹: lcd

基本思路

  • 利用客户端和服务断框架,一旦服务端接收到客户端的连接请求,服务器fork()创建一个子进程负责处理客户端的指令,客户端发出指令,服务端根据指令做出相应的处理并返回值给客户端,客户端根据返回值打印结果。
  • 利用宏定义指令简化代码
  • 用函数封装实现小功能
  • 利用结构体储存并传递指令和返回值
  • 当客户端读取到指令输入,用cmd_handler把指令转化为宏,输送给服务端。服务端接收到指令,msg_handler进行处理,并返回data给客户端,然后客户端再用server_handler处理返回的数据,最后输出结果。

小功能实现

  • 宏定义以及结构体构建
    这里直接自定义一个头文件,包含宏定义指令和要用的结构体,以便于引用
    congfig.h:
#define LS   0
#define CD   1
#define PWD  2
#define GET  3

#define IFRET 4

#define LLS  5
#define LCD  6
#define PUT  7
#define QUIT   8
#define DOFILE 9


struct Msg                                  //传递的信息结构体
{
        int type ;                  //服务器返回类型,0表示不用返回,1表示字符串,DOFILE表示要创建文件
        char data[32];    //指令
        char secondBuf[10240];//数据,用于server和client间的通信

};
  • getdir()用空格分割处理ls的输出结果,并返回。strtok()首次调用,使用空格第一次分割,之后调用传入NULL,字符串固定用法。我们二次调用,返回值是被分割出来的第二个字符串,即文件名。
 			char *getdir(char *cmd)
           {
                  char *p;

                  p = strtok(cmd," ");
                  p = strtok(NULL," ");

                  return p;

           }
  • cd/pwd
    与ls类似,使用popen(),调用相应的命令,返回输出结果,注意cd改变目录时,调用的是chdir(),表示进入相应的文件,不能用system(),否则,是在shell窗口下进入。主窗口下没有变化。

服务端:

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

        break;
 case CD:
        msg.type = 1;
        char *dir = getDesDir(msg.data);
        printf("dir:%s\n",dir);
        chdir(dir);
        break;
   
  • lls/lcd

同理,在客户端,直接调用相关函数:

case LLS:
        system("ls");
        break;
case LCD:
        dir = getdir(msg.data);
        chdir(dir);
        break;
  • quit
    服务端调用extit(-1)退出。

代码

  1. servser.c
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include<linux/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <string.h>
#include <unistd.h>
#include"config.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>



/*struct sockaddr_in {
		sa_family_t sin_family;		//协议族
		in_port_t 	sin_port;		//端口号
		struct in_addr sin_addr;		//IP地址结构体
		unsigned char	sin_zero[8];	//填充,没有实际意义,只是为更sockaddr结构在内存中相互对齐,这样才能相互转换

}*/



/*struct in_addr {
        __be32  s_addr;
};*/

int get_cmd_type( char *cmd){

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

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

	return -1;
}

char *getdesdir(char *cmd){

	char *p;

	p = strtok(cmd," ");
	p = strtok(NULL," ");
	
	return p;
}



void msghandler(int fd,struct Msg msg){

	int ret = get_cmd_type(msg.data);
	char *file = NULL;
	int fdfile;
	char databuf[10240] = {0};
	char *dir;
	char msg_databuf[32] = {0};

	printf("cmd:%s\n",msg.data);
	
	switch(ret){
	
		case LS:
		case PWD:
			msg.type = 1;

			FILE *r = popen(msg.data,"r");
			fread(msg.secondBuf,sizeof(msg.secondBuf),1,r);
			write(fd,&msg,sizeof(msg));

			break;
		case GET:
			strcpy(msg_databuf,msg.data);
			file = getdesdir(msg.data);
			strcpy(msg.data,msg_databuf);

			if(access(file,F_OK) == -1){//判断文件名是否存在
		
				msg.type = 1;	
				strcpy(msg.secondBuf,"file is not exist");
				write(fd,&msg,sizeof(msg));
			
			}else {
			
				msg.type = DOFILE;
	                   	
				fdfile = open(file,O_RDWR);
				read(fdfile,databuf,sizeof(databuf));
				
				close(fdfile);
				
				strcpy(msg.secondBuf,databuf);
				write(fd,&msg,sizeof(msg));
			
			}

			break;
		case PUT:
			file = getdesdir(msg.data);
                        if(access(file,F_OK) != -1){//判断文件名是否存在

				msg.type = 1;
                                strcpy(msg.secondBuf,"file is  exist");
                                write(fd,&msg,sizeof(msg));

                        }else{
				msg.type = 0;
		
                                fdfile = open(file,O_RDWR|O_CREAT,0600);
                                write(fdfile,msg.secondBuf,sizeof(msg.secondBuf));
                                close(fdfile);

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

			break;	
		case CD:

			dir = getdesdir(msg.data);
			
			if(access(dir,F_OK) == -1){
				msg.type = 1;
				strcpy(msg.secondBuf,"dir is not exist");	
		
			}else{
				msg.type = 0; 
				chdir(dir);
			}
			write(fd,&msg,sizeof(msg));

			break;
		case QUIT:
			msg.type = 0;
			write(fd,&msg,sizeof(msg));	
			printf("client quit\n");
			exit(-1);
			break;
		case -1:

			break;		
	}


	
}




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

	int s_fd;
	int c_fd;
	key_t key;
	pid_t pid;
	int sizec_addr;

	struct Msg msg;
	char readbuf[128] ={0}; 

	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));


	//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;		//IPV4 因特网
	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 );

	printf("listen...\n");

	while(1){ //不停的接受客户端请求

	//4.accept()函数
	
		sizec_addr = sizeof(struct sockaddr_in);
		c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &sizec_addr);


		if(c_fd != -1){   //有客户端接入
		
			char *p = inet_ntoa(c_addr.sin_addr);			
			printf("client %s connect\n",p);

			pid = fork();
			if(pid == 0){
				while(1){	
					memset(msg.data,0,sizeof(msg.data));
					memset(msg.secondBuf,0,sizeof(msg.secondBuf));
					int n_read = read(c_fd,&msg,sizeof(msg));
					if(n_read == 0){
						printf("client %s out\n",p);
						break;
					
					}else if(n_read >0){
					
						msghandler(c_fd,msg);				
				
					}
				}
			}
	
		}	

	}



	close(s_fd);
	close(c_fd);
	return 0;


}

  1. client.c
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include<linux/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <string.h>
#include <unistd.h>
#include"config.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>




/*struct sockaddr_in {
  sa_family_t sin_family;		//协议族
  in_port_t 	sin_port;		//端口号
  struct in_addr sin_addr;		//IP地址结构体
  unsigned char	sin_zero[8];	//填充,没有实际意义,只是为更sockaddr结构在内存中相互对齐,这样才能相互转换

  }*/



/*struct in_addr {
  __be32  s_addr;
  };*/

int get_cmd_type(char *cmd){

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

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


	return -1;
}

char *getdir(char *cmd){
																
	char *p;

	p = strtok(cmd," ");
	p = strtok(NULL," ");

	return p;
}



int cmd_handler(struct Msg msg,int fd){

	int ret;
	char buf[32] = {0};
	char *dir  = NULL;
	int  filefd;

	ret = get_cmd_type(msg.data);

	switch(ret){
	
		case LS:   
		case CD:	
		case PWD:
		case GET:
			write(fd,&msg,sizeof(msg));
			break;	
		case PUT:
			strcpy(buf,msg.data);
			dir = getdir(buf);
			
			if(access(dir,F_OK) == -1){
			
				printf("%s is not exist\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:
			write(fd,&msg,sizeof(msg));
			system("ls");
			break;
		case LCD:
			write(fd,&msg,sizeof(msg));
			dir = getdir(msg.data);
			
			if(access(dir,F_OK) == -1){
				printf("dir is not exist\n");	
		
			}else{
				chdir(dir);
			}	
			break;
		case QUIT:
			strcpy(msg.secondBuf,"quit");
			printf("client quit\n");
			write(fd,&msg,sizeof(msg));
			close(fd);
			exit(-1);
			break; 	
	
	
	}


	return ret;
}

void server_message_handler(struct Msg msg,int fd){

	int n_read;
	int newfilefd;
	char *file = NULL;

	memset(msg.data,0,sizeof(msg.data));	
	n_read = read(fd,&msg,sizeof(msg));
	
	if(n_read == 0){
		printf("server is out,quit\n");
		exit(-1);
	}
	
	if(msg.type == DOFILE){

		file = getdir(msg.data);
		newfilefd = open(file,O_RDWR|O_CREAT,0600);
		if(newfilefd == -1){
					
			perror("newfilefd");	
		}
		write(newfilefd,msg.secondBuf,strlen(msg.secondBuf));
		close(newfilefd );

	}else if(msg.type == 1){
		printf("................................\n");
		printf("\n%s\n",msg.secondBuf);
		printf("................................\n");

		fflush(stdout);	
	}else if(msg.type == 0){
	
		return ;	
	
	}
	
}




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

	int c_fd;//socket的返回值
	int c_ret;//connect的返回值
	int ret_cmd_handler;//cmd_handler()的返回值
	int sizec_addr;
	struct Msg msg;

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


	//1.socket创建套接字

	c_fd = socket(AF_INET,SOCK_STREAM, 0);
	if(c_fd == -1){

		perror("socket");
		exit(-1);
	}


	//2.connect(向服务器发送连接请求)

	c_addr.sin_family = AF_INET;		//IPV4 因特网
	c_addr.sin_port   = htons( atoi(argv[2]) );//大端变小端
	inet_aton(argv[1],&c_addr.sin_addr) ;//字符串变网络形式

	c_ret = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));
	if(c_ret == -1){
		printf("connect fail\n");
		exit(-1);
	}
	printf("connect %s\n",argv[1]);//显示当前连接服务端ip地址

	while(1){ //不停的获取用户输入

		memset(msg.data,0,sizeof(msg.data));//每次用户输入前,先把数据初始化
		memset(msg.secondBuf,0,sizeof(msg.secondBuf));
		msg.type = 0;
		putchar('>');//每次输入前,打印‘>’,等待输入 
		fflush(stdout);	

		gets(msg.data);//获取输入命令,cmd,存入mag.data中

		if(strlen(msg.data) == 0 ){//当输入为空
		
			continue;	//直接进入下一次循环,重新获取输入
		
		}else{
		
			ret_cmd_handler = cmd_handler(msg,c_fd);//根据输命令入,发送不同的数据给服务端
			
			if(ret_cmd_handler > IFRET){ //IFRET为宏,大于它,表示server返回client的结果不需要处理
			
				fflush(stdout);//冲刷缓冲区,是数据即时输出
				continue;//进入下一次循环	

			}
			
			if(ret_cmd_handler == -1){//非法指令
				
				printf("command not found\n");
				fflush(stdout);//冲刷缓冲区,是数据即时输出
				continue;//进入下一次循环

			}else{

				server_message_handler(msg,c_fd);//服务端返回信息处理
			
			}
		
		}

	}


	return 0;


}



  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 非常感谢,我可以为您说明基于Linux的103协议的代码。103协议的代码是基于Linux的操作系统构建的,它是一种可以用来传输数据的标准网络协议,它允许客户端和服务器之间进行安全可靠的数据传输。它使用TCP/IP协议进行数据传输,可以支持多种不同的网络服务,如FTP,SMTP,HTTP,SSH等。它还支持多种数据类型,如文本,图像,视频和音频等。 ### 回答2: 基于Linux的103协议代码是一种用于电力系统通信的协议。它基于Linux操作系统进行开发,旨在实现电力系统之间的数据交换和远程控制。 103协议代码的实现包括以下几个方面: 1. 数据通信:代码中实现了与电力设备、终端和控制中心之间的数据通信。通过使用Linux提供的网络编程接口,实现数据的传输和接收。协议代码使用了TCP/IP协议进行数据传输,确保数据的可靠性和安全性。 2. 远程控制:代码实现了从控制中心对电力设备进行远程控制的功能。通过协议定义的控制指令,可以对电力设备进行启动、停止、切换等操作。代码中使用了Linux提供的系统级函数,实现对设备的控制。 3. 数据解析:协议代码对接收到的数据进行解析,提取出有用的信息。通过定义协议的数据结构和解析函数,将原始数据解析为可读的格式,方便后续的处理和分析。 4. 异常处理:协议代码实现了异常情况的处理机制。当网络连接断开或收到异常数据时,代码能够进行相应的处理,例如重新建立连接或向控制中心报告异常情况。 5. 安全功能:协议代码考虑了数据的安全性。通过使用加密算法对数据进行加密和解密,防止数据被非法篡改。同时,代码也实现了身份验证功能,确保只有经过授权的设备和用户可以进行通信和控制操作。 总之,基于Linux的103协议代码实现了电力系统之间的数据通信和远程控制。它通过使用Linux提供的网络编程接口和系统级函数,实现了数据的传输、解析和控制。代码还考虑了数据的安全性和异常情况处理,为电力系统的运行和管理提供了可靠的支持。 ### 回答3: 基于Linux的103协议代码用于实现与电力系统通信的功能。103协议是一种通信协议,用于电力系统中的自动化设备之间的数据交换。下面是一个简单的基于Linux的103协议代码示例: ```c #include <stdio.h> #include <stdbool.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define SERVER_PORT 2404 #define BUFFER_SIZE 1024 int main() { int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len; char buffer[BUFFER_SIZE]; // 创建socket server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("Failed to create socket"); return -1; } // 绑定地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("Failed to bind address"); return -1; } // 监听端口 if (listen(server_fd, 5) < 0) { perror("Failed to listen port"); return -1; } printf("Waiting for client connection...\n"); while (true) { // 接受客户端连接 client_len = sizeof(client_addr); client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd < 0) { perror("Failed to accept client connection"); return -1; } printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 接收数据 int bytesRead = read(client_fd, buffer, sizeof(buffer)); if (bytesRead < 0) { perror("Failed to read data"); return -1; } printf("Received data from client: %s\n", buffer); // 发送响应 char response[] = "Hello, client!"; if (write(client_fd, response, sizeof(response)) < 0) { perror("Failed to send response"); return -1; } // 关闭连接 close(client_fd); } // 关闭服务器socket close(server_fd); return 0; } ``` 这段代码实现了一个简单的基于Linux的103协议的服务器程序。它通过创建socket、绑定端口、监听端口,使得服务器可以接受客户端的连接。一旦有客户端连接成功,服务器就通过read函数接收客户端发送的数据,并通过write函数向客户端发送响应。然后,服务器关闭与该客户端的连接,并等待下一个客户端连接。这个示例只是一个简单的实现,实际应用中可能需要进行更多的错误处理和数据处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elaot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值