(一)背景介绍
昨天学习了基于QT的网络编程,与LINUX下的网络编程十分相似。学完基础知识就决定要自己编写一个类似于NetAssist的网络上位机,并实现其大部分的功能。
当然计算机网络不可能就这么简单只是socket编程,并没有掌握问题的本质,对于计算机网络等以后有时间还得要单独学习一下。
对于我们做嵌入式的人来说,调试一般都会用别人提供好的调试软件。但是可以自己写一个上位机 真的是一件令人兴奋的事情。先看源码。
服务器端:
#ifndef SEVERWIDGET_H
#define SEVERWIDGET_H
#include <QWidget>
#include <QTcpServer>//监听套接字
#include <QTcpSocket>//通信套接字
#include "clintwidget.h"
#include <QFile>
#include <QTimer>
namespace Ui {
class severWidget;
}
class severWidget : public QWidget
{
Q_OBJECT
public:
explicit severWidget(QWidget *parent = 0);
~severWidget();
void subprocess();
void senddata();
QString getIP() ;
private slots:
void on_buttonsend_clicked();
void on_pushButton_2_clicked();
void on_change_clicked();
void on_buttonfile_clicked();
void on_buttonsend_2_clicked();
private:
Ui::severWidget *ui;
clintwidget w;
QTcpServer *tcpsever;
QTcpSocket *tcpsocket;
static int severstate;//反映服务器端所处状态
QFile file;
QString filename;
qint64 filesize;
qint64 sendsize;//已发大小
QTimer timer;
};
#endif // SEVERWIDGET_H
#include "severwidget.h"
#include "ui_severwidget.h"
#include "clintwidget.h"
#include <QFile>
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
#include <QTimer>
#include <QtNetwork>
severWidget::severWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::severWidget)
{
ui->setupUi(this);
setWindowTitle("服务器 端口:8888");
//指针悬空防止没有连接而死机
tcpsever=NULL;
tcpsocket=NULL;
ui->buttonfile->setEnabled(false);
ui->buttonsend->setEnabled(false);
ui->buttonsend_2->setEnabled(false);
//指定父对象可以自动回收空间
tcpsever=new QTcpServer(this);
//监听套接字
tcpsever->listen(QHostAddress::Any,8888);
//如果成功连接
connect(tcpsever,&QTcpServer::newConnection,
[=]()
{
//取出套接字
tcpsocket=tcpsever->nextPendingConnection();
//获取对方IP端口
QString ip=tcpsocket->peerAddress().toString();
quint16 port =tcpsocket->peerPort();
QString temp=QString("[%1:%2]:成功连接").arg(ip).arg(port);
qDebug()<<getIP();
ui->buttonfile->setEnabled(true);
ui->buttonsend->setEnabled(true);
// ui->buttonsend_2->setEnabled(true);
ui->textEditRead->setText(temp);
connect(tcpsocket,&QTcpSocket::readyRead,
[=]()
{
//从通信套接字中取出内容
QByteArray array=tcpsocket->readAll();
ui->textEditRead->append(array);
}
);
}
);
connect(&timer,&QTimer::timeout,
[=]()
{
timer.stop();
//发送文件
senddata();
}
);
void (clintwidget::*funSing)()=&clintwidget::mySignal;
connect(&w,funSing,this,&severWidget::subprocess);
}
severWidget::~severWidget()
{
delete ui;
}
void severWidget::on_buttonsend_clicked()
{
if(NULL==tcpsocket)
{
return;
}
//获取编辑区内容
QString str =ui->textEditWrite->toPlainText();
//将内容发出去
tcpsocket->write(str.toUtf8().data());
}
void severWidget::on_pushButton_2_clicked()
{
if(NULL==tcpsocket)
{
return;
}
//主动和客户端断开连接
tcpsocket->disconnectFromHost();
tcpsocket->close();
}
void severWidget::on_change_clicked()
{
this->close();
w.show();
}
void severWidget::subprocess(void)
{
this->show();
w.hide();
}
void severWidget::on_buttonfile_clicked()
{
QString filepath =QFileDialog::getOpenFileName(this,"open","../");
if(false ==filepath.isEmpty())
{
filename.clear();
filesize=0;
//获取文件信息
QFileInfo info(filepath);
filename =info.fileName();
filesize=info.size();
sendsize=0;
//只读打开
//指定名字
//打开文件
file.setFileName(filepath);
bool isok=file.open(QIODevice::ReadOnly);
if(false==isok)
{
qDebug()<<"打开失败";
ui->buttonfile->setEnabled(true);
ui->buttonsend_2->setEnabled(false);
}
ui->textEditRead->append(filepath);
ui->buttonsend_2->setEnabled(true);
}
else
{
qDebug()<<"路径文件错误";
}
}
//发送文件按钮
void severWidget::on_buttonsend_2_clicked()
{
//发送文件头
QString head =QString("%1##%2").arg(filename).arg(filesize);
//发送头部信息
qint64 len =tcpsocket->write(head.toUtf8());
if(len>0)
{
//发送文件
//防止TCP连包问题
//需要延时
timer.start(20);
}
else
{
qDebug()<<"头部信息发送失败";
file.close();
ui->buttonfile->setEnabled(true);
ui->buttonsend_2->setEnabled(false);
}
}
void severWidget::senddata()
{
qint64 len=0;
do
{
//每次发送4K
char buf[1024*4]={0};
len=0;
len=file.read(buf,sizeof(buf));
//发送数据
tcpsocket->write(buf,len);
sendsize+=len;
}while(len>0);
//是否发送完毕
if(sendsize==filesize)
{
ui->textEditRead->append("文件发送完毕");
file.close();
}
}
QString severWidget::getIP() //获取ip地址
{
QList<QHostAddress> list =QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
{
if(address.protocol() ==QAbstractSocket::IPv4Protocol)
//我们使用IPv4地址
return address.toString();
}
return 0;
}
客户端:
#ifndef CLINTWIDGET_H
#define CLINTWIDGET_H
#include <QWidget>
#include <QTcpSocket>// 通信套接字
#include <QFile>
namespace Ui {
class clintwidget;
}
class clintwidget : public QWidget
{
Q_OBJECT
public:
explicit clintwidget(QWidget *parent = 0);
~clintwidget();
QTcpSocket *tcpsocket;
QString getIP() ;
private slots:
void on_buttonconnect_clicked();
void on_pushButton_4_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_linkstate_clicked();
signals:
//信号只能由singal声明
//信号可以重载
void mySignal();
public slots:
void sendSignal();
private:
Ui::clintwidget *ui;
qint64 clintstate;//反映当前客户端所处状态
QFile file;
QString filename;
qint64 filesize;
qint64 recvsize;//已发大小
bool isstart;
};
#endif // CLINTWIDGET_H
#include "clintwidget.h"
#include "ui_clintwidget.h"
#include <QHostAddress>
#include <QMessageBox>
clintwidget::clintwidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::clintwidget)
{
ui->setupUi(this);
setWindowTitle("客户端");
clintstate=0;
tcpsocket=NULL;
isstart=true;
//分配空间
tcpsocket=new QTcpSocket(this);
connect(tcpsocket,&QTcpSocket::connected,
[=]()
{
ui->textEditread->setText("成功连接服务器");
}
);
connect(tcpsocket,&QTcpSocket::readyRead,
[=]()
{
//获取内容
//
if(clintstate==0)
{
QByteArray array=tcpsocket->readAll();
ui->textEditread->append(array);
}
else
{
QByteArray buf=tcpsocket->readAll();
if(isstart==true)
{
isstart=false;
//解析头部信息
filename=QString(buf).section("##",0,0);
filesize=QString(buf).section("##",1,1).toInt();
qDebug()<<filesize;
recvsize=0;
file.setFileName(filename);
bool isok=file.open(QIODevice::WriteOnly);
if(isok==false)
{
qDebug()<<filename;
qDebug()<<"open error";
}
}
else
{
qint64 len= file.write(buf);
recvsize+=len;
ui->progressBar->setValue(100*double(recvsize)/filesize);
if(recvsize==filesize)
{
file.close();
QMessageBox::information(this,"success","文件接收完成");
isstart=true;
}
}
}
}
);
}
clintwidget::~clintwidget()
{
delete ui;
}
void clintwidget::on_buttonconnect_clicked()
{
//获取服务器
QString ip=ui->lineEditip->text();
qint16 port=ui->lineEditport->text().toInt();
//主动连接服务器
tcpsocket->connectToHost(QHostAddress(ip),port);
}
void clintwidget::on_pushButton_4_clicked()
{
//获取内容
QString str =ui->textEditwrite->toPlainText();
//发送数据
tcpsocket->write(str.toUtf8().data());
}
void clintwidget::on_pushButton_2_clicked()
{
//主动断开
tcpsocket->disconnectFromHost();
}
void clintwidget::sendSignal()
{
emit mySignal();
}
void clintwidget::on_pushButton_3_clicked()
{
sendSignal();
}
void clintwidget::on_linkstate_clicked()
{
clintstate=!clintstate;
if(clintstate==0)
{
ui->linkstate->setText("文本接收");
}
else
{
ui->linkstate->setText("文件接收");
}
}
(三)简单的TCP/UDP知识
相对于UDP协议TCP相对复杂
(四)效果展示
测试:
1.两个端口实现文本互传
2.两台电脑之间通过网络实现文件互传
传输完成后在应用程序的同级目录产生传输完成后的文件
下面是源码和应用程序的链接: