一个简单的文件共享工程 -- FileClient

FileClient文件夹中文件:

FileClient.h:

#ifndef __FILE_CLIENT_H__
#define __FILE_CLIENT_H__

#include 
#include 
using std::map;
using std::string;

#include "../TMClient/TMClient.h"

class FileClient : public TMClient
{
public:
    FileClient(const char * host, const char * serv);
    ~FileClient();

protected:
    virtual bool handlecmd(char * data);

protected:
    bool send(const char * data, int n);
    bool recv(char * buff, int n);
    void showusage();

private:
    bool handle_ls_res();
    bool handle_cd_res();
    bool handle_mkdir_res();
    bool handle_touch_res();
    bool handle_rm_res();
    bool handle_download_res();
    bool handle_upload_res(char * data);

private:
    bool handle_normal_res();
    bool upsend(unsigned char state, char * buff, unsigned short uslen);
    int upfile(char * filename, char * buff, unsigned short uslen);
    int updir(char * pathname, char * buff, unsigned short uslen);

protected:
    map  m_cmd;
};

#endif
FileClient.cpp:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using std::pair;

#include "../ByteStream/ByteStream.h"
#include "../Head/Command.h"
#include "FileClient.h"

FileClient::FileClient(const char * host, const char * serv)
 : TMClient(host, serv)
{
    m_cmd.insert(pair("ls", ls));
    m_cmd.insert(pair("cd", cd));
    m_cmd.insert(pair("mkdir", mk));
    m_cmd.insert(pair("touch", touch));
    m_cmd.insert(pair("rm", rm));
    m_cmd.insert(pair("download", download));
    m_cmd.insert(pair("upload", upload));
}

FileClient::~FileClient()
{
    
}

bool FileClient::handlecmd(char * data)
{
    unsigned short uslen = strlen(data);

    int fws;
    for (fws = 0; fws < uslen; ++fws) {
        if (' ' != data[fws]) {
            break;
        }
    }
    if (fws >= uslen) {
        showusage();
        return(true);
    }
    
    int fwe;
    for (fwe = fws + 1; fwe < uslen; ++fwe) {
        if (' ' == data[fwe]) {
            break;
        }
    }
    data[fwe] = '\0';

    int lws;
    for (lws = fwe + 1; lws < uslen; ++lws) {
        if (' ' != data[lws]) {
            break;
        }
    }
    
    int lwe;
    for (lwe = uslen - 1; lwe > lws; --lwe) {
        if (' ' != data[lwe]) {
            break;
        }
    }
    data[lwe + 1] = '\0';
    
    map::iterator iter = m_cmd.find(data + fws);
    if (m_cmd.end() == iter) {
        showusage();
        return(true);
    }
    unsigned char cmd = iter->second;

    if (lws > lwe) {
        if (ls == cmd) {
            data[0] = cmd;
            data[1] = '.';
            data[2] = '\0';
            uslen = 3;
        }
        else if (cd == cmd) {
            data[0] = cmd;
            data[1] = '\0';
            uslen = 2;
        }
        else {
            showusage();
            return(true);
        }
    }
    else {
        data += lws - 1;
        *data = cmd;
        uslen = 1 + (lwe - lws + 1) + 1; /* cmd_sz + str_len + terminator_sz */
    }

    unsigned short reserved = sizeof(unsigned short);
    data -= reserved;
    OBStream os(data, reserved);
    if (upload == cmd) {
        os << (unsigned short)1;
        if (!send(data, reserved + 1)) {
            return(false);
        }
        data += reserved + 1;
    }
    else {
        os << uslen;
        if (!send(data, reserved + uslen)) {
            return(false);
        }
    }

    switch (cmd)
    {
        case ls:
        {
            return(handle_ls_res());
        }
        case cd:
        {
            return(handle_cd_res());
        }
        case mk:
        {
            return(handle_mkdir_res());
        }
        case touch:
        {
            return(handle_touch_res());
        }
        case rm:
        {
            return(handle_rm_res());
        }
        case download:
        {
            return(handle_download_res());
        }
        case upload:
        {
            return(handle_upload_res(data));
        }
        default:
        {
            return(false);
        }
    }
}

bool FileClient::send(const char * data, int n)
{
    return(TConnection::send(m_connfd, data, n));
}

bool FileClient::recv(char * buff, int n)
{
    if (!setrcvlow(m_connfd, n)) {
        return(false);
    }
    return(TConnection::recv(m_connfd, buff, n));
}

void FileClient::showusage()
{
    printf("usage:\n"
           "\t 1> list directory, Example: ls directory\n"
           "\t 2> change directory, Example: cd directory\n"
           "\t 3> create empty directory, Example: mkdir directory\n"
           "\t 4> create empty file, Example: touch file\n"
           "\t 5> remove file or directory, Example: rm file\n"
           "\t 6> download file or directory, Example: download file\n"
           "\t 7> upload file or directory, Example: upload file\n"
           "\t 8> quit\n");
}

bool FileClient::handle_ls_res()
{
    char buff[BUFFSIZ] = { 0 };

    while (true) {
        unsigned short uslen = sizeof(unsigned short);
        if (!recv(buff, uslen)) {
            return(false);
        }

        IBStream is(buff, uslen);
        is >> uslen;
        assert(uslen > 0);

        if (!recv(buff, uslen)) {
            return(false);
        }

        printf("%s", buff + sizeof(unsigned char));

        if ((unsigned char)1 == buff[0]) {
            return(true);
        }
    }
}

bool FileClient::handle_cd_res()
{
    return(handle_normal_res());
}

bool FileClient::handle_mkdir_res()
{
    return(handle_normal_res());
}

bool FileClient::handle_touch_res()
{
    return(handle_normal_res());
}

bool FileClient::handle_rm_res()
{
    return(handle_normal_res());
}

bool FileClient::handle_download_res()
{
    char buff[BUFFSIZ] = { 0 };
    int  fd = -1;
    char laststate = done;

    while (true) {
        unsigned short uslen = sizeof(unsigned short);
        if (!recv(buff, uslen)) {
            return(false);
        }

        IBStream is(buff, uslen);
        is >> uslen;
        assert(uslen > 0);

        if (!recv(buff, uslen)) {
            return(false);
        }

        switch (buff[0])
        {
            case snddir:
            {
                if (-1 == mkdir(buff + 1, DIR_MODE) && EEXIST != errno) {
                    printf("mkdir error: %s\n", strerror(errno));
                }
                break;
            }
            case sndfile:
            {
                if (-1 != fd) {
                    close(fd);
                }
                int index = 0;
                while (++index > 0 && -1 != access(buff + 1, F_OK)) {
                    snprintf(buff + 1 + (uslen - 2), BUFFSIZ - 1 - uslen, "(%d)", index);
                }
                if (-1 == (fd = open(buff + 1, O_WRONLY | O_CREAT, FILE_MODE))) {
                    printf("open error: %s\n", strerror(errno));
                }
                break;
            }
            case sndtxt:
            {
                if (sndfile != laststate && sndtxt != laststate) {
                    if (-1 != fd) {
                        close(fd);
                    }
                    printf("error: state from (%d) to (%d)\n", laststate, buff[0]);
                    return(false);
                }
                uslen -= 1;
                if (-1 != fd) {
                    if (uslen != write(fd, buff + 1, uslen)) {
                        printf("write error: %s\n", strerror(errno));
                    }
                }
                break;
            }
            case done:
            {
                if (-1 != fd) {
                    close(fd);
                }
                printf("%s", buff + 1);
                return(true);
            }
            default:
            {
                if (-1 != fd) {
                    close(fd);
                }
                printf("error: unknown state (%d)\n", buff[0]);
                return(false);
            }
        }
        laststate = buff[0];
    }
}

bool FileClient::handle_upload_res(char * data)
{
    char        buff[BUFFSIZ] = { 0 };
    char        pathname[PATH_MAX + 1] = { 0 };
    struct stat sbuf;

    if (-1 == lstat(data, &sbuf)) {
        printf("lstat error: %s\n", strerror(errno));
        return(true);
    }

    int index = strlen(data) - 1;
    while (index >= 0 && '/' == data[index]) {
        --index;
    }
    while (index >= 0 && '/' != data[index]) {
        --index;
    }
    ++index;

    strcpy(pathname, data + index);

    data[index] = '\0';
    if (0 == strlen(data)) {
        strcpy(data, ".");
    }
    if (-1 == chdir(data)) {
        printf("chdir error: %s\n", strerror(errno));
        return(true);
    }

    if (S_ISDIR(sbuf.st_mode)) {
        int len = strlen(pathname);
        if ('/' != pathname[len - 1]) {
            strcat(pathname, "/");
        }
        if (-1 == updir(pathname, buff, BUFFSIZ - 1)) {
            return(false);
        }
    }
    else {
        if (-1 == upfile(pathname, buff, BUFFSIZ - 1)) {
            return(false);
        }
    }

    return(upsend(done, buff, 0));
}

bool FileClient::handle_normal_res()
{
    char buff[BUFFSIZ] = { 0 };
    unsigned short uslen = sizeof(unsigned short);

    if (!recv(buff, uslen)) {
        return(false);
    }

    IBStream is(buff, uslen);
    is >> uslen;

    if (0 == uslen) {
        return(true);
    }

    if (!recv(buff, uslen)) {
        return(false);
    }

    printf("%s", buff);

    return(true);
}

bool FileClient::upsend(unsigned char state, 
                        char * buff, unsigned short uslen)
{
    uslen += sizeof(unsigned char);
    OBStream os(buff, sizeof(unsigned short) + sizeof(unsigned char));
    os << uslen << state;
    uslen += sizeof(unsigned short);
    return(send(buff, uslen));
}

int FileClient::upfile(char * filename, char * buff, unsigned short uslen)
{
    const int      reserved = sizeof(unsigned short) + sizeof(unsigned char);
    unsigned short filelen = strlen(filename);

    strcpy(buff + reserved, filename);
    if (!upsend(sndfile, buff, filelen + 1)) {
        return(-1);
    }

    int fd;
    if (-1 == (fd = open(filename, O_RDONLY))) {
        printf("open error: %s\n", strerror(errno));
        return(0);
    }

    char           * ptr  = buff  + reserved;
    unsigned short   left = uslen - reserved;
    unsigned short   size = 0;
    int              n    = 0;
    int              ret  = 1;

    while ((n = read(fd, ptr, left)) > 0) {
        ptr  += n;
        left -= n;
        size += n;
        if (0 == left || size >= 4096 - reserved) {
            if (!upsend(sndtxt, buff, size)) {
                ret = -1;
                break;
            }
            ptr  = buff  + reserved;
            left = uslen - reserved;
            size = 0;
        }
    }

    do {
        if (size > 0) {
            if (!upsend(sndtxt, buff, size)) {
                ret = -1;
            }
        }

        if (1 != ret) {
            break;
        }

        if (-1 == n) {
            printf("read error: %s\n", strerror(errno));
            ret = 0;
            break;
        }
    } while (false);

    if (-1 == ::close(fd)) {
        printf("close error: %s\n", strerror(errno));
        if (1 == ret) {
            ret = 0;
        }
    }

    return(ret);
}

int FileClient::updir(char * pathname, char * buff, unsigned short uslen)
{
    struct dirent * dirp;
    DIR           * dp;
    struct stat     sbuf;
    int             ret = 1;
    unsigned short  pathlen = strlen(pathname);
    const int       reserved = sizeof(unsigned short) + sizeof(unsigned char);

    strcpy(buff + reserved, pathname);
    if (!upsend(snddir, buff, pathlen + 1)) {
        return(-1);
    }

    if (NULL == (dp = opendir(pathname))) {
        printf("opendir error: %s\n", strerror(errno));
        return(0);
    }

    while (NULL != (dirp = readdir(dp))) {
        if (strcmp(dirp->d_name, ".") == 0 ||
            strcmp(dirp->d_name, "..") == 0) {
            continue;
        }

        strcat(pathname, dirp->d_name);
        if (-1 == lstat(pathname, &sbuf)) {
            pathname[pathlen] = '\0';
            continue;
        }

        if (S_ISDIR(sbuf.st_mode)) {
            strcat(pathname, "/");
            if (1 != (ret = updir(pathname, buff, uslen))) {
                break;
            }
        }
        else {
            if (1 != (ret = upfile(pathname, buff, uslen))) {
                break;
            }
        }
        pathname[pathlen] = '\0';
    }

    pathname[pathlen] = '\0';
    if (-1 == closedir(dp)) {
        printf("closedir error: %s\n", strerror(errno));
        if (1 == ret) {
            ret = 0;
        }
    }

    return(ret);
}
Client.cpp:

#include 
#include 

#include "FileClient.h"

int main(int argc, char ** argv)
{
    if (3 != argc) {
        printf("usage: %s  \n", argv[0]);
        exit(1);
    }

    FileClient client(argv[1], argv[2]);
    client.mainloop();
    return(0);
}
makefile:

objects=Client.o FileClient.o TMClient.o TConnection.o ByteStream.o
client:$(objects)
	g++ -o client $(objects)  

Client.o:Client.cpp
	g++ -c Client.cpp
FileClient.o:FileClient.cpp FileClient.h ../Head/Command.h
	g++ -c FileClient.cpp
TMClient.o:../TMClient/TMClient.cpp ../TMClient/TMClient.h ../Head/Uncopy.h
	g++ -c ../TMClient/TMClient.cpp
TConnection.o:../TConnection/TConnection.cpp ../TConnection/TConnection.h
	g++ -c ../TConnection/TConnection.cpp
ByteStream.o:../ByteStream/ByteStream.cpp ../ByteStream/ByteStream.h
	g++ -c ../ByteStream/ByteStream.cpp

rebuild:clean client

clean:  
	-rm client $(objects)

你可能感兴趣的:(c++,makefile,unix,项目)