您的位置:首页 > 其它

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

2012-06-03 13:18 337 查看
FileClient文件夹中文件:

FileClient.h:

#ifndef __FILE_CLIENT_H__
#define __FILE_CLIENT_H__

#include <map>
#include <string>
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<string, unsigned char> m_cmd;
};

#endif
FileClient.cpp:
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <utility>
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<string, unsigned char>("ls", ls));
m_cmd.insert(pair<string, unsigned char>("cd", cd));
m_cmd.insert(pair<string, unsigned char>("mkdir", mk));
m_cmd.insert(pair<string, unsigned char>("touch", touch));
m_cmd.insert(pair<string, unsigned char>("rm", rm));
m_cmd.insert(pair<string, unsigned char>("download", download));
m_cmd.insert(pair<string, unsigned char>("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<string, unsigned char>::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 <cstdio>
#include <cstdlib>

#include "FileClient.h"

int main(int argc, char ** argv)
{
if (3 != argc) {
printf("usage: %s <host> <serv>\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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐