libevent实践11:主动模式的FTP服务器

这篇具有很好参考价值的文章主要介绍了libevent实践11:主动模式的FTP服务器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

代码仅供参考,如用于正式项目,根据实际添加并发处理代码。代码使用的libevent库和使用的CMakeLists.txt文件参考本系列博客前面的篇章。

简介

 在本次测试中实现的命令:

CWD:切换到指定的目录

USER:登录用户

CDUP:回到上一层目录

PORT:主动传输方式

LIST:获取目录列表

RETR:请求服务器想客户端发送指定文件

STOR:客户端向服务器上传指定文件

这些命令的参数在下面的表格中都有详细说明。

表10-1 常用的FTP访问控制命令 

libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server

表10-2 传输参数命令

libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server

表10-3 常用的服务命令

libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server

表10-4 不同应答码的含义 libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server

根据表10-4中对应答码含义的规定,表10-5按照功能划分列举了常用的FTP应答码并介绍了其具体含义。 

表10-5 常用的FTP应答码及其含义说明 libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server

 测试代码

#include <sys/types.h>
#include <event2/event-config.h>
#include <event2/listener.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
,__FILE__,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
 
#define _DEBUG_PRINT
#ifdef _DEBUG_PRINT
#define DEBUG_PRINT(format,...)	printf(format,##__VA_ARGS__)	
#else
#define DEBUG_PRINT(format,...)
#endif

//sudo ip addr add 192.168.0.12/24 dev ens33
//添加新的IP地址用于测试

struct private_base_data{
    struct event_base *base;
    struct evconnlistener *control_listener;    
    struct sockaddr_in control_server_addr;

    int current_user_count;

};

struct private_client_data{
    struct private_base_data* pbd;
    struct bufferevent *bev;
    int client_socket;
    char buf[4096 + 1];
    int len;
    char remote_ips[20];
    int remote_port;
    struct bufferevent *list_bev;
    char root_dir[1024];
    char current_dir[1024];

    struct bufferevent *stor_bev;
    FILE *stor_fp;

    struct bufferevent *retr_bev;
    FILE *retr_fp;    
};

void event_cb(struct bufferevent *bev, short what, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;

    DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
        ((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
        ((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
        ((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
        ((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
        ((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
        ((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
        );
    if(bev != pcd->list_bev){
        DEBUG_INFO("listbev error");
    }
    if(what & BEV_EVENT_EOF){
        bufferevent_free(bev);
        pcd->list_bev = NULL;
    }else if(what == BEV_EVENT_CONNECTED){
        DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
    }else
    {
        bufferevent_free(bev);
        pcd->list_bev = NULL;
    } 
}

void write_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    DEBUG_INFO("write_cb");
    if(bev != pcd->list_bev){
        DEBUG_INFO("pcd->remote_host error");
    }
    //bufferevent_write(pcd->remote_host, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
    
    if(bev == pcd->list_bev){
        DEBUG_INFO("list close");
        write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
        bufferevent_free(pcd->list_bev);
        pcd->list_bev = NULL;
        return;
    }
    DEBUG_INFO("bev error");
    return;
}

void read_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    int len;
    DEBUG_INFO("readcb %d",pcd->client_socket);
    if(bev == pcd->stor_bev && pcd->stor_fp != NULL){
        while (1) {
            len = bufferevent_read(bev, pcd->buf, sizeof(pcd->buf) - 1);
            if (len <= 0) {
                return;
            }
            pcd->buf[pcd->len] = '\0';
            fwrite(pcd->buf, 1, len, pcd->stor_fp);
        }
        return;
    }
    pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
    pcd->buf[pcd->len] = '\0';
    DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);
    return;
}

void stor_event_cb(struct bufferevent *bev, short what, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;

    DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
        ((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
        ((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
        ((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
        ((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
        ((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
        ((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
        );

    if(bev != pcd->stor_bev){
        DEBUG_INFO("bev error");
    }
    if(what & BEV_EVENT_EOF){
        bufferevent_free(bev);
        write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
        pcd->stor_bev = NULL;
        if(pcd->stor_fp != NULL){
            DEBUG_INFO("close file");
            fclose(pcd->stor_fp);
            pcd->stor_fp = NULL;
        }
    }else if(what == BEV_EVENT_CONNECTED){
        DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
    }else
    {
        DEBUG_INFO("uknown error");
        bufferevent_free(bev);
        write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
        pcd->stor_bev = NULL;
        if(pcd->stor_fp != NULL){
            DEBUG_INFO("close file");
            fclose(pcd->stor_fp);
            pcd->stor_fp = NULL;
        }
    } 
}

void stor_write_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    DEBUG_INFO("write_cb");
    if(bev != pcd->stor_bev){
        DEBUG_INFO("pcd->remote_host error");
    }
    //bufferevent_write(pcd->remote_host, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
    
    if(bev == pcd->stor_bev){
        DEBUG_INFO("stor write");

        write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
        bufferevent_free(pcd->stor_bev);
        pcd->stor_bev = NULL;
        if(pcd->stor_fp != NULL){
            DEBUG_INFO("close file");
            fclose(pcd->stor_fp);
            pcd->stor_fp = NULL;
        }
        return;
    }
    DEBUG_INFO("bev error");
    bufferevent_free(bev);
    return;
}

void stor_read_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    int len;
    DEBUG_INFO("readcb %d",pcd->client_socket);
    char *buf = NULL;
    if(bev == pcd->stor_bev && pcd->stor_fp != NULL){
        buf = malloc(1024);
        while (1) {
            len = bufferevent_read(bev, buf, 1024);
            if (len <= 0) {
                free(buf);
                return;
            }
            buf[len] = '\0';
            DEBUG_INFO("buf = %s",buf);
            fwrite(buf, 1, len, pcd->stor_fp);
        }
        free(buf);
        return;
    }else{
        if(pcd->stor_bev != NULL){
            bufferevent_free(pcd->stor_bev);
            pcd->stor_bev = NULL;
        }
        if(pcd->stor_fp != NULL){
            fclose(pcd->stor_fp);
            pcd->stor_fp = NULL;
        }
    }
    return;
}

void retr_event_cb(struct bufferevent *bev, short what, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;

    DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
        ((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
        ((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
        ((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
        ((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
        ((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
        ((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
        );
    if(bev != pcd->retr_bev){
        DEBUG_INFO("bev error");
    }
    if(what == BEV_EVENT_CONNECTED){
        DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
        return;
    }
    //if(what & BEV_EVENT_EOF)
    {
        bufferevent_free(pcd->retr_bev);
        //write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
        pcd->retr_bev = NULL;
        if(pcd->retr_fp != NULL){
            DEBUG_INFO("close retr file");
            fclose(pcd->retr_fp);
            pcd->retr_fp = NULL;
        }
    }
}

void retr_write_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    int len = 0;
    char *buf = NULL;
    int send_len = 0;
    if(bev == pcd->retr_bev){
        DEBUG_INFO("retr write");
        if(pcd->retr_fp == NULL){
            DEBUG_INFO("file is not open");
            return;
        }
        buf = malloc(1024 + 1);
        do{
            len = fread(buf, 1, 1024, pcd->retr_fp);
            if (len <= 0) {
                DEBUG_INFO("retr read finish");
                //bufferevent_flush(pcd->retr_bev,EV_WRITE,BEV_FLUSH);
                // bufferevent_free(pcd->retr_bev);
                // pcd->retr_bev = NULL;
                // fclose(pcd->retr_fp);
                // pcd->retr_fp = NULL;
                free(buf);
                write(pcd->client_socket, "226 Transfer comlete", sizeof("226 Transfer comlete"));
                return;
            }
            send_len += len;
            buf[len] = '\0';
            DEBUG_INFO("buf = %s,len = %d", buf, len);
            DEBUG_INFO("send_len = %d", send_len);
            bufferevent_write(pcd->retr_bev, buf, len);
        }while(1);
        free(buf);
    }
    DEBUG_INFO("bev error");
    bufferevent_free(bev);
    return;
}
void retr_read_cb(struct bufferevent *bev, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    DEBUG_INFO("readcb %d",pcd->client_socket);
    pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
    pcd->buf[pcd->len] = '\0';
    DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);
    return;
}
struct bufferevent * connect_to_remote_port(struct private_client_data *pcd,int type){
    struct sockaddr_in sin;
    struct bufferevent *bev;
    if(type == 0){//list
        if(pcd->list_bev != NULL){
            bufferevent_free(pcd->list_bev);
            pcd->list_bev = NULL;
        }
    }else if(type == 1){//stor
        if(pcd->stor_bev != NULL){
            bufferevent_free(pcd->stor_bev);
            pcd->stor_bev = NULL;
        }
    }else if(type == 2){
        if(pcd->retr_bev != NULL){
            bufferevent_free(pcd->retr_bev);
            pcd->retr_bev = NULL;
        }
    }else{
        DEBUG_INFO("unknown type %d",type);
        exit(0);
    }
    bev = bufferevent_socket_new(pcd->pbd->base,
                                 -1, BEV_OPT_CLOSE_ON_FREE);
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(pcd->remote_port);
    evutil_inet_pton(AF_INET, pcd->remote_ips, &sin.sin_addr.s_addr);

    if(type == 0){
        DEBUG_INFO("list");

        bufferevent_setcb(bev, read_cb, write_cb, event_cb, pcd);
        bufferevent_enable(bev, EV_READ | EV_WRITE);
    }else if(type == 1){
        DEBUG_INFO("stor");

        bufferevent_setcb(bev, stor_read_cb, stor_write_cb, stor_event_cb, pcd);
        bufferevent_enable(bev, EV_READ | EV_WRITE);
    }else if(type == 2){
        DEBUG_INFO("retr");
        bufferevent_setcb(bev, retr_read_cb, retr_write_cb, retr_event_cb, pcd);
        bufferevent_enable(bev, EV_READ|EV_WRITE);
    }else{
        bufferevent_free(bev);
        DEBUG_INFO("unknown type %d",type);
        exit(0);
    }
	
	

    struct timeval t = {1, 0};
	bufferevent_set_timeouts(bev, &t, 0);
    bufferevent_socket_connect(bev, (struct sockaddr*)&sin, sizeof(sin));
    DEBUG_INFO("connected to %s:%d finish",pcd->remote_ips,pcd->remote_port);

    if(type == 0){
        //list
        pcd->list_bev = bev;
    }else if(type == 1){
        //stor
        pcd->stor_bev = bev;
    }else if(type == 2){
        //retr
        pcd->retr_bev = bev;
    }else{
        bev = NULL;
        DEBUG_INFO("error");
        DEBUG_INFO("unknown type %d",type);
        exit(0);
    }
    return bev;
}

char * get_list_data(char* _path,int *_datasize) {
    char* _cmd = "ls -l ";
	char cmd[1024] = "ls -l ";
    char *pnew;
    int current_len = 0;
    int len;
    int size = 1024*1024;
    char* buf ;
	snprintf(cmd,1024,"%s%s",_cmd,_path);
    DEBUG_INFO("cmd = %s",cmd);
	FILE *f = popen(cmd, "r");
	if (!f){
        return NULL;
    }
    
	buf = malloc(size + 2);
    
	while (1) {
		len = fread(&buf[current_len], 1, size - 1 - current_len, f);
		if (len <= 0){
            break;
        }
        current_len += len;
		buf[current_len] = '\0';
        if(current_len >= size - 1){
            pnew = realloc(buf,current_len+size);
            if(pnew != NULL){
                size += current_len;
                buf = pnew;
            }else{
                DEBUG_INFO("realloc fail");
                break;
            }            
        }
	}
	pclose(f);
    buf[current_len] = '\r';
    buf[current_len + 1] = '\n';

    *_datasize = current_len + 2;
	return buf;
}

void client_read_bufferevent_data_cb(struct bufferevent *bev, void *ctx){
    // char *pret;
    int i = 0;
    int nums[20];
    int index = 0;
    int temp = 0;
    char* path = NULL;
    int path_len = 0;
    struct private_client_data *pcd = (struct private_client_data *)ctx;
    DEBUG_INFO("readcb %d",pcd->client_socket);
    pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
    pcd->buf[pcd->len] = '\0';
    DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);

    if(pcd->len == 0){
        return;
    }

    
    if(pcd->buf[0] == 'U'){
        if(strncmp(&pcd->buf[0],"USER",4) == 0){
            DEBUG_INFO("user name = %s",&pcd->buf[5]);
            write(pcd->client_socket,"230 Login successsful.\r\n",sizeof("230 Login successsful.\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }

    if(pcd->buf[0] == 'F'){
        if(strncmp(&pcd->buf[0],"FEAT",4) == 0){
            DEBUG_INFO("FEAT = %s",&pcd->buf[5]);
            //write(pcd->client_socket,"230 Login successsful.\r\n",sizeof("230 Login successsful.\r\n"));
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }

    if(pcd->buf[0] == 'P'){
        if(strncmp(&pcd->buf[0],"PORT",4) == 0){
            DEBUG_INFO("PORT = %s",&pcd->buf[5]);

            //获取IP地址和端口号
            
            for (i = 5; i < pcd->len; i++) {
                if (pcd->buf[i] == ',' || pcd->buf[i] == '\r') {
                    nums[index] = temp;
                    index++;
                    temp = 0;
                    continue;
                }
                temp = (pcd->buf[i] - 0x30) + temp*10;
            }
            for(i = 0; i < index;i++){
                printf("%d,",nums[i]);
            }
            printf("\n");
            if (index != 6) {
                write(pcd->client_socket,("501 Syntax error in parameters or arguments."),
                    sizeof("501 Syntax error in parameters or arguments."));
                return;
            }
            memset(pcd->remote_ips,0,sizeof(pcd->remote_ips));
            snprintf(pcd->remote_ips,sizeof(pcd->remote_ips),"%d.%d.%d.%d",nums[0],nums[1],nums[2],nums[3]);
            pcd->remote_port = ((uint16_t)nums[4] << 8) + (uint16_t)nums[5];
            DEBUG_INFO("ips = %s,port = %d",pcd->remote_ips,pcd->remote_port);

            write(pcd->client_socket,"200 PORT command success.\r\n",sizeof("200 PORT command success.\r\n")); 
            return;
        }

        if(strncmp(&pcd->buf[0],"PASS",4) == 0){
            DEBUG_INFO("PORT = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }

        if(strncmp(&pcd->buf[0],"PWD",3) == 0){
            DEBUG_INFO("PWD = %s",&pcd->buf[4]);
            DEBUG_INFO("pcd->current_dir = %s ",pcd->current_dir);

            if(strlen(pcd->current_dir) == 1){
                write(pcd->client_socket,"257 \"/\" is current dir.\r\n",sizeof("230 Login successsful.\r\n"));
                return;
            }
            path_len = 100 + strlen(pcd->current_dir);
            path = malloc(100 + strlen(pcd->current_dir));
            snprintf(path,path_len,"257 \"%s/\" is current dir.\r\n",pcd->current_dir);
            // write(pcd->client_socket,"257 \"/\" is current dir.\r\n",sizeof("230 Login successsful.\r\n"));
            write(pcd->client_socket,path,strlen(path));
            DEBUG_INFO("path = %s",path);
            free(path);
            return;
        }

        if(strncmp(&pcd->buf[0],"PASV",4) == 0){
            DEBUG_INFO("PASV = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }

    

    if(pcd->buf[0] == 'L'){
        if(strncmp(&pcd->buf[0],"LIST",4) == 0){
            DEBUG_INFO("LIST = %s",&pcd->buf[5]);
            connect_to_remote_port(pcd,0);
            path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + 1;
            path = malloc(path_len);
            snprintf(path,path_len,"%s%s",pcd->root_dir,pcd->current_dir);
            path[path_len] = '\0';
            DEBUG_INFO("path = %s",path);
            int datasize;
            char* listdata = get_list_data(path,&datasize);
            free(path);
            char *pret = "150 Here coms the directory listing.\r\n";
            write(pcd->client_socket,pret,strlen(pret));
            DEBUG_INFO("datasize = %d",datasize);
            if(pcd->list_bev == NULL){
                DEBUG_INFO("remote host not connected");
            }
            // bufferevent_write(pcd->remote_host, 
            // "150 Here coms the directory listing.\r\n", 
            // sizeof("150 Here coms the directory listing.\r\n"));
            DEBUG_INFO("listdata = %s",listdata);
            if(datasize > 0 && listdata != NULL){
                int ret = bufferevent_write(pcd->list_bev, listdata, datasize);   
                DEBUG_INFO("ret = %d,datasize = %d",ret,datasize);             
            }
            if(listdata != NULL){
                free(listdata);
            }
            DEBUG_INFO("process LIST finish");
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'C'){
        if(strncmp(&pcd->buf[0],"CWD",3) == 0){
            DEBUG_INFO("CWD = %s",&pcd->buf[4]);
            path_len = strlen(&pcd->buf[4]);
            path = malloc(path_len + 1);
            memset(path,0,path_len);
            memcpy(path,&pcd->buf[4],path_len);
            path[path_len] = '\0';
            while(1){
                if(path_len == 0){
                    break;
                }
                if(path[path_len - 1] == '\r' || path[path_len - 1] == '\n' || path[path_len - 1] == '\0'){
                    path[path_len - 1] = '\0';
                    path_len--;
                }else{
                    break;
                }                
            }
            DEBUG_INFO("path: %s", path);
            if(path_len > 0){
                memcpy(pcd->current_dir,path,path_len);
                pcd->current_dir[path_len] = '\0';
                write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            }else{
                write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
            }
            free(path);
            return;
        }
        if(strncmp(&pcd->buf[0],"CDUP",4) == 0){
            DEBUG_INFO("CDUP = %s",&pcd->buf[5]);
            path_len = strlen(pcd->current_dir);
            while(path_len > 1){
                if(pcd->current_dir[path_len - 1] != '/'){
                    pcd->current_dir[path_len - 1] = '\0';
                    path_len--;
                }else{
                    pcd->current_dir[path_len - 1] = '\0';
                    path_len--;
                    break;
                }
            }
            DEBUG_INFO("pcd->current_dir = %s",pcd->current_dir);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'D'){
        if(strncmp(&pcd->buf[0],"DELE",4) == 0){
            DEBUG_INFO("DELE = %s",&pcd->buf[4]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'M'){
        if(strncmp(&pcd->buf[0],"MKD",3) == 0){
            DEBUG_INFO("MKD = %s",&pcd->buf[4]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'R'){
        if(strncmp(&pcd->buf[0],"RMD",3) == 0){
            DEBUG_INFO("RMD = %s",&pcd->buf[4]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        if(strncmp(&pcd->buf[0],"RETR",4) == 0){
            DEBUG_INFO("RETR = %s",&pcd->buf[5]);

            path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + strlen(&pcd->buf[5]);
            path = malloc(path_len);
            memset(path,0,path_len);
            snprintf(path,path_len,"%s%s/%s",pcd->root_dir,pcd->current_dir,&pcd->buf[5]);
            path[path_len] = '\0';
            do{
                if(path_len == 0){
                    break;
                }
                if(path[path_len - 1] == 0x0a || path[path_len - 1] == 0x0d || path[path_len - 1] == 0){
                    path[path_len - 1] = '\0';
                    path_len--;
                }else{
                    DEBUG_INFO("path[%d]=%02x",path_len,path[path_len - 1]);
                    break;
                }
            }while(1);
            DEBUG_INFO("path = %s",path);

            for(i = 0;i < path_len;i++){
                printf("%02x,",path[i]);
            }
            printf("\n");

            if(pcd->retr_fp != NULL){
                fclose(pcd->retr_fp);
                pcd->retr_fp = NULL;
            }

            pcd->retr_fp = fopen(path,"r");
            if(pcd->retr_fp != NULL){
                DEBUG_INFO("open %s ok\r\n",path);
                connect_to_remote_port(pcd,2);
                write(pcd->client_socket,"150 File OK.\r\n",strlen("150 File OK.\r\n"));
                char*buf = malloc(4096);
                while(1){
                    int read_len = fread(buf,1,4096,pcd->retr_fp);
                    if(read_len <= 0){
                        break;
                    }
                    bufferevent_write(pcd->retr_bev,buf,read_len);
                }
                write(pcd->client_socket,"226 Transfer complete\r\n",sizeof("226 Transfer complete\r\n"));
                //bufferevent_trigger(pcd->retr_bev, EV_WRITE, 0);
                free(buf);
            }else{
                DEBUG_INFO("open %s error\r\n",path);
                write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
            }
            free(path);
            if(pcd->retr_bev == NULL){
                DEBUG_INFO("retr_bev remote host not connected");
            }
            DEBUG_INFO("process RETR finish");
            return;
        }
        if(strncmp(&pcd->buf[0],"REST",4) == 0){
            DEBUG_INFO("REST = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'S'){
        if(strncmp(&pcd->buf[0],"SIZE",4) == 0){
            DEBUG_INFO("SIZE = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        if(strncmp(&pcd->buf[0],"STOR",4) == 0){
            DEBUG_INFO("STOR = %s",&pcd->buf[5]);

            path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + strlen(&pcd->buf[5]);
            path = malloc(path_len + 1);
            snprintf(path,path_len,"%s%s/%s",pcd->root_dir,pcd->current_dir,&pcd->buf[5]);
            path[path_len] = '\0';
            do{
                if(path_len == 0){
                    break;
                }
                if(path[path_len - 1] == 0x0a || path[path_len - 1] == 0x0d || path[path_len - 1] == 0){
                    path[path_len - 1] = '\0';
                    path_len--;
                }else{
                    DEBUG_INFO("path[%d]=%02x",path_len,path[path_len - 1]);
                    break;
                }
            }while(1);
            DEBUG_INFO("path = %s",path);

            for(i = 0;i < path_len;i++){
                printf("%02x,",path[i]);
            }
            printf("\n");

            if(pcd->stor_fp != NULL){
                fclose(pcd->stor_fp);
                pcd->stor_fp = NULL;
            }

            pcd->stor_fp = fopen(path,"wb");
            if(pcd->stor_fp){
                connect_to_remote_port(pcd,1);
                write(pcd->client_socket,"125 File OK.\r\n",strlen("125 File OK.\r\n"));
                bufferevent_trigger(pcd->stor_bev, EV_READ, 0);
            }else{
                write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
            }
            free(path);
            if(pcd->stor_bev == NULL){
                DEBUG_INFO("remote host not connected");
            }
            DEBUG_INFO("process STOR finish");
            return;
        }
        if(strncmp(&pcd->buf[0],"SYST",4) == 0){
            DEBUG_INFO("SYST = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    if(pcd->buf[0] == 'T'){
        if(strncmp(&pcd->buf[0],"TYPE",4) == 0){
            DEBUG_INFO("TYPE = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
    }
    if(pcd->buf[0] == 'Q'){
        if(strncmp(&pcd->buf[0],"QUIT",4) == 0){
            DEBUG_INFO("QUIT = %s",&pcd->buf[5]);
            write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
            return;
        }
        DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
    }
    DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);

    

}
void client_event_bufferevent_event_cb(struct bufferevent *bev, short what, void *ctx){
    struct private_client_data *pcd = (struct private_client_data *)ctx;

    DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
        ((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
        ((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
        ((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
        ((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
        ((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
        ((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
        );
    pcd->pbd->current_user_count--;
    if(what & BEV_EVENT_EOF){
        close(pcd->client_socket);
        bufferevent_free(bev);
        if(pcd->list_bev != NULL){
            bufferevent_free(pcd->list_bev);
            pcd->list_bev = NULL;
        }
        if(pcd->stor_bev != NULL){
            bufferevent_free(pcd->stor_bev);
            pcd->stor_bev = NULL;
        }
        if(pcd->retr_bev != NULL){
            bufferevent_free(pcd->retr_bev);
            pcd->retr_bev = NULL;
        }
        if(pcd->stor_fp != NULL){
            fclose(pcd->stor_fp);
            pcd->stor_fp = NULL;
        }
        if(pcd->retr_fp != NULL){
            fclose(pcd->retr_fp);
            pcd->retr_fp = NULL;
        }
        free(pcd);
    }else{
        DEBUG_INFO("未知错误");
        //即便是未知错误,也关闭连接并释放资源比较好吧
        close(pcd->client_socket);
        bufferevent_free(bev);
        free(pcd);
    } 
}

void server_evconnlistener_cb(struct evconnlistener *listener, evutil_socket_t new_client, struct sockaddr *addr, int socklen, void *arg){
    int options = 0;
    struct private_base_data *pbd = (struct private_base_data*)arg;
    struct sockaddr_in *paddr = (struct sockaddr_in *)addr;
    DEBUG_INFO("a new client fd = %d",new_client);

    DEBUG_INFO("ip = %s,port = %d",inet_ntoa(paddr->sin_addr),ntohs(paddr->sin_port));
    options |= BEV_OPT_CLOSE_ON_FREE;
    struct bufferevent *bev = bufferevent_socket_new(pbd->base,new_client, options);
    if(bev == NULL){
        DEBUG_INFO("bufferevent_socket_new error");
        exit(-1);
    }
    pbd->current_user_count++;
    struct private_client_data * pcd = (struct private_client_data*)malloc(sizeof(struct private_client_data));
    memset(pcd, 0, sizeof(struct private_client_data));
    pcd->root_dir[0]='.';
    pcd->current_dir[0]='/';

    pcd->client_socket = new_client;
    pcd->pbd = pbd;
    pcd->list_bev = NULL;
    write(new_client,"220 Welcome to XFtpServer\r\n",sizeof("220 Welcome to XFtpServer\r\n"));
    bufferevent_setcb(bev, 
                    client_read_bufferevent_data_cb, 
                    NULL,
                    client_event_bufferevent_event_cb,
                    pcd);
    bufferevent_enable(bev,EV_READ);
}

int main(int argc, char **argv)
{
    struct private_base_data *pbd  = (struct private_base_data*)malloc(sizeof(struct private_base_data));
    if(pbd == NULL){
        DEBUG_INFO("malloc error");
        return 0;
    }
    pbd->current_user_count = 0;
    pbd->control_server_addr.sin_family = AF_INET;
    pbd->control_server_addr.sin_addr.s_addr = INADDR_ANY;
    // pbd->control_server_addr.sin_addr.s_addr = inet_addr("192.168.0.12");
    pbd->control_server_addr.sin_port = htons(6021);

    pbd->base = event_base_new();
    if(pbd->base == NULL){
        DEBUG_INFO("event_base_new error");
        return 0;
    }
    pbd->control_listener = evconnlistener_new_bind(
                                    pbd->base,
                                    server_evconnlistener_cb,
                                    pbd,
                                    LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
                                    5,
                                    (struct sockaddr*)&pbd->control_server_addr,
                                    sizeof(pbd->control_server_addr));
    if(pbd->control_listener == NULL){
        DEBUG_INFO("evconnlistener_new_bind error");
        return 0;
    }

    event_base_dispatch(pbd->base);
    evconnlistener_free(pbd->control_listener);
    event_base_free(pbd->base);
    free(pbd);
    DEBUG_INFO("bye bye");
    return 0;
}

测试 

libevent实践11:主动模式的FTP服务器,linux 应用,libevent,tftp server文章来源地址https://www.toymoban.com/news/detail-578115.html

 小结

到了这里,关于libevent实践11:主动模式的FTP服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TCP服务器的演变过程:C++使用libevent库开发服务器程序

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。 在上一章节介绍了如何使用epoll构建reactor网络模型开发高效的服务器,有了上一节的基础,本节将介绍

    2024年01月23日
    浏览(39)
  • Ftp服务器、 Samba服务器、NFS服务器的区别

    根据使用的方式来看,可以分为3种类别的文件服务器:ftp服务器(ftp/tftp)、 Samba服务器、NFS服务器。ftp的客户可以是任意平台,samba是专门针对windows客户,而NFS则是面向linux/unix用户的。下面是三种服务器的对比情况: 各个服务器的配置 NFS服务器: NFS是SUN Microsystem公司开发

    2024年02月03日
    浏览(41)
  • ubuntu服务器配置ftp服务

    目录  一、安装vsftpd 二、配置vsftpd 三、设置安全组 四、客户端测试 SFTP服务的配置看主页的下一篇博客:ubuntu云服务器配置SFTP服务-CSDN博客 需求:配置ftp服务用于在windows电脑上直接浏览、下载、上传ubuntu服务器上的文件,用于文件共享,方便实用 效果:用户打开windows资源

    2024年02月13日
    浏览(37)
  • 监控 FTP 服务器

    文件传输协议 (FTP) 用于在 TCP/IP 网络中的服务器和客户端之间传输文件,它是一种标准协议,广泛用于在各个垂直行业的组织之间从集中位置存储和分发数据。FTP协议的其他一些安全版本如下: SSH 文件传输协议 (SFTP) :它使用SSH(安全外壳协议)加密传输的命令和数据

    2024年02月11日
    浏览(33)
  • FTP服务器

    FTP(File Transfer Protocol) 是相当古老的传输协议之一,它最主要的功能是在服务器与客户端之间进行文件的传输。这个古老的协议使用的是明文传输的方式,且过去有相当多的安全危机历史。为了更安全的使用FTP协议,主要介绍较为安全的vsftpd这个软件。 下面的图片来自百度百

    2024年02月09日
    浏览(32)
  • FTP文件传输服务器

    目录 一、FTP协议两种工作模式 二、FTP数据两种传输模式 三、FTP用户分类 四、VSFTP配置案例 4.1匿名开放模式 4.2本地用户模式 4.3虚拟用户模式 五、实验总结 一、FTP 协议两种工作模式 主动模式: 1、客户端主动向ftp服务器发送控制连接,三次握手控制连接建立成功(密码认证

    2024年02月10日
    浏览(39)
  • 匿名访问ftp服务器

    我们启用ftp服务,想要上传或者下载远程文件时,存在着匿名访问ftp服务器问题。 通常,我们使用网页直接进入ftp服务器时,可以选择以匿名登录的方式访问ftp服务器,此时一般不会出现需要填写用户名和密码的问题,并且在网页状态下,我们不能上传文件。 比如,进入到

    2024年02月04日
    浏览(55)
  • 有人USR-M100边缘主动上报电流数据到TCP服务器

    前两天跟强哥配置了有人的USR-M100模块,实现了采集的电流信号主动上报服务器的功能,昨天去第一污水厂配置了1台、第二污水厂配置了5台、第三污水厂配置了1台,能够将数据上报到甲方的云平台,这里记录一下配置过程,方便以后的师弟们学习,能够去现场完成配置工作

    2024年02月08日
    浏览(36)
  • 在IIS服务器下搭建FTP服务

    为了实现文件局域网或远程共享与访问,在IIS服务器手动搭建一个FTP Server共享服务。 基于Windows 11 操作系统。 一、安装FTP服务 打开“控制面板”-双击“程序和功能”项,如下图:  在“程序和功能”窗口,点击左边栏“启用或关闭Windows 功能”选项,展开“Internet Informati

    2024年02月04日
    浏览(52)
  • 【Linux】FTP文件服务器

    FTP (File transfer protocol) 是TCP/IP 协议组中的协议之一。他最主要的功能是在服务器与客户端之间进行文件的传输。FTP就是实现两台计算机之间的拷贝,从远程计算机拷贝文件至自己的计算机上,称之为“下载 (download)”文件。将文件从自己计算机中拷贝至远程计算机上,则称

    2024年02月10日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包