QT5.9利用tcp Socke实现消息与文件的传输, tcpServer和tcpClient

利用Socket写了一个文件传输软件; 平时用来在台式机跟笔记本直接传输一下文件,省去拔插U盘的步骤. Ubuntu和win10都能用.

软件截图:
QT5.9利用tcp Socke实现消息与文件的传输, tcpServer和tcpClient_第1张图片
Server:

#include "server.h"
#include "ui_server.h"
#include

QString Server::getlocalIP()
{
    QString hostName=QHostInfo::localHostName();
    QHostInfo hostInfo=QHostInfo::fromName(hostName);

    QList addList=hostInfo.addresses();
    if(!addList.isEmpty())
        for(int i=0;iplainTextEdit->appendPlainText("本机主机名:"+hostName);
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);

    QList addList=hostInfo.addresses();//
    if (!addList.isEmpty())
    for (int i=0;iplainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
//          if (ui->comboIP->findText(IP)<0)  ui->comboIP->addItem(IP);
        }
    }
}

Server::Server(QWidget *parent) :QMainWindow(parent), ui(new Ui::Server)
{
    ui->setupUi(this);
    ui->editIP->setText(getlocalIP());   this->setWindowTitle(this->windowTitle()+"---本机IP:"+getlocalIP());

    initSocket();
    initFileSocket();
}
void Server::initSocket()
{
    LabListen=new QLabel("监听状态:");
    LabListen->setMinimumWidth(150);
    ui->statusBar->addWidget(LabListen);
    LabSocketState=new QLabel("Socket状态:");//
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}

void Server::initFileSocket()
{
    //// 文件传送相关变量初始化
    perDataSize = 64*1024;
    totalBytes = 0;
    bytestoWrite = 0;
    bytesWritten = 0;
    bytesReceived = 0;
    filenameSize = 0;
    ///文件传送套接字
    fileSocket = new QTcpSocket(this);
    fileServer = new QTcpServer(this);
    fileServer->listen(QHostAddress::Any,ui->spinPort->value()+1);
    connect(fileServer,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));
}
Server::~Server()
{
    delete ui;
    delete tcpServer;
    delete fileServer;
}

void Server::on_actStart_triggered()
{//开始监听
    QString     IP=ui->editIP->text();//IP地址
    quint16     port=ui->spinPort->value();//端口
    QHostAddress    addr(IP);
    tcpServer->listen(QHostAddress::Any,port);//
//  tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1").
    ui->plainTextEdit->appendPlainText("**开始监听...");
    ui->plainTextEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));
    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);
    LabListen->setText("监听状态:正在监听");
}
void Server::on_actStop_triggered()
{//停止监听
    if (tcpServer->isListening()) //tcpServer正在监听
    {
        tcpServer->close();//停止监听
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        LabListen->setText("监听状态:已停止监听");
    }
}

void Server::onNewConnection()
{
    ui->plainTextEdit->appendPlainText("有新连接");
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket
    connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));//
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpSocket->state());

    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
void Server::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;
    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void Server::onClientConnected()
{//客户端接入时
    ui->plainTextEdit->appendPlainText("**client socket connected");
    ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort()));
}

void Server::onClientDisconnected()
{//客户端断开连接时
    ui->plainTextEdit->appendPlainText("**client socket disconnected");
    tcpSocket->deleteLater();
   // deleteLater();
}

void Server::onSocketReadyRead()
{
    qDebug()<<"data to read....";
//    while(tcpSocket->canReadLine())
//        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
    //无法读取python,必须换行
//    QByteArray buffer;
//    buffer = tcpSocket->readAll();
//    if(!buffer.isEmpty())
//    {
//        QString str = tr(buffer);
//        ui->plainTextEdit->appendPlainText(str);
//    }
    ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readAll());
}

void Server::on_btnSendMsg_clicked()
{
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    //str.append('\n');//添加一个换行符
    tcpSocket->write(str);
}

void Server::closeEvent(QCloseEvent *event)
{//关闭窗口时停止监听
    if (tcpServer->isListening())
        tcpServer->close();//停止网络监听
    if (fileServer->isListening())
        fileServer->close();//停止网络监听
    event->accept();
}

void Server::acceptFileConnection()
{
    bytesWritten = 0;
    ///每次发送数据大小为64kb
    perDataSize = 64*1024;
    fileSocket =fileServer->nextPendingConnection();
    ///接受文件
    connect(fileSocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));
    connect(fileSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
    connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
}

void Server::updateFileProgress()
{
    QDataStream inFile(fileSocket);
    inFile.setVersion(QDataStream::Qt_4_8);

    ///如果接收到的数据小于16个字节,保存到来的文件头结构
    if(bytesReceived <= sizeof(qint64)*2)
    {
        if((fileSocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
        {
            inFile>>totalBytes>>filenameSize;
            bytesReceived += sizeof(qint64)*2;
        }
        if((fileSocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
        {
            inFile>>filename;
            bytesReceived += filenameSize;
            ////接收的文件放在指定目录下
            filename = ui->editSaveDir->text()+"/"+filename;
            localFile = new QFile(filename);
            if(!localFile->open(QFile::WriteOnly))
            {
                ui->plainTextEdit->appendPlainText("Server::open file error!");
                return;
            }
        }
        else
            return;
    }
    /////如果接收的数据小于总数据,则写入文件
    if(bytesReceived < totalBytes)
    {
        bytesReceived += fileSocket->bytesAvailable();
        inBlock = fileSocket->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    ////更新进度条显示
    this->ui->progressBarRec->setMaximum(totalBytes);
    this->ui->progressBarRec->setValue(bytesReceived);
    ////数据接收完成时
    if(bytesReceived == totalBytes)
    {
        this->ui->plainTextEdit->appendPlainText("Receive file successfully!");
        bytesReceived = 0;
        totalBytes = 0;
        filenameSize = 0;
        localFile->close();
        //fileSocket->close();
    }
}
void Server::updateFileProgress(qint64 numBytes)
{ ////已经发送的数据大小
    bytesWritten += (int)numBytes;
    ////如果已经发送了数据
    if(bytestoWrite > 0)
    {
        outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
        ///发送完一次数据后还剩余数据的大小
        bytestoWrite -= ((int)fileSocket->write(outBlock));
        ///清空发送缓冲区
        outBlock.resize(0);
    }
    else
        localFile->close();
    ////更新进度条
    this->ui->progressBarSend->setMaximum(totalBytes);
    this->ui->progressBarSend->setValue(bytesWritten);

    ////如果发送完毕
    qDebug()<<"bytesWritten"<close();
      // fileSocket->close();
       qDebug()<progressBarRec->value()<<"value";
       qDebug()<progressBarRec->maximum()<<"maximum";
    }
}

void Server::displayError(QAbstractSocket::SocketError socketError)
{
    ui->plainTextEdit->appendPlainText(fileSocket->errorString());
    //socket->close();
}

void Server::on_btnSaveDir_clicked()
{
    ui->editSaveDir->setText(QFileDialog::getExistingDirectory(this,"请选择保存路径"));
}
void Server::on_btnSelectFile_clicked()
{
   //  ui->editFile->setText(QFileDialog::getOpenFileName(this,"请选择待发送文件"));
    //???fileSocket->open(QIODevice::WriteOnly);
    ///文件传送进度更新
    //connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
    filename = QFileDialog::getOpenFileName(this,"Open a file");
    ui->editFile->setText(filename);
}

void Server::on_btnSendFile_clicked()
{

    localFile = new QFile(filename);
    if(!localFile->open(QFile::ReadOnly))
    {
        ui->plainTextEdit->appendPlainText("Client:open file error!");
        return;
    }
    ///获取文件大小
    this->totalBytes = localFile->size();
    QDataStream sendout(&outBlock,QIODevice::WriteOnly);
    sendout.setVersion(QDataStream::Qt_4_8);
    QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);

    qDebug()<seek(0);
    sendout<write(outBlock);
    outBlock.resize(0);
}

客户端:Client

#include "client.h"
#include "ui_client.h"
#include
#include
#include
QString Client::getlocalIP()
{
    QString hostName=QHostInfo::localHostName();
    QHostInfo hostInfo=QHostInfo::fromName(hostName);

    QList addList=hostInfo.addresses();
    if(!addList.isEmpty())
        for(int i=0;iplainTextEdit->appendPlainText("本机主机名:"+hostName);
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);

    QList addList=hostInfo.addresses();//
    if (!addList.isEmpty())
    for (int i=0;iplainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
//          if (ui->comboIP->findText(IP)<0)  ui->comboIP->addItem(IP);
        }
    }
}

Client::Client(QWidget *parent) :QMainWindow(parent),ui(new Ui::Client)
{
    ui->setupUi(this);
    ui->editIP->setText(getlocalIP());   this->setWindowTitle(this->windowTitle()+"--本机IP:"+getlocalIP());

    initSocket();
    initFileSocket();

}
void Client::initFileSocket()
{
    /////文件传送相关变量初始化
    ///每次发送数据大小为64kb
    perDataSize = 64*1024;
    totalBytes = 0;
    bytestoWrite = 0;
    bytesWritten = 0;
    bytesReceived = 0;
    filenameSize = 0;

    fileSocket = new QTcpSocket(this);
    fileSocket->abort();
    ////文件传送进度更新
    connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
    connect(fileSocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));

    connect(fileSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
    ui->progressBarSend->setValue(0);ui->progressBarRec->setValue(0);
}
void Client::initSocket()
{
    LabSocketState =new QLabel("Socket状态:");
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    tcpClient=new QTcpSocket(this);
    connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
    connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpClient->state());
}

Client::~Client()
{
    delete ui;
    delete tcpClient;
    delete fileSocket;
}

void Client::on_actConnect_triggered()
{//连接主机
    QString addr=ui->editIP->text();
    quint16 port=ui->spinPort->value();
    tcpClient->connectToHost(addr,port);

    fileSocket->connectToHost(ui->editIP->text(),ui->spinPort->value()+1);
}
void Client::on_actDisconnect_triggered()
{
  if(tcpClient->state()==QAbstractSocket::ConnectedState)
      tcpClient->disconnectFromHost();
}

void Client::onConnected()
{
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                   tcpClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                   QString::number(tcpClient->peerPort()));
    ui->actConnect->setEnabled(false);
    ui->actDisconnect->setEnabled(true);

}

void Client::onDisconnected()
{
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->actConnect->setEnabled(true);
    ui->actDisconnect->setEnabled(false);
}

void Client::onSocketReadyRead()
{
//    qDebug()<<"data to read....";
//    while(tcpClient->canReadLine())
//        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
//    无法读取python,必须换行
//    QByteArray buffer;
//    buffer = tcpClient->readAll();
//    if(!buffer.isEmpty())
//    {
//        QString str = tr(buffer);
//        ui->plainTextEdit->appendPlainText(str);
//    }
    ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readAll());
}

void Client::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号槽函数
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;
    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}
void Client::on_btnSendMsg_clicked()
{//发送数据
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    //str.append('\n');
    tcpClient->write(str);
}

void Client::closeEvent(QCloseEvent *event)
{
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
    if (fileSocket->state()==QAbstractSocket::ConnectedState)
        fileSocket->disconnectFromHost();
       event->accept();
}

void Client::on_btnSelectSaveDir_clicked()
{
    ui->editSaveDir->setText(QFileDialog::getExistingDirectory(this,"接收文件保存路径"));
}

void Client::on_btnSelectFile_clicked()
{
   // ui->editFile->setText(QFileDialog::getOpenFileName(this,"选择待发送文件"));
   filename = QFileDialog::getOpenFileName(this);
   ui->editFile->setText(filename);
}

void Client::on_btnSendFile_clicked()
{

       localFile = new QFile(filename);
        if(!localFile->open(QFile::ReadOnly))
        {
            ui->plainTextEdit->appendPlainText("Client:open file error!");
            return;
        }
        ///获取文件大小
        this->totalBytes = localFile->size();
        QDataStream sendout(&outBlock,QIODevice::WriteOnly);
        sendout.setVersion(QDataStream::Qt_4_8);
        QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);

        //qDebug()<seek(0);
        sendout<write(outBlock);
        outBlock.resize(0);
}

void Client::updateFileProgress(qint64 numBytes)
{
    ////已经发送的数据大小
    bytesWritten += (int)numBytes;
    ////如果已经发送了数据
    if(bytestoWrite > 0)
    {
        outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
        ///发送完一次数据后还剩余数据的大小
        bytestoWrite -= ((int)fileSocket->write(outBlock));
        ///清空发送缓冲区
        outBlock.resize(0);
    }
    else
        localFile->close();
    ////更新进度条
    ui->progressBarSend->setMaximum(totalBytes);
    ui->progressBarSend->setValue(bytesWritten);

    ////如果发送完毕
    qDebug()<<"bytesWritten"<close();
      // fileSocket->close();
       qDebug()<progressBarRec->value()<<"value";
       qDebug()<progressBarRec->maximum()<<"maximum";
    }
}

void Client::updateFileProgress()
{
    QDataStream inFile(fileSocket);
    inFile.setVersion(QDataStream::Qt_4_8);

    ///如果接收到的数据小于16个字节,保存到来的文件头结构
    if(bytesReceived <= sizeof(qint64)*2)
    {
        if((fileSocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
        {
            inFile>>totalBytes>>filenameSize;
            bytesReceived += sizeof(qint64)*2;
        }
        if((fileSocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
        {
            inFile>>filename;
            bytesReceived += filenameSize;
            ////接收的文件放在指定目录下
            filename = ui->editSaveDir->text()+"/"+filename;
            localFile = new QFile(filename);
            if(!localFile->open(QFile::WriteOnly))
            {
                ui->plainTextEdit->appendPlainText("Server::open file error!");
                return;
            }
        }
        else
            return;
    }
    /////如果接收的数据小于总数据,则写入文件
    if(bytesReceived < totalBytes)
    {
        bytesReceived += fileSocket->bytesAvailable();
        inBlock = fileSocket->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    ////更新进度条显示
    this->ui->progressBarRec->setMaximum(totalBytes);
    this->ui->progressBarRec->setValue(bytesReceived);
    ////数据接收完成时
    if(bytesReceived == totalBytes)
    {
        this->ui->plainTextEdit->appendPlainText("Receive file successfully!");
        bytesReceived = 0;
        totalBytes = 0;
        filenameSize = 0;
        localFile->close();
        //fileSocket->close();
    }
}
void Client::displayError(QAbstractSocket::SocketError socketError)
{
    ui->plainTextEdit->appendPlainText(fileSocket->errorString());
    //socket->close();
}

完整工程:https://download.csdn.net/download/qq_43569273/11097167

你可能感兴趣的:(QT相关)