QT中可以通过TCP协议让服务器和客户端之间行通信。所以下面我就围绕服务器和客户端来写。
这是我么写服务器和客户端的具体流程:
A、服务器:
1.创建QTcpServer对象
2.启动服务器(监听)调用成员方法listen(QHostAddress::Any,端口号)
3.当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)
4.QTcpsocket发送数据用成员方法write,
5.读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据
B、客户端
1.创建QTcpSocket对象
2.链接服务器connectToHost(QHostAddress("ip"),端口号)
3.QTcpsocket发送数据用成员方法write,
4.读数据当对方有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据
我们需要调用到的头文件有两个:
- #include <QTcpServer>
- #include <QTcpSocket>
我们先要在工程文件中加入network
- QT += core gui network
下面我们来看看服务器程序步骤:
1、初始化服务器server对象
- mServer = new QTcpServer();
2、启动监听服务器
- mServer->listen(QHostAddress::Any,9988);//9988为端口号
3、当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)
- connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client()));
- mSocket = mServer->nextPendingConnection();//与客户端通信的套接字
4、发送数据
- mSocket - >write(msg.toUtf8());
5、读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据
- connect(mSocket, SIGNAL(readyRead()), this, SLOT(read_client_data()));
6、连接多个客户端
- //可以实现同时读取多个客户端发送过来的消息
- QTcpSocket * obj = (QTcpSocket * ) sender();
7、检测掉线
- connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis())); //检测掉线信号
下面是服务器的实现的具体代码:
- #include "tcpserver.h"
- #include "ui_tcpserver.h"
- #include <QDebug>
- TcpServer::TcpServer(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::TcpServer)
- {
- ui->setupUi(this);
- //初始化服务器server对象
- mServer = new QTcpServer();
- //关联客户端连接信号newConnection
- connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client())); //连接客户端
- //启动服务器监听
- mServer->listen(QHostAddress::Any,9988);
- }
- TcpServer::~TcpServer()
- {
- delete ui;
- }
- void TcpServer::new_client()
- {
- qDebug()<<"新客户段连接";
- mSocket = mServer->nextPendingConnection();//与客户端通信的套接字
- //关联接收客户端数据信号readyRead信号(客户端有数据就会发readyRead信号)
- connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_client_data()));
- //检测掉线信号
- connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
- }
- void TcpServer::read_client_data()
- {
- //可以实现同时读取多个客户端发送过来的消息
- QTcpSocket *obj = (QTcpSocket*)sender();
- QString msg = obj->readAll();
- qDebug()<<msg;
- }
- void TcpServer::client_dis()
- {
- QTcpSocket *obj = (QTcpSocket*)sender();//掉线对象
- qDebug()<<obj->peerAddress().toString();//打印出掉线对象的ip
- }
说完服务器那我们继续来看看客户端是怎么实现的:
1、创建QTcpSocket对象
- mSocket = new QTcpSocket();
2、链接服务器connectToHost(QHostAddress("ip"),端口号),连接服务器ip和端口号
- mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt()); //ui->ipEdit->text():ip,ui->portEdit->text().toInt():端口号
3、发送数据
- //取发送信息编辑框内容
- QString msg = ui->sendEdit->toPlainText();
- mSocket->write(msg.toUtf8());//转编码
4、检测链接成功信号关联槽函数
- connect(mSocket, SIGNAL(connected()), this, SLOT(connect_suc()));
5、检测掉线信号
- connect(mSocket, SIGNAL(disconnected()), this, SLOT(client_dis()));
6、服务器和客户端关闭都可以使用close
- mSocket - >close();
这是客户端实现的具体代码
- #include "tcpclient.h"
- #include "ui_tcpclient.h"
- #include <QDebug>
- TcpClient::TcpClient(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::TcpClient)
- {
- ui->setupUi(this);
- //初始化套接字对象
- mSocket = new QTcpSocket();
- //关联数据信号
- connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
- }
- TcpClient::~TcpClient()
- {
- delete ui;
- }
- void TcpClient::read_data()
- {
- QString msg = mSocket->readAll();
- qDebug()<<msg;
- }
- void TcpClient::on_btn_connectServer_clicked()
- {
- //检测链接成功信号关联槽函数
- connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
- //检测掉线信号
- connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
- //连接服务器,设置ip和端口号
- mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt());
- }
- void TcpClient::on_btn_send_clicked()
- {
- //取发送信息编辑框内容
- QString msg = ui->sendEdit->toPlainText();
- mSocket->write(msg.toUtf8());//转编码
- }
- void TcpClient::connect_suc()
- {
- ui->btn_connectServer->setEnabled(false);//如果连接成功则连接按钮不能按下
- }
- void TcpClient::client_dis()
- {
- ui->btn_connectServer->setEnabled(true);//如果连接没有成功则连接按钮还可以按下
- }
这是服务器和客户端分开两个文件夹写的程序,在这里我也实现了服务器和客户端写在同一个文件中
具体代码如下:
头文件:tcpapp.h
- #ifndef TCPAPP_H
- #define TCPAPP_H
- #include <QMainWindow>
- #include <QTcpServer>
- #include <QTcpSocket>
- #include <QHostAddress>
- #include <QFile>
- #include <QTimer>
- #include <QMessageBox>
- namespace Ui {
- class TcpApp;
- }
- class TcpApp : public QMainWindow
- {
- Q_OBJECT
- public:
- explicit TcpApp(QWidget *parent = 0);
- ~TcpApp();
- private slots:
- void on_severRB_clicked();//选择作为服务器
- void on_clientRB_clicked();//选择作为客户端
- void on_StartBt_clicked();//启动服务器或链接客户端
- void on_closeBt_clicked();//关闭服务器或断开客户端
- void on_onlineUserList_doubleClicked(const QModelIndex &index);//选择给哪个客户端发送数据
- void on_autoCB_clicked(bool checked);//选择自动发送还是手动发送
- void on_sendMsgBt_clicked();//发送信息
- //服务器
- void accept_connect();//与newconnection信号关联
- void recv_data(); //接收数据
- void auto_time_send();//定时器定时发送数据
- void client_disconnect();//关联掉线信号
- void connect_suc();//检测客户端连接成功信号
- void on_clearRcvBt_clicked();
- void on_clearSendBt_clicked();
- private:
- Ui::TcpApp *ui;
- QTimer *mTimer;//定时发送数据
- QTcpServer *mServer;
- QTcpSocket *mSocket;
- QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
- bool isServer;//标志位,true为服务器,false为客户端
- //保存接收和发送数据的字节数
- quint64 recvSize;
- quint64 sendSize;
- qint16 onNum;
- bool isCheckServer;//判断是否选择了服务器
- bool isCheckClient;//判断是否选择了客户端
- };
- #endif // TCPAPP_H
源文件:tcpapp.cpp
- #include "tcpapp.h"
- #include "ui_tcpapp.h"
- TcpApp::TcpApp(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::TcpApp),
- onNum(0)
- {
- ui->setupUi(this);
- recvSize = 0;
- sendSize = 0;
- //初始化定时器
- mTimer = new QTimer();
- connect(mTimer,SIGNAL(timeout()),this,SLOT(auto_time_send()));
- }
- TcpApp::~TcpApp()
- {
- delete ui;
- }
- //与newconnection信号关联
- void TcpApp::accept_connect()
- {
- mSocket = mServer->nextPendingConnection(); //返回与客户端连接通信的套接字
- //关联接收数据信号
- connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
- //关联掉线信号
- connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
- //上线用户添加到客户列表容器
- clients.append(mSocket);
- //把用户添加到界面列表中
- QString ip = mSocket->peerAddress().toString().remove("::ffff:");//去除客户端中多余的字符
- ui->onlineUserList->addItem(ip);
- //在线数量添加
- onNum++;
- ui->onlineUserCount->setText(QString::number(onNum));//显示在线数
- }
- //接收数据
- void TcpApp::recv_data()
- {
- QTcpSocket *obj = (QTcpSocket*)sender();
- //获取发送数据端的IP
- QString ip = obj->peerAddress().toString();
- ip.remove("::ffff:");
- QString msg = obj->readAll();
- ui->receiveList->addItem(ip+":"+msg);//显示接收到的数据
- recvSize += msg.size();//统计接收到的数据的字节数
- ui->receiveNumLabel->setText(QString::number(recvSize));
- }
- void TcpApp::client_disconnect()
- {
- QTcpSocket *obj = (QTcpSocket*)sender();//获取掉线对象
- if(isServer)
- {
- int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
- QListWidgetItem *item = ui->onlineUserList->takeItem(row);//从界面列表中去除找到的一行内容
- delete item;
- clients.remove(row);//从容器中删除对象
- //掉线时删除在线数量
- onNum--;
- ui->onlineUserCount->setText(QString::number(onNum));
- }
- else
- {
- ui->StartBt->setEnabled(true);//断开连接的时候重新启用开始按钮
- }
- }
- //客户端连接成功
- void TcpApp::connect_suc()
- {
- ui->StartBt->setEnabled(false);//连接成功则禁用开始按钮
- }
- //定时器定时发送数据
- void TcpApp::auto_time_send()
- {
- quint64 len = mSocket->write(ui->sendMsgEdit->toPlainText().toUtf8());
- if(len > 0)
- {
- sendSize += len;//统计发送的字节数
- ui->sendNumLabel->setText(QString::number(sendSize));//把发送的字节数显示到sendNumLabel上
- }
- }
- //选择作为服务器
- void TcpApp::on_severRB_clicked()
- {
- this->isCheckServer = true;
- this->isServer = true;
- //获取本地ip显示在IpEdit中
- ui->IpEdit->setText(QHostAddress(QHostAddress::LocalHost).toString());
- ui->IpEdit->setEnabled(false);//关闭ip输入编辑器
- this->isCheckClient = false;
- }
- //选择作为客户端
- void TcpApp::on_clientRB_clicked()
- {
- this->isCheckClient = true;
- this->isServer = false;
- ui->IpEdit->setEnabled(true);//打开ip输入编辑器
- this->isCheckServer = false;
- }
- //启动服务器或者链接服务器
- void TcpApp::on_StartBt_clicked()
- {
- if(isServer) //服务器
- {
- mServer = new QTcpServer();
- //关联新客户端链接信号
- connect(mServer,SIGNAL(newConnection()),this,SLOT(accept_connect()));
- mServer->listen(QHostAddress::Any,ui->PortEdit->text().toInt());//启动服务器监听
- ui->StartBt->setEnabled(false);//开始按钮禁用
- }
- if(isServer == false) //客户端
- {
- mSocket = new QTcpSocket();
- //检测链接成功信号
- connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
- //设置服务器的 ip和端口号
- mSocket->connectToHost(ui->IpEdit->text(),ui->PortEdit->text().toInt());
- //关联接收数据信号
- connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
- //关联掉线信号
- connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
- }
- if(isCheckServer == false && isCheckClient == false)//如果两个都没选择
- {
- QMessageBox::warning(this,"提示","请选择服务器或者客户端");
- ui->StartBt->setEnabled(true);
- return;
- }
- if(isCheckServer)//选择了服务器
- {
- if(ui->PortEdit->text().isEmpty() || ui->PortEdit->text() == "请输入端口号")
- {
- QMessageBox::warning(this,"提示","请输入端口号");
- ui->StartBt->setEnabled(true);
- return;
- }
- }
- if(isCheckClient)//选择了客户端
- {
- if(ui->IpEdit->text().isEmpty() || ui->IpEdit->text() == "请输入ip" || ui->IpEdit->text() == "请输入端口号")
- {
- QMessageBox::warning(this,"提示","请输入ip和端口号");
- ui->StartBt->setEnabled(true);
- return;
- }
- }
- }
- //关闭服务器或者断开
- void TcpApp::on_closeBt_clicked()
- {
- if(isServer)//服务器
- {
- for(int i=0;i<clients.count();i++)
- {
- clients.at(i)->close();//关闭所有客户端
- }
- //关闭所有服务器之后开始按钮才能启用
- mServer->close();
- ui->StartBt->setEnabled(true);
- }
- else //客户端
- {
- mSocket->close();//关闭客户端
- ui->StartBt->setEnabled(true);//启用开始按钮
- }
- }
- //双击选择要发送的客户端
- void TcpApp::on_onlineUserList_doubleClicked(const QModelIndex &index)
- {
- mSocket = clients.at(index.row());
- }
- //自动发送数据
- void TcpApp::on_autoCB_clicked(bool checked)
- {
- if(checked)
- {
- if(ui->autoTimeEdit->text().toInt() <= 0)
- {
- QMessageBox::warning(this,"提示","请输入时间值ms");
- ui->autoCB->setChecked(false);//把按钮重新置于没选中的状态
- return;
- }
- mTimer->start(ui->autoTimeEdit->text().toInt());//启动定时器
- }
- else
- {
- mTimer->stop();//停止定时器
- }
- }
- //手动发送数据
- void TcpApp::on_sendMsgBt_clicked()
- {
- auto_time_send();
- }
- //清空接收区
- void TcpApp::on_clearRcvBt_clicked()
- {
- ui->receiveNumLabel->clear();
- this->recvSize = 0;
- ui->receiveNumLabel->setText(QString::number(recvSize));
- }
- //清空发送区
- void TcpApp::on_clearSendBt_clicked()
- {
- ui->sendNumLabel->clear();
- this->sendSize = 0;
- ui->sendNumLabel->setText(QString::number(sendSize));
- }
界面文件tcpapp.ui如下图
此外这里还使用到了容器,在这里讲讲容器的使用
1、定义容器对象
- QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
- 解释:QTcpSocke 容器的类型
- clients 容器名
2、往容器中添加成员
- //上线用户添加到客户列表容器
- clients.append(mSocket);
3、寻找某个成员在容器中位置
- int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
4、从容器中删除车成员
- clients.remove(row);//从容器中删除成员
来源: http://www.cnblogs.com/wurenzhong/p/8018862.html