我们在使用Qt和Linux实现fpt文件传输协议时,需要将服务器运行在Linux系统上,使用Qt来编写客户端,用Qt实现实现一个界面从客户端可以访问与服务器之间的共享目录,实现上传和下载的功能。
1、客户端
客户端主要是实现一个界面的可视化,并且完成与服务器的连接,命令的发送和接收。
可视化界面:
客户端的主要代码:
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTcpSocket>
#include <QSize>
#include <QListWidgetItem>
#include <cstring>
#include <QFileDialog>
#include <QFile>
#include <QFileInfo>
#include <QThread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->progressBar->setValue(0);
ui->progressBar->setVisible(false);
p_Msg = new ftp_msg;
memset(p_Msg,0,sizeof(*p_Msg));
ui->lineEditIP->setText("192.168.0.106");
ui->lineEditPORT->setText("9998");
//第一步 创建socket对象 绑定信号
pCli = new QTcpSocket;
connect(pCli,SIGNAL(readyRead()),this,SLOT(SocketReadyreadSlotFun()),Qt::QueuedConnection);
connect(pCli,SIGNAL(connected()),this,SLOT(SocketConnectedSlotFun()));
connect(pCli,SIGNAL(disconnected()),this,SLOT(SocketDisConnectedSlotFun()));
//第二步 当用户点击连接按钮,发起connect请求
connect(ui->btnConnect,SIGNAL(clicked()),this,SLOT(btnConnectClickedSlotFun()));
//第三步 设置其他的信号与槽函数
connect(ui->btnLook,SIGNAL(clicked()),this,SLOT(btnLookClickedSlotFun()));
connect(ui->btnDown,SIGNAL(clicked()),this,SLOT(btnDownClickedSlotFun()));
connect(ui->btnUp,SIGNAL(clicked()),this,SLOT(btnUpClickedSlotFun()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::btnConnectClickedSlotFun()
{
QString ip = ui->lineEditIP->text();
QString strport = ui->lineEditPORT->text();
unsigned short port = strport.toUShort();
pCli->connectToHost(ip,port);
bool ok = pCli->waitForConnected(80);
if(ok == false)
{
QMessageBox::warning(this,"警告,连接失败","请保持网络畅通,可能服务器不存在",QMessageBox::Yes);
return ;
}
ui->btnConnect->setText("断开");
}
void Widget::SocketReadyreadSlotFun()
{
struct ftp_msg *p_Msg = new ftp_msg;
memset(p_Msg,0,sizeof(*p_Msg));
int ret = pCli->read((char *)p_Msg,sizeof(*p_Msg));
if(ret<0)
{
QMessageBox::warning(this,"警告,连接失败","请检查连接",QMessageBox::Yes);
return;
}
//qDebug()<<p_Msg->cmd<<endl;
switch (p_Msg->cmd) {
case 1:
for(int i=0;i<p_Msg->len;i++)
{
QString str = p_Msg->response[i];
char *ret = strstr(p_Msg->response[i],".");
if(ret == NULL)
{
//创建item
QSize sz(80,40);
pItem=new QListWidgetItem;
pItem->setSizeHint(sz);
QIcon icon(":/file.ico");
pItem->setIcon(icon);
pItem->setText(p_Msg->response[i]);
}else
{
QSize sz(80,40);
pItem=new QListWidgetItem;
pItem->setSizeHint(sz);
QIcon icon(":/text.ico");
pItem->setIcon(icon);
pItem->setText(p_Msg->response[i]);
}
ui->listWidgetFile->addItem(pItem);
ui->listWidgetFile->setViewMode(QListWidget::ListMode);
}
break;
case 2:{
ui->progressBar->setVisible(true);
bool ok = file.write((char *)p_Msg->filebuf, sizeof(p_Msg->filebuf) );
if(ok==false){
QMessageBox::warning(this,"警告,写入失败","请文件是否存在",QMessageBox::Yes);
return;
}
//qDebug()<<"down load txt:"<<p_Msg->filebuf;
if(p_Msg->endfileflag == 1)
{
file.close();
ui->progressBar->setValue(0);
ui->progressBar->setVisible(false);
memset(p_Msg,0,sizeof(*p_Msg));
}
Sret+=sizeof(p_Msg->filebuf);
val = Sret/p_Msg->len;
//ui->lbl->setText(QString::number(Sret));
ui->progressBar->setValue(int(val*100));
memset(p_Msg,0,sizeof(*p_Msg));
break;
}
}
}
void Widget::SocketConnectedSlotFun()
{
}
void Widget::SocketDisConnectedSlotFun()
{
ui->btnConnect->setText("连接");
pCli->disconnectFromHost();
pCli->close();
}
void Widget::btnLookClickedSlotFun()
{
memset(p_Msg,0,sizeof(*p_Msg));
p_Msg->cmd = 1;
pCli->write((char *)p_Msg,sizeof(*p_Msg));
}
void Widget::btnDownClickedSlotFun()
{
//QString str = ui->listWidgetFile->currentItem()->text();
//qDebug()<<str<<endl;
memset(p_Msg,0,sizeof(*p_Msg));
p_Msg->cmd = 2;
int p = ui->listWidgetFile->currentRow();
if(p<0)
{
QMessageBox::about(this,"下载失败","请选择文件");
return;
}
QString fn = ui->listWidgetFile->currentItem()->text();
if(fn.isEmpty())
{
QMessageBox::about(this,"下载失败","请选择文件");
return;
}
//qDebug()<<fn.toStdString().c_str()<<endl;
strcpy(p_Msg->filename,fn.toStdString().c_str());
qDebug()<<p_Msg->filename<<endl;
QString str = "D:/Qt(C++)/project/Qt-ftp/test/" + fn;
//qDebug()<<str<<endl;
QString filename = QFileDialog::getSaveFileName(this,"请选择你要保存的路径",str, "*.c;*.h;*.txt");
if(filename.isEmpty() ){// filename == ""
return;
}
qDebug()<<filename<<endl;
file.setFileName(filename);
bool ok = file.open(QIODevice::WriteOnly);
if(ok==false){
QMessageBox::warning(this,"警告,创建失败","请检查正确路径",QMessageBox::Yes);
return;
}
pCli->write((char *)p_Msg,sizeof(*p_Msg));
memset(p_Msg,0,sizeof(*p_Msg));
Sret= 0;val= 0;
}
void Widget::btnUpClickedSlotFun()
{
memset(p_Msg,0,sizeof(*p_Msg));
p_Msg->cmd = 3;
QString filename = QFileDialog::getOpenFileName(this,"请选择文件","D:/Qt(C++)/project/Qt-ftp/test/","*.txt;*.c;*.h");
if(filename.isEmpty() ){
QMessageBox::about(this,"提示框","请选择文件");
return;
}
QString fn = filename.right(filename.length()-filename.lastIndexOf('/')-1);
//qDebug()<<fn<<endl;
strcpy(p_Msg->filename,fn.toStdString().c_str());
//创建Qfile对象,并绑定到具体文件上
QFile file(filename);
QFileInfo fileinfo(filename);
bool ok = file.open(QIODevice::ReadOnly);
if(ok==false){
QMessageBox::warning(this,"警告","文件上传失败",QMessageBox::Yes);
return;
}
pCli->write((char *)p_Msg,sizeof(*p_Msg));
Sret= 0;val= 0;
qDebug()<<"open success"<<endl;
ui->progressBar->setValue(0);
ui->progressBar->setVisible(true);
while(1){
memset(p_Msg->filebuf,0,sizeof(p_Msg->filebuf));
int ret = file.read((char *)p_Msg->filebuf,sizeof (p_Msg->filebuf));
if(ret == 0){
break;
}else if(ret<0){
QMessageBox::warning(this,"文件读取失败","文件读取失败了",QMessageBox::Yes);
file.close();
return ;
}
Sret+=ret;
val = Sret/fileinfo.size();
//ui->lbl->setText(QString::number(Sret));
ui->progressBar->setValue(int(val*100));
QThread::msleep(100);
//qDebug()<<"up load txt:"<<p_Msg->filebuf;
pCli->write((char *)p_Msg,sizeof(*p_Msg));
}
ui->progressBar->setValue(0);
ui->progressBar->setVisible(false);
memset(p_Msg,0,sizeof(*p_Msg));
p_Msg->cmd = 3;
p_Msg->endfileflag=1;
pCli->write((char *)p_Msg,sizeof(*p_Msg));
file.close();
}
2、服务器
服务器主要需要实现对命令的接收和对应的操作等等,和客户端相互配合完成文件的上传和下载的功能。服务器的部分代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include "commen.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
struct pthread_serv_msg{
pthread_t tid;
int cli_socket;
};
void *serv_for_client(void *args)
{
int ret;
struct pthread_serv_msg *pmsg=args;
int socket = pmsg->cli_socket;
struct ftp_msg serv_msg;
while(1){
memset(&serv_msg,0,sizeof(serv_msg));
ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
if(ret < 0)
{
perror("recv err");
close(socket); free(pmsg);return NULL;
}else if(ret == 0)
{
close(socket); free(pmsg);return NULL;
}
//printf("serv got serv_msg:%s\n",rxbuf);
switch(serv_msg.cmd){
case 1: //list 获取当前目录下的内容 readdir()
{
DIR *dir = opendir("./");
if(dir==NULL)
{
perror("file opendir err");
return NULL;
}
int i=0,j=0;
while(1)
{
struct dirent *rent = readdir(dir);
if(rent==NULL)
{
//for(int n=0;n<i;n++)
//{
//printf("%s\n",serv_msg.response[n]);
//}
serv_msg.len=i;
break;
}
if(strcmp(rent->d_name,".")==0 || strcmp(rent->d_name,"..")==0)
{
continue;
}
//printf("%6s :%d\n",rent->d_name,rent->d_type);
strcpy(serv_msg.response[i++],rent->d_name);
//snprintf(serv_msg.response,sizeof(serv_msg.response),\
" %s %s ",serv_msg.response,rent->d_name);
}
closedir(dir);
ret = send(socket,&serv_msg,sizeof(serv_msg),0);
if(ret < 0)
{
perror("serv send err");
return NULL;
}
break;
}
case 2:
{
//char buf[64]={0};
//snprintf(buf,sizeof(buf),".\\comm\\%s",serv_msg.filename);
int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
if(fd < 0){
perror("open err");
return NULL;
}
serv_msg.len = lseek(fd,0,SEEK_END);
if(serv_msg.len <0){
perror("lseek err");
return NULL;
}
printf("open success:%d\n",serv_msg.len);
lseek(fd,0,SEEK_SET);
while(1){
memset(serv_msg.filebuf,0,sizeof(serv_msg.filebuf));
ret = read(fd,serv_msg.filebuf,sizeof(serv_msg.filebuf)-1);
if(ret < 0 ){
perror("read err");
return NULL;
}else if(ret ==0){
//send(socket,&serv_msg,sizeof(serv_msg),0);
printf("end of file\n");
break;
}else if(ret < sizeof(serv_msg.filebuf)-1)
{
serv_msg.endfileflag = 1;
}
serv_msg.cmd=2;
ret = send(socket,&serv_msg,sizeof(serv_msg),0);
if(ret < 0)
{
perror("serv send err");
return NULL;
}
//printf("%s",serv_msg.filebuf);
usleep(100*1000);
}
printf("\n");
ret = close(fd);
if(ret <0){
perror("close err");
return NULL;
}
break;
}
case 3:
{
//创建一个空文件
int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
if(fd < 0)
{
perror("open err");
return NULL;
}
printf("file creat success\n");
while(1)
{
memset(&serv_msg,0,sizeof(serv_msg));
ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
if(ret < 0)
{
perror("recv err");
return NULL;
}
ret = write(fd,serv_msg.filebuf,strlen(serv_msg.filebuf));
if(ret < 0 ){
perror("write err");
return NULL;
}
//printf("%s\n",serv_msg.filebuf);
//如果发现对方最后一次,结束while
if(serv_msg.endfileflag == 1)
{
printf("upload success\n");
break;
}
}
ret = close(fd);
if(ret <0){
perror("close err");
return NULL;
}
break;
}
}
}
close(socket);
free(pmsg);
return NULL;
}
int main()
{
int socket_main = socket(AF_INET,SOCK_STREAM,0);
if(socket_main < 0)
{
perror("socket creat err");
return -1;
}
printf("socket success\n");
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9998);
serv_addr.sin_addr.s_addr = inet_addr("192.168.0.106");
int ret = bind(socket_main, (struct sockaddr *)&serv_addr , sizeof(serv_addr));
if(ret < 0)
{
perror("bind err");
return -3;
}
printf("bind success\n");
struct sockaddr_in cli_addr;
socklen_t addrlen=sizeof(cli_addr);
struct pthread_serv_msg *pserv_msg=NULL;
int socket_new;
ret = listen(socket_main,5);
if(ret < 0)
{
perror("listen err");
return -3;
}
printf("listen......\n");
loop:
socket_new = accept(socket_main,(struct sockaddr *)&cli_addr,&addrlen);
if(socket_new < 0)
{
perror("accept err");
return -3;
}
printf("accpet success\n");
printf("serv accpet client ip=%s port=%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
pserv_msg=malloc(sizeof(*pserv_msg));
pserv_msg->cli_socket=socket_new;
pthread_create(&pserv_msg->tid,NULL,serv_for_client,pserv_msg);
pthread_detach(pserv_msg->tid);
printf("success link\n");
goto loop;
close(socket_main);
return 0;
}
在客户端与服务器通信的过程中,我们需要定义一个相同的结构体来传输文件:
#ifndef __COMMON_XXX_
#define __COMMON_XXX_
struct ftp_msg {
char cmd; //命令 1-查看目录 2-下载 3-上传
char filename[32]; //文件名
char filebuf[128]; //文本内容
int len; //文本和目录名字的个数
char response[32][32];//保存文本和目录的名字
int endfileflag; //判断文本内容是否传输完成
};
#endif
需要完成版请私信我!!!!!