1. 在.pro工程文件中,加入qt 网络支持
QT += core gui \
network
2.创建 ClientSocket 类
客户端的主要功能包括:
连接服务器,断开服务器,接收并显示服务器数据,向服务器发送数据
//.h
class ClientSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit ClientSocket(QObject *parent = Q_NULLPTR);
~ClientSocket();
bool CilentConect(QHostAddress hadd,ushort port);//连接服务器
void CilentBreakConect();//断开服务器
void TransMess(QString str);//向服务器发送数据
signals:
void dataReady(const QString &ip, const QByteArray &data);//从服务器接收到数据后向界面层发送信号
private slots:
void recvData();//对QTcpSocket 接收到数据产生的信号设定的槽函数
};
//.cpp
ClientSocket::ClientSocket(QObject *parent) :QTcpSocket(parent)
{
connect(this,SIGNAL(readyRead()),this,SLOT(recvData()));//底层信号readyRead -> 槽函数recvDate
}
ClientSocket::~ClientSocket()
{
}
bool ClientSocket::CilentConect(QHostAddress hadd,ushort port)
{
this->connectToHost(hadd,port);
if (this->waitForConnected(1000)) // 连接成功则true
{
return true;
}
return false;
}
void ClientSocket::CilentBreakConect()
{
this->disconnectFromHost();//断开连接
}
void ClientSocket:: TransMess(QString str)//发送数据
{
this->write(str.toLocal8Bit());
}
void ClientSocket:: recvData() //从服务器接收到数据后
{
QString ip = peerAddress().toString().remove(0, 7);
QByteArray data = readAll();
emit dataReady(ip, data); //向界面层发送带数据的信号量
}
3.客户端以及ui设计
//.h
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_Connect_clicked();//连接与断开服务器槽函数
void on_pushButtonTrans_clicked();//发送数据槽函数
void recvData(const QString &ip, const QByteArray &data);//接收数据处理槽函数
private:
Ui::Widget *ui;
ClientSocket *Cilent;//客户端Socket类
};
//.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
Cilent = new ClientSocket(parent);
//客户端类接收到数据的信号连接到界面处理函数
connect(Cilent, SIGNAL(dataReady(const QString&, const QByteArray&)),this, SLOT(recvData(const QString&, const QByteArray&)));
}
服务器端程序的主要思路是,创建一个 QTcpServer 来侦听某一个端口,当有客户端接入时,启动一个线程,并创建一个Socket与对应的客户端通讯。所以这里涉及到四个部分:界面类,服务器类,通讯线程处理和服务器Socket。
服务器端及UI设计
//.h
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
public:
void showNewConnection(int sockDesc);//提示新连接 sockDesc:客户端ID
void showDisconnection(int sockDesc);//提示连接断开
signals:
void MessOk(const QString &mess);
private slots:
void MessWindUpdate(const QString &mess);
void on_pushButton_Trans_clicked(); //发送数据按键响应槽函数
void on_pushButton_StartServer_clicked();//启动或关闭服务器槽函数
signals:
void sendData(int id, const QByteArray &data); //发送数据产生信号
public slots:
void recvData(const QString &ip, const QByteArray &data);//接收到数据后的处理槽函数
private:
Ui::Widget *ui;
Server *m_Server;
};
//.c
void Widget::on_pushButton_StartServer_clicked()
{
QHostAddress address;
if(ui->pushButton_StartServer->text() == "启动服务器")
{
QString localHostName = QHostInfo::localHostName(); //获取主机名
ui->textBrowser_ServerMess->insertPlainText(localHostName+'\n');
QHostInfo info = QHostInfo::fromName(localHostName); //获取主机IP
foreach(address,info.addresses())//获取IPV4的第一个ip
{
if(address.protocol() == QAbstractSocket::IPv4Protocol)
{
ui->textBrowser_ServerMess->insertPlainText(address.toString()+'\n');
break;
}
}
QString serIP = address.toString();//获取IP
QString serPort = ui->lineEdit_Port->text();//获取端口
m_Server->listen((QHostAddress)serIP,serPort.toUInt());//启动监听
ui->pushButton_StartServer->setText("关闭服务器");
}else if(ui->pushButton_StartServer->text() == "关闭服务器")
{
m_Server->close();//关闭服务器
ui->pushButton_StartServer->setText("启动服务器");
}
}
服务器类:
//.h
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = Q_NULLPTR);
~Server();
private:
void incomingConnection(int sockDesc); //QTcpServer中被重写的函数,该函数在客户端接入时被调用
private slots:
void clientDisconnected(int sockDesc); //当产生客户端断开连接时向上层发送信号
private:
Widget *m_widget; //上层界面的句柄 便于底层 服务器进程类的 信号量直接连接到界面处理函数
QList m_socketList; //服务器Socket ID链表
};
//.cpp
//这里的Server类继承于QTcpServer,
//重写其中的void incomingConnection(int sockDesc)方法,
//该方法在有客户端接入时自动调用。
//每当一个新的客户端连接时,通过标识码socketDescriptor,实现与对应的客户端通信
void Server::incomingConnection(int sockDesc)
{
m_socketList.append(sockDesc);//客户端ID 加入链表
ServThread *thread = new ServThread(sockDesc); //创建服务器处理进程
m_widget->showNewConnection(sockDesc); //界面提示,新客户端接入
//服务器进程发出消息,告诉服务器,XX客户端断开连接
connect(thread, SIGNAL(disconnectTCP(int)), this, SLOT(clientDisconnected(int)));
//服务器进程发出消息给窗口,从哪个ip收到数据,槽函数由窗口构建
connect(thread, SIGNAL(dataReady(const QString&, const QByteArray&)),
m_widget, SLOT(recvData(const QString&, const QByteArray&)));
//窗口向服务器进程发出信号 以客户端ID 为标识,发出数据,槽函数由服务器进程构建
connect(m_widget, SIGNAL(sendData(int, const QByteArray&)),
thread, SLOT(sendDataSlot(int, const QByteArray&)));
//启动进程
thread->start();
}
//这是一个槽函数 用于在界面上显示服务器断开了
void Server::clientDisconnected(int sockDesc)
{
m_widget->showDisconnection(sockDesc);
}
服务器通讯线程类
//.h
class ServThread : public QThread
{
Q_OBJECT
public:
explicit ServThread(int sockDesc, QObject *parent = Q_NULLPTR);
~ServThread();
private:
void run(void);
public slots:
void sendDataSlot(int sockDesc, const QByteArray &data);
signals:
void dataReady(const QString &ip, const QByteArray &data);
void sendData(int sockDesc, const QByteArray &data);
void disconnectTCP(int sockDesc);
private slots:
void recvDataSlot(const QString &ip, const QByteArray &data);
void disconnectToHost(void);
private:
ServSocket *m_socket;
int m_sockDesc;
};
//.c
void ServThread:: sendDataSlot(int sockDesc, const QByteArray &data)
{
emit sendData(sockDesc, data);
}
void ServThread:: recvDataSlot(const QString &ip, const QByteArray &data)
{
emit dataReady(ip, data);
}
void ServThread:: disconnectToHost(void)
{
emit disconnectTCP(m_sockDesc);
m_socket->disconnectFromHost();//断开连接
this->quit();
}
void ServThread::run(void)
{
m_socket = new ServSocket(m_sockDesc);
if (!m_socket->setSocketDescriptor(m_sockDesc)) {
return ;
}
connect(m_socket, &ServSocket::disconnected, this, &ServThread::disconnectToHost);
connect(m_socket, SIGNAL(dataReady(const QString&, const QByteArray&)),
this, SLOT(recvDataSlot(const QString&, const QByteArray&)));
connect(this, SIGNAL(sendData(int, const QByteArray&)),
m_socket, SLOT(sendData(int, const QByteArray&)));
this->exec();//在Qt中启动消息机制 龟腚
}
服务器Socket类
//.h
class ServSocket: public QTcpSocket
{
Q_OBJECT
public:
explicit ServSocket(int sockDesc, QObject *parent = Q_NULLPTR);
~ServSocket();
signals:
void dataReady(const QString &ip, const QByteArray &data);
public slots:
void recvData(void);
void sendData(int id, const QByteArray &data);
private:
int m_sockDesc;
};
//.c
ServSocket::ServSocket(int sockDesc,QObject *parent) :QTcpSocket(parent)
{
m_sockDesc = sockDesc;
connect(this,SIGNAL(readyRead()),this,SLOT(recvData()));//底层信号readyRead -> recvDate
}
ServSocket::~ServSocket()
{
}
void ServSocket:: recvData()
{
QString ip = peerAddress().toString().remove(0, 7);
QByteArray data = readAll();
emit dataReady(ip, data);
}
void ServSocket:: sendData(int id, const QByteArray &data)
{
if (id == m_sockDesc && !data.isEmpty()) {
this->write(data);
}
}
源码下载链接
https://download.csdn.net/download/zhaopeng6b/14193041