⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpclient.c

📁 Linux下C实现的ftp客户端代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* achieve base function of ftp client.Maybe some bugs are in the file,
 *  if you know how to correct them,please tell me,thank you!
 *  All rights reserved.
 *  Author : xiaoleng
 *  Email   : flylgh@163.com
 *  create time: 2008-11-1
 *
 *  实现FTP客户端基本功能,或者本实现有潜在错误,
 *  如果你知道如何改正,或者你有更好的建议,请通知我。
 *  对你无私的精神,我表示衷心的感谢!
 *  你可以随意发布、修改,但请别用于学习或者交流的其他
 *  用途! 
 *  作者: xiaoleng
 *  Email    : flylgh@163.com
 *  创建时间: 2008-11-1
 */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/time.h>#include <sys/select.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <dirent.h>

#include "common.h"
#include "ftpclient.h"
#include "debug.h"

#define FTP_RES_BUF_SIZE 2048

static char server_response[FTP_RES_BUF_SIZE];
static uint32 first_recv = TRUE;
static char server_ip[16];
static uint16  server_port;

static void setlock(int fd,int flag)
{
	int file_flag;

	file_flag = fcntl(fd,F_GETFD);
	if(flag == FALSE){
		fcntl(fd,F_SETFD, file_flag |O_NONBLOCK);
	}
	else{
		fcntl(fd,F_SETFD, file_flag & ~O_NONBLOCK);
	}
}

static void get_server_info(char *svr_ip,uint16 *server_port)
{
	char *p1,*p2;
	uint8 high_byte,low_byte;
	char tmp[FTP_RES_BUF_SIZE];
	int i = 4;


	p1 = strchr(server_response,'(')+1;	
	p2 = strchr(server_response,')')-1;
	strncpy(tmp,p1,p2-p1+1);
	tmp[p2-p1+1] = '\0';
	p1 = tmp;
	while(i){
		while(*p1 != ','){
			*svr_ip++ = *p1++;
		}
		if(i == 1){
			*svr_ip++ = '\0';
		}else{
			*svr_ip++ = '.';	
		}
		p1++;
		i--;			
	}

	p2 = p1;
	while(*p2 != ',') p2++;
	low_byte = atoi(++p2);
	*(--p2) = '\0';
	high_byte = atoi(p1);
	*server_port = (high_byte<<8) + low_byte;
}

static int send_cmd(char *cmd,ftpc_ctrl *ftp_info)
{
	if(send(ftp_info->ctrl_fd,cmd,strlen(cmd),0) == -1){
		return -1;
	}

	return 0;
}

static int recv_response(ftpc_ctrl *ftp_info)
{
	int n_read,retval;
	fd_set readfd;
	struct timeval timeout;
	char res_code[4]={0};

	FD_ZERO(&readfd);
	FD_SET(ftp_info->ctrl_fd,&readfd);
	timeout.tv_sec = FTPC_RECV_TIMEOUT;
	timeout.tv_usec = 0;

	retval = select(ftp_info->ctrl_fd + 1,&readfd,NULL,NULL,&timeout);
	if(retval == -1){
		return -1;
	}
	else if(retval == 0){
		debug_print("receive response from server time out!\n");
		return -1;
	}
	else{	
		n_read = recv(ftp_info->ctrl_fd,server_response,FTP_RES_BUF_SIZE,0);
		if((n_read==-1) || (n_read==0)){
			return -1;	
		}
		server_response[n_read-1] = '\0';
		server_response[n_read-2] = '\0';
	}
	strncpy(res_code,server_response,3);
	return atoi(res_code);
}

static int get_res_code(void)
{
	char buf[4] = {0};

	strncpy(buf,server_response,3);
	return atoi(buf);
}

static void ftpc_help(void)
{
	sprintf(server_response,
		"These commands below are surported:\n"
		 "%-10s %-10s %-10s %-10s %-10s\n"
		 "%-10s %-10s %-10s %-10s %-10s\n"
		 "%-10s %-10s %-10s				",
		 "ls","lcd","put","get","rmdir",
		 "mkdir","del","dir","quit","bye",
		 "pwd","localshow","help"
		);
}

static int go_passive(ftpc_ctrl *ftp_info)
{
	ftp_info->open_mode = MODE_PASSIVE;
	send_cmd("PASV\r\n",ftp_info);
	if(recv_response(ftp_info) != 227){
		return -1;
	}
	printf("%s\n",server_response);
	get_server_info(server_ip,&server_port);

	return 0;
}

static int deal_cmd_lcshow(void)
{
	char cur_dir[128],buf[80];
	int i = 0,len;
	int spare_dot = 80;
	DIR *dir;
	struct dirent *ptr;

	memset(server_response,0,sizeof(server_response));
	getcwd(cur_dir,sizeof(cur_dir));
	dir = opendir(cur_dir);
	while((ptr=readdir(dir)) != NULL){
		sprintf(buf,"[%s]  ",ptr->d_name);
		len = strlen(buf);
		if(spare_dot > len){
			strcat(server_response,buf);
			spare_dot -= len;
		}
		else{
			strcat(server_response,"\n");
			strcat(server_response,buf);
			spare_dot = 80-len;
		}
		i++;
	}
	closedir(dir);
	sprintf(buf,"\nTotal %d files at local",i);
	strcat(server_response,buf);	

	return 0;
}

static int deal_cmd_lcd(char *param,ftpc_ctrl *ftp_info)
{
	int retval;
	char cur_dir[128];

	getcwd(cur_dir,sizeof(cur_dir));
	if(*param == '\0'){
		sprintf(server_response,"now dir is [%s]",cur_dir);
		return 0;
	}
	
	retval = chdir(param);
	getcwd(cur_dir,sizeof(cur_dir));
	if(retval == 0){
		sprintf(server_response,"now dir is [%s]",cur_dir);
	}
	else{
		strcpy(server_response,"change directory error!");
	}

	return retval;
}

static int send_data(char *pdata,ftpc_ctrl *ftp_info,int n_send)
{
	int retval,maxfd;
	int n_data = 0;
	fd_set writefd;
	struct timeval timeout;
	struct sockaddr_in sa;

	if(first_recv == TRUE){
		first_recv = FALSE;
		if(ftp_info->open_mode == MODE_PASSIVE){
			sa.sin_family = AF_INET;
			sa.sin_port = htons(server_port);
			sa.sin_addr.s_addr = inet_addr(server_ip);
			ftp_info->data_fd = socket(AF_INET,SOCK_STREAM,0);
			connect(ftp_info->data_fd,(struct sockaddr *)&sa,sizeof(sa));
		}
	}

	if(n_send <= 0){
		return 0;
	}

	FD_ZERO(&writefd);
	FD_SET(ftp_info->data_fd,&writefd);
	timeout.tv_sec = FTPC_SEND_TIMEOUT;
	timeout.tv_usec = 0;
	maxfd = ftp_info->data_fd + 1;
	retval = select(maxfd,NULL,&writefd,NULL,&timeout);
	if(retval == -1){
		return -1;
	}
	else if(retval == 0){
		debug_print("send to server time out!\n");
		return -1;
	}
	else{
		if(FD_ISSET(ftp_info->data_fd,&writefd)){
			n_data = send(ftp_info->data_fd,pdata,n_send,0);
			if(n_data != n_send){
				printf("send data error!\n");
				return -1;
			}
		}
	}
	return n_data;
}

static int recv_data(char *pdata,ftpc_ctrl *ftp_info)
{
	int retval,maxfd;
	int n_res = 0;
	int n_data = 0;
	char res_buf[64];
	fd_set readfd;
	struct timeval timeout;
	struct sockaddr_in sa;

	if(first_recv == TRUE){
		first_recv = FALSE;
		if(ftp_info->open_mode == MODE_PASSIVE){
			sa.sin_family = AF_INET;
			sa.sin_port = htons(server_port);
			sa.sin_addr.s_addr = inet_addr(server_ip);
			ftp_info->data_fd = socket(AF_INET,SOCK_STREAM,0);
			connect(ftp_info->data_fd,(struct sockaddr *)&sa,sizeof(sa));
		}
	}

	FD_ZERO(&readfd);
	FD_SET(ftp_info->data_fd,&readfd);
	FD_SET(ftp_info->ctrl_fd,&readfd);	
	timeout.tv_sec = FTPC_RECV_TIMEOUT;
	timeout.tv_usec = 0;
	maxfd = ftp_info->data_fd > ftp_info->ctrl_fd ? ftp_info->data_fd : ftp_info->ctrl_fd;
	retval = select(maxfd+ 1,&readfd,NULL,NULL,&timeout);
	if(retval == -1){
		return -1;
	}
	else if(retval == 0){
		debug_print("receive data from server time out!\n");
		return -1;
	}
	else{
		if(FD_ISSET(ftp_info->data_fd,&readfd)){
			n_data = recv(ftp_info->data_fd,pdata,FTPC_MAX_DATA_LEN,0);
		}
		if(FD_ISSET(ftp_info->ctrl_fd,&readfd)){
			n_res = recv(ftp_info->ctrl_fd,server_response,sizeof(server_response),0);
			server_response[n_res-1] = '\0';
			server_response[n_res-2] = '\0';
			strcpy(res_buf,server_response);
			res_buf[3] = '\0';
			if(atoi(res_buf) == 226){
				return n_data;
			}
			else{
				return -1;
			}
		}
	}

	return n_data;
}

static int deal_cmd_cd(char *host_dir,ftpc_ctrl *ftp_info)
{
	char cmd_line[64];

	sprintf(cmd_line,"CWD %s\r\n",host_dir);
	if(send_cmd(cmd_line,ftp_info) == -1){
		return -1;
	}
	if(recv_response(ftp_info) != 250){
		return -1;
	}

	return 0;
}

static int deal_cmd_ls(ftpc_ctrl *ftp_info)
{
	int retval = 0;
	char file_list[2048];

	if(ftp_info->open_mode == MODE_PASSIVE){
		if(go_passive(ftp_info) == -1){
			return -1;
		}
	}

	if(send_cmd("LIST\r\n",ftp_info) == -1){
		return -1;
	}
	if(recv_response(ftp_info) != 150){
		return -1;
	}
	printf("%s\n",server_response);

	retval = recv_data(file_list ,ftp_info);
	file_list[retval] = '\0';
	printf("%s",file_list);
	
	first_recv = TRUE;
	close(ftp_info->data_fd);
	ftp_info->data_fd = -1;
	if(retval == -1){
		return -1;
	}
	
	return 0;
}

static int deal_cmd_mkdir(char *host_dir,ftpc_ctrl *ftp_info)
{
	char cmd_line[64];

	sprintf(cmd_line,"MKD %s\r\n",host_dir);
	if(send_cmd(cmd_line,ftp_info) == -1){
		return -1;
	}
	if(recv_response(ftp_info) != 257){
		return -1;
	}

	return 0;
}

static int deal_cmd_rmdir(char *host_dir,ftpc_ctrl *ftp_info)
{
	char cmd_line[64];

	sprintf(cmd_line,"RMD %s\r\n",host_dir);
	if(send_cmd(cmd_line,ftp_info) == -1){
		return -1;
	}
	if(recv_response(ftp_info) != 250){
		return -1;
	}

	return 0;
}

static int deal_cmd_del(char *filename,ftpc_ctrl *ftp_info)
{
	char cmd_line[64];

	sprintf(cmd_line,"DELE %s\r\n",filename);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -