目录
任务:实现一个基于TCP的聊天程序,需要使用的类有:
QTcpServer 编辑
QTcpSocket 编辑
QTextStream
服务端:server(QTcpServer)
步骤:
代码:
dialog.h
dialog.cpp
客户端:client(QTcpSocket)
步骤:
代码:
dialog.h
dialog.cpp
dialog.ui
运行效果:
客户端
服务器
服务器管理类:管理服务器的多个连接,直接继承了QObject,因此不具备IO能力。
相关函数如下:
// 构造函数 QTcpServer::QTcpServer(QObject * parent = 0)
// 服务器开启监听,等待客户主动发起连接 // 参数1:监听来自于哪个IP地址的请求,默认值为不限制IP地址,QHostAddress类是IP地址的封装类。 // 参数2:服务器端口号 // 返回值:监听开启结果 bool QTcpServer::listen( const QHostAddress & address = QHostAddress::Any, quint16 port = 0)
// 有新连接建立的通知信号 void QTcpServer::newConnection() [signal]
// 服务器是否还在监听 bool QTcpServer::isListening() const
// 关闭服务器 void QTcpServer::close()
// 返回一个就绪的连接对象,此对象用于跟某个客户端进行IO操作 QTcpSocket * QTcpServer::nextPendingConnection() [virtual]
TCP连接类:进行网络IO操作,间接继承QIODevice类。
相关函数如下:
// 构造函数 QTcpSocket::QTcpSocket(QObject * parent = 0)
// 连接到服务器 // 参数1:服务器的IP地址 // 参数2:服务器的端口号 // 参数3:读写模式,默认为可读可写 void QAbstractSocket::connectToHost(const QString & hostName, quint16 port, OpenMode openMode = ReadWrite) [virtual]
// 连接是否处于打开状态 bool QIODevice::isOpen() const
// 关闭连接 void QIODevice::close() [virtual]
// 拿到对面的IP地址封装类对象,如果没有连接返回QHostAddress::Null QHostAddress QAbstractSocket::peerAddress() const
// 连接断开发射的信号 void QAbstractSocket::disconnected() [signal]
文本流类:是一种高效地文本数据IO的辅助类。
①创建QTcpServer对象
②监听list需要的参数是地址和端口号
③当有新的客户端连接成功回发送newConnect信号
④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象
⑤连接QTcpSocket对象的readRead信号
⑥在readRead信号的槽函数使用read接收数据
⑦调用write成员函数发送数据
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
//网络相关类
#include
#include
#include
#include
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpServer *server;//服务器对象
QTcpSocket *socket=NULL;
private slots:
void newConnSlot();//新连接的槽函数
void disconnectedSlot(); //网络连接断开的槽函数
void readReadSlot(); //读取客户端信息的槽函数
void btnSendClickedSlot();//发送给客户端消息的槽函数
};
#endif // DIALOG_H
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//设置窗口标记为顶层
setWindowFlags(Qt::WindowStaysOnTopHint);
//创建管理类对象
server=new QTcpServer(this);
//连接服务器通知的信号槽
connect(server,SIGNAL(newConnection()),this,SLOT(newConnSlot()));
//向客户端发送信息的信号槽
connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickedSlot()));
// 服务器开启监听,等待客户主动发起连接
// 参数1:监听来自哪个IP地址的请求,默认值为不限制IP地址,QHostAddress类是IP地址的封装类。
// 参数2:服务器端口号
server->listen(QHostAddress::Any,8887);
}
Dialog::~Dialog()
{
if(server->isListening())//如果在监听
server->close();//关闭服务器
delete ui;
}
void Dialog::newConnSlot()
{
//踢掉之前的连接
if(socket!=NULL)
{
socket->close();
}
//拿到与客户端进行连接的QTcpSocket对象
socket=server->nextPendingConnection();
//建立断链通知的信号槽
connect(socket,SIGNAL(disconnected()), this,SLOT(disconnectedSlot()));
//建立读取消息的信号槽
connect(socket,SIGNAL(readyRead()),this,SLOT(readReadSlot()));
//拿到客户端的ip和端口号
QString ip=socket->peerAddress().toString();
quint16 port=socket->peerPort();
QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append("新连接来了!");
ui->textBrowser->append("");
ui->textBrowser->append(ip.append(":").append(QString::number(port)));
ui->textBrowser->append("");
}
void Dialog::disconnectedSlot()
{
//拿到客户端的ip和端口号
QString ip=socket->peerAddress().toString();
quint16 port=socket->peerPort();
QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append("连接结束了!");
ui->textBrowser->append("");
ui->textBrowser->append(ip.append(":").append(QString::number(port)));
ui->textBrowser->append("");
}
void Dialog::readReadSlot() //读取客户端信息
{
QTextStream input(socket);
QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
//读取数据
QString msg=input.readAll();
//展示内容
ui->textBrowser->append(time);
ui->textBrowser->append(msg);
}
void Dialog::btnSendClickedSlot() //向客户端发送消息
{
//获取用户输入的内容
QString info=ui->lineEdit->text();
if(info=="")
{
QMessageBox::warning(this,"提示","请输入发送的内容");
return;
}
//创建文本流对象
QTextStream output(socket);
//发送内容
output<lineEdit->clear();
}
①创建QTcpSocket对象
②当对象与Server连接成功时会发送connected 信号
③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号
④connected信号的槽函数开启发送数据
⑤使用write发送数据,read接收数据
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
#include
//连接类
#include
#include
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpSocket *client;//连接对象
QTcpSocket *socket=NULL;
private slots:
void btnConnClickedSlot();//连接按钮的槽函数
void btnSendClickedSlot();//发送按钮的槽函数
void connectedSlot(); //连接的槽函数
void disconnectedSlot(); //断开连接的槽函数
void readInfoSlot();//接收信息的槽函数
};
#endif // DIALOG_H
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->pushButtonConn,SIGNAL(clicked()),this,SLOT(btnConnClickedSlot()));
connect(ui->pushButtonSend,SIGNAL(clicked()), this,SLOT(btnSendClickedSlot()));
//设置窗口标记为顶层
setWindowFlags(Qt::WindowStaysOnTopHint);
//创建连接对象
client=new QTcpSocket(this);
//连接状态检测的信号槽
connect(client,SIGNAL(connected()),this,SLOT(connectedSlot()));
connect(client,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));
//读取服务器发来消息的信号槽
connect(client,SIGNAL(readyRead()),this,SLOT(readInfoSlot()));
}
Dialog::~Dialog()
{
if(client->isOpen())//如果连接处于打开状态
client->close();//关闭连接
delete ui;
}
void Dialog::btnConnClickedSlot()
{
// 默认输入有效,连接到服务器
// 参数1:服务器的IP地址
// 参数2:服务器的端口号
client->connectToHost(ui->lineEditIp->text(),8887);
}
void Dialog::btnSendClickedSlot()
{
//获取用户输入的内容
QString msg=ui->lineEditInfo->text();
if(msg=="")
{
QMessageBox::warning(this,"提示","请输入要发送的内容!");
return;
}
//创建文本流对象
QTextStream output(client);
//发送内容
output<lineEditInfo->clear();
}
void Dialog::connectedSlot()
{
//屏蔽连接按钮
ui->pushButtonConn->setEnabled(false);
ui->pushButtonConn->setText("已连接");
//释放发送按钮
ui->pushButtonSend->setEnabled(true);
}
void Dialog::disconnectedSlot()
{
//恢复连接按钮
ui->pushButtonConn->setEnabled(true);
ui->pushButtonConn->setText("连接");
//屏蔽发送按钮
ui->pushButtonSend->setEnabled(false);
}
void Dialog::readInfoSlot()
{
QTextStream input(client);
QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
//读取数据
QString info=input.readAll();
ui->textBrowser->append(time);
ui->textBrowser->append(info);
}