TCP实现文件夹传输

1 篇文章 0 订阅
1 篇文章 0 订阅

目标

c语言+tcp,实现一个server和client。
client可以将本地文件夹上传到server的指定文件路径上;也可以请求server指定路径下的文件夹,将远程内容写到本地。
接口形式如下:

//path 是server上文件夹的绝对地址,localpath下载到本地的地址
int save_file_from_server(char *serverip, int port, char *path, char *localpath);
//localpath是本地上传绝对路径,上传到server的指定路径下,server路径写死在逻辑中。
int upload_file_to_server(char *serverip, int port, char *localpath);

每次有一个client连接,server端就创建一个线程与client进行交互。

代码框架

server

int main(){
    listenfd = socket(...);
    bind(...);
    listen(...);
    while(1){
    connfd = accept(...);
    pthread_create(&tid, NULL, (void *)response, (void *)&connfd)
    }
    close(listenfd);
    return 0;
    }

client
上传文件夹

int main(int argc, char **argv)
{
    char *serverip = "127.0.0.1";
    int port = 11710;
    char localpath[] = "...";
    char path[] = "...";
    upload_file_to_server(serverip, port, path);
    return 0;
}

下载文件夹

    char *serverip = "127.0.0.1";
    int port = 11710;
    char path[] = "...";
    upload_file_to_server(serverip, port, path);

逻辑

上传文件夹到服务器
在这里插入图片描述
从服务器下载文件夹到本地
在这里插入图片描述
逻辑不难,难点在

  • 如何确定收发数据的类型。是下载命令,还是文件名,还是文件内容?
  • 如何确定一个文件已经写完?
    一般来说,写文件可以用recv()函数,如下。但是收到完文件后,recv会阻塞住,不会正常结束。
while(recv_len = recv(sockfd, recv_buf, BUF_SZ, 0)){
fwrite(recv_buf, 1, recv_len , fp);
}

解决办法,每次服务器客户端通信,发送BUF_SZ个数据,预留最后五个字节,倒数前四个字节表示这次通信中的有效数据的长度,最后一个数据标志位:表示这次数据的类型。
在这里插入图片描述
标志位:

enum
{
    FNAME_FIN = 1,//文件名,非这次传输的最后一个文件
    FNAME_NFIN,   //文件名,这次传输的最后一个文件
    FCON_FIN,     //文件内容,是这个文件的需最后的数据
    FCON_NFIN,    //文件内容,不是这个文件的需最后的数据
    CMD,          //命令
    PATH,         //文件路径
};

代码

用逻辑写看起来挺麻烦的,但是代码确实简单明了,每个函数最多几十行.
上贡代码:https://github.com/ltCodeW/DirTrans/

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Qt 中,你可以使用 QTcpSocket 类来实现基于 TCP 的文件传输。要传输文件夹和其中的文件,你需要使用递归函数遍历文件夹和子文件夹,并将它们发送到接收端。 以下是一个简单的代码示例,可以帮助你开始实现这个功能: ```cpp // 客户端发送文件夹和文件 void sendFolder(QString folderPath, QTcpSocket *socket) { QFileInfo folderInfo(folderPath); if (folderInfo.isFile()) { // 发送文件 sendFile(folderPath, socket); } else if (folderInfo.isDir()) { // 发送文件夹 QByteArray byteArray; QDataStream out(&byteArray, QIODevice::WriteOnly); out << QString("Folder") << folderInfo.fileName(); socket->write(byteArray); // 遍历文件夹 QDir dir(folderPath); QStringList files = dir.entryList(QStringList(), QDir::Files); for (int i = 0; i < files.size(); ++i) { QString filePath = folderPath + "/" + files.at(i); sendFile(filePath, socket); } QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (int i = 0; i < folders.size(); ++i) { QString folderPath = folderPath + "/" + folders.at(i); sendFolder(folderPath, socket); } } } // 客户端发送文件 void sendFile(QString filePath, QTcpSocket *socket) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Failed to open file"; return; } QByteArray byteArray; QDataStream out(&byteArray, QIODevice::WriteOnly); out << QString("File") << QFileInfo(filePath).fileName() << file.readAll(); socket->write(byteArray); file.close(); } // 服务端接收文件夹和文件 void receiveFolder(QTcpSocket *socket) { QString folderName; QByteArray byteArray = socket->readAll(); QDataStream in(&byteArray, QIODevice::ReadOnly); in >> folderName; QDir dir(folderName); dir.mkpath("."); while (socket->bytesAvailable() > 0) { QByteArray byteArray = socket->readAll(); QDataStream in(&byteArray, QIODevice::ReadOnly); QString type, fileName; in >> type >> fileName; if (type == "File") { QFile file(folderName + "/" + fileName); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "Failed to open file"; continue; } QByteArray data; in >> data; file.write(data); file.close(); } else if (type == "Folder") { receiveFolder(socket); } } } // 服务端开始监听 void startServer() { QTcpServer *server = new QTcpServer(this); connect(server, &QTcpServer::newConnection, this, &MyClass::newConnection); server->listen(QHostAddress::Any, 1234); } // 服务端新连接处理 void newConnection() { QTcpSocket *socket = server->nextPendingConnection(); receiveFolder(socket); } ``` 在这个例子中,客户端递归遍历文件夹并发送文件到服务端,服务端接收文件夹和文件。当接收到一个文件夹时,服务端会递归调用自己来接收文件夹中的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值