网络通信三——1-13

// my_ftp_server.h
// 声明文件服务器的相关函数和常量

// 配置文件服务器的根目录
#define SERVER_ROOT_DIR "/home/vicliu/my_ftp_root"

// 响应客户端的list命令
// conn_fd  通过指定的连接套接字传递数据
void put_list_data_to_client(int conn_fd);

// 响应客户端的get命令
// conn_fd  连接套接字
// file     客户端待下载的文件名
void put_file_data_to_client(int conn_fd, char *file);

// 响应客户端的put命令
// conn_fd  连接套接字
// file     客户端待上传的文件名
void get_file_data_from_client(int conn_fd, char *file);
// my_ftp_client.h
// 文件服务器客户端的函数声明

// 客户端的list执行函数
void get_list_data_from_server(int sock_fd);

// 客户端的get执行函数
void get_file_data_from_server(int sock_fd, char *file);

// 客户端的put执行函数
void put_file_data_to_server(int sock_fd, char *file);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "my_header.h"
#include "my_ftp_client.h"

#define N 150

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        printf("usage : %s <server_ip> <server_port>\n", argv[0]);
        return 1;
    }
    
    int sock_fd = 0;
    struct sockaddr_in serveraddr;
    char buf[N] = {'\0'};
    
    struct data_package pkg;
    memset(&pkg, 0, sizeof(pkg));

    // 1.socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2.connect
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));
    connect(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    
    // 3.循环从键盘读入命令并构造数据结构体发送给服务器
    while(1)
    {
        // 3.1输入
        printf("my_ftp>");
        fgets(buf, N, stdin);
        buf[strlen(buf)-1] = '\0';  // 消除'\n'
        
        // 3.2构造结构体发送,并准备接收服务器发来的数据
        if(strncmp(buf, "list", 4) == 0)
        {
            pkg.cmd = CMD_LIST;
            send(sock_fd, &pkg, sizeof(pkg), 0);
            // 执行接收list数据
            get_list_data_from_server(sock_fd);
        }
        else if(strncmp(buf, "get ", 4) == 0)
        {
            pkg.cmd = CMD_GET;
            strcpy(pkg.filename, buf+4);
            send(sock_fd, &pkg, sizeof(pkg), 0);
            // 执行下载函数
            get_file_data_from_server(sock_fd, buf+4);
        }
        else if(strncmp(buf, "put ", 4) == 0)
        {
            pkg.cmd = CMD_PUT;
            strcpy(pkg.filename, buf+4);
            send(sock_fd, &pkg, sizeof(pkg), 0);
            // 执行上传函数
            put_file_data_to_server(sock_fd, buf+4);
        }
        else if(strncmp(buf, "quit", 4) == 0)
        {
            pkg.cmd = CMD_QUIT;
            send(sock_fd, &pkg, sizeof(pkg), 0);
            // 执行退出操作
            printf("client quit...\n");
        }
        else 
        {
        }
    }
    
    // 4.close
    close(sock_fd);   
    
    return 0;
}

// 客户端的list执行函数
void get_list_data_from_server(int sock_fd)
{
    struct data_package pkg;
       
    // 循环接收并打印,直到收到结束标志为止
    while(1)
    {
        memset(&pkg, 0, sizeof(pkg));
        
        recv(sock_fd, &pkg, sizeof(pkg), 0);
        
        if(pkg.cmd != CMD_LIST)
            continue;
            
        if(pkg.flag == DATA_END_FLAG)
            break;
            
        // 打印数据
        printf("%s\n", pkg.data);
    }
}

// 客户端的get执行函数
void get_file_data_from_server(int sock_fd, char *file)
{
    struct data_package pkg;
    int fd = 0;
    int n = 0;

    // 1.打开待下载文件,如果文件不存在则创建,如果文件存在,则将其数据截短为0
    fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    
    // 2.循环读取服务器发送来的数据,并写入文件
    while(1)
    {
        recv(sock_fd, &pkg, sizeof(pkg), 0);
        
        if(pkg.cmd != CMD_GET)
            continue;
        
        if(pkg.flag == DATA_END_FLAG)
            break;
        
        n = strlen(pkg.data);   // 实际数据长度
        write(fd, pkg.data, n);
    }
    
    // 3.关闭文件
    close(fd);
}

// 客户端的put执行函数
void put_file_data_to_server(int sock_fd, char *file)
{
    struct data_package pkg;
    int fd;

    // 1.判断待上传文件是否存在,如果不存在,则发送数据结束状态包
    if(access(file, F_OK) == -1)
    {
        memset(&pkg, 0, sizeof(pkg));
        pkg.cmd = CMD_PUT;
        pkg.flag = DATA_END_FLAG;
        
        send(sock_fd, &pkg, sizeof(pkg), 0);
        
        return;
    }
    
    // 2.打开文件
    fd = open(file, O_RDONLY);
    
    // 3.循环读取文件内容,发送给服务器
    memset(&pkg, 0, sizeof(pkg));
    pkg.cmd = CMD_PUT;
    pkg.flag = 0;
    while(read(fd, pkg.data, MAX_DATA_LEN-1) > 0)
    {
        send(sock_fd, &pkg, sizeof(pkg), 0);
        
        memset(pkg.data, 0, MAX_DATA_LEN);
    }   
    
    // 4.构建数据结束状态包发送给服务器
    memset(&pkg, 0, sizeof(pkg));
    pkg.cmd = CMD_PUT;
    pkg.flag = DATA_END_FLAG;
    send(sock_fd, &pkg, sizeof(pkg), 0);
    
    // 5.关闭文件
    close(fd);
}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <dirent.h>
#include "my_header.h"
#include "my_ftp_server.h"

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        printf("usage : %s <server_ip> <server_port>\n", argv[0]);
        return 1;
    }
    
    int sock_fd = 0;
    int conn_fd = 0;
    int n = 0;
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    socklen_t len = 0;
    
    // 存储客户端和服务器的交互数据
    struct data_package pkg;
    
    memset(&pkg, 0, sizeof(pkg));

    // 1.socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2.bind
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));
    bind(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    
    // 3.listen
    listen(sock_fd, 15);
    
    // 4.accept
    while(1)
    {
        printf("waiting for connetion...\n");
        len = sizeof(clientaddr);
        conn_fd = accept(sock_fd, (struct sockaddr *)&clientaddr, &len);
        
        printf("connection with %s : %d\n", 
            inet_ntoa(clientaddr.sin_addr),
            ntohs(clientaddr.sin_port));
        
        while(1)
        {
            // 循环读取客户端发送来的数据,分析并执行相应操作
            // 直到客户端退出为止
            n = recv(conn_fd, &pkg, sizeof(pkg), 0);
            switch(pkg.cmd)
            {
                case CMD_LIST:
                    // 执行list操作
                    put_list_data_to_client(conn_fd);
                    break;
                case CMD_GET:
                    // 执行get操作
                    put_file_data_to_client(conn_fd, pkg.filename);
                    break;
                case CMD_PUT:
                    // 执行put操作
                    get_file_data_from_client(conn_fd,  pkg.filename);
                    break;
                case CMD_QUIT:
                    printf("server quit...\n");
                    // 执行quit操作
                    break;
                default:
                    break;
            }
        }
        
        // 5.关闭连接套接字
        close(conn_fd);
    }
    
    // 6.close监听套接字
    close(sock_fd);
    
    return 0;
}


// 响应客户端的list命令
// conn_fd  通过指定的连接套接字传递数据
void put_list_data_to_client(int conn_fd)
{
    struct data_package pkg;

    // 1.打开文件服务器根目录
    DIR *p_dir = opendir(SERVER_ROOT_DIR);
    
    // 2.循环读取目录项信息,发送给客户端
    struct dirent *p = NULL;
    while((p = readdir(p_dir)) != NULL)
    {
        if(strncmp(p->d_name, ".", 1) == 0)
            continue;
    
        memset(&pkg, 0, sizeof(pkg));
        pkg.cmd = CMD_LIST;
        strcpy(pkg.data, p->d_name);
        pkg.flag = 0;
        
        send(conn_fd, &pkg, sizeof(pkg), 0);
    }
    
    // 2.1发送数据结束状态数据包
    memset(&pkg, 0, sizeof(pkg));
    pkg.cmd = CMD_LIST;
    pkg.flag = DATA_END_FLAG;       // 结束标志
    send(conn_fd, &pkg, sizeof(pkg), 0);
    
    // 3.关闭目录
    closedir(p_dir);
}

// 响应客户端的get命令
// conn_fd  连接套接字
// file     客户端待下载的文件名
void put_file_data_to_client(int conn_fd, char *file)
{
    struct data_package pkg;
    char path[MAX_FILE_NAME_LEN] = {'\0'};
    int fd = 0;
    
    // 构造待下载文件在服务器文件系统中的绝对路径
    sprintf(path, "%s/%s", SERVER_ROOT_DIR, file);

    // 1.判断待下载文件是否存在,如果不存在,直接发送数据结束状态包 
    if(access(path, F_OK) == -1)
    {
        memset(&pkg, 0, sizeof(pkg));
        pkg.cmd = CMD_GET;
        pkg.flag = DATA_END_FLAG;
        
        send(conn_fd, &pkg, sizeof(pkg), 0);
        
        return;
    }
    
    // 2.如果文件存在,打开文件
    fd = open(path, O_RDONLY);
    
    // 3.循环的读取文件内容,发送给客户端
    memset(&pkg, 0, sizeof(pkg));
    pkg.cmd = CMD_GET;
    pkg.flag = 0;
    while(read(fd, pkg.data, MAX_DATA_LEN-1) > 0)
    {
        send(conn_fd, &pkg, sizeof(pkg), 0);
        memset(pkg.data, 0, MAX_DATA_LEN);
    }
        
    // 4.构造数据结束状态包
    memset(&pkg, 0, sizeof(pkg));
    pkg.cmd = CMD_GET;
    pkg.flag = DATA_END_FLAG;
    send(conn_fd, &pkg, sizeof(pkg), 0);
    
    // 5.关闭文件
    close(fd);
}

// 响应客户端的put命令
// conn_fd  连接套接字
// file     客户端待上传的文件名
void get_file_data_from_client(int conn_fd, char *file)
{
    struct data_package pkg;
    int fd = 0;
    int n = 0;
    char path[MAX_FILE_NAME_LEN] = {'\0'};

    // 构建待上传文件在服务器文件系统中的绝对路径
    sprintf(path, "%s/%s", SERVER_ROOT_DIR, file);

    // 1.打开文件,如果文件不存在,则创建;如果文件存在,则将其长度截短为0
    fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    
    // 2.循环读取文件内容,写入文件
    while(1)
    {
        recv(conn_fd, &pkg, sizeof(pkg), 0);
        
        if(pkg.cmd != CMD_PUT)
            continue;
            
        if(pkg.flag == DATA_END_FLAG)
            break;
        
        n = strlen(pkg.data);
        write(fd, pkg.data, n);
    }
    
    // 3.关闭文件
    close(fd);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,457评论 4 357
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 65,943评论 1 285
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,327评论 0 236
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,307评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,630评论 3 283
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,114评论 1 202
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,514评论 2 305
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,227评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,859评论 1 234
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,186评论 2 238
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,741评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,087评论 2 248
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,614评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,926评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,630评论 0 190
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,117评论 2 261
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,076评论 2 257

推荐阅读更多精彩内容