本项目分为服务器与客户端,用了qt的ui设计界面
服务器页面
客户端页面
两个按钮的样式为:
background:rgb(117, 117, 117);
border-radius:20px;
background:rgb(117, 117, 117);
border-radius:10px;
无论是客户端还是服务器,都需要在pro文件内添加
QT += network
否则无法识别头文件
服务器端:
先要实例化一个服务器,并把标识符isOk置为false,不过其实因为局限于个人水平,我没找到如何用qt实现让服务器与客户端断开,所以这个标识符其实并没有实际效果。只能利用它,直接关闭服务器页面。(但凡换成C,我就会写了)
//实例化服务器
server = new QTcpServer(this);
isOk = false;
按钮对应的槽函数:
//启动按钮对应的槽函数
void ChatServer::on_pushButton_clicked()
{
if(isOk == false)
{
quint16 port = quint16( ui->portEdit->text().toInt());
//将服务器设置为监听状态
/*bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)
* 功能:服务器监听客户端的连接
* 参数:
* address:主机地址
* port:端口号
* 返回值:
* true:创建成功
* false:创建失败
*/
server->listen(QHostAddress::Any, port);
//将相应的控件设置为不可用
ui->portEdit->setEnabled(false);
ui->pushButton->setText("退出服务器");
isOk = true;
//当有新的客户端连接到服务器后,会发出newConnection的信号
connect(server, &QTcpServer::newConnection, this,
&ChatServer::on_newConnection_slot);
}
else
{
ui->pushButton->setText("连接服务器");
this->close(); //直接退出服务器
}
}
按钮内的connect信号:
//connect对应的槽函数
void ChatServer::on_newConnection_slot()
{
/*QTcpSocket *nextPendingConnection();
* 功能:获取最新连接的客户端的套接字
* 参数:无
* 返回值:新客户的套接字
*/
QTcpSocket *socket = server->nextPendingConnection();
//将该套接字放入套接字链表中
socketList.append(socket);
//当服务器接收到客户端传过来的消息时,就会触发一个readyRead信号,在信号对应的槽函数中处理相关逻辑(自定义)
connect(socket, &QTcpSocket::readyRead, this, &ChatServer::on_readyRead_solt);
}
最后是这个readyRead信号
//readyRead对应槽函数的定义
void ChatServer::on_readyRead_solt()
{
//判断客户端套接字是否有效
for(int i=0; i<socketList.count(); i++)
{
if(socketList.at(i)->state() == false)
{
socketList.removeAt(i);
}
}
//遍历客户端的链表,判断是哪一个客户端发送消息
for(quint16 i=0; i<socketList.count(); i++)
{
/*qint64 bytesAvailable()
*功能:获取客户端中待读取数据的个数
* 参数:无
* 返回值:待读取数据的个数
*/
if(socketList.at(i)->bytesAvailable())
{
/*QByteArray readAll()
*参数:无
* 返回值:QByteArray类型函数
*/
QString mes = QString::fromLocal8Bit(socketList.at(i)->readAll()); //转换成字符串
//将消息展示到list widget上
ui->listWidget->addItem(mes);
//同时将消息广播出去
send(mes);
}
}
}
send函数
void ChatServer::send(QString mes)
{
for(int i=0; i<socketList.count(); i++)
{
socketList.at(i)->write(mes.toLocal8Bit());
}
}
客户端:
构造函数
//实例化socket
socket = new QTcpSocket;
//给连接状态初始值
isOk = false;
//将connect信号连接到自定义的槽函数中处理相关逻辑
connect(socket,&QTcpSocket::connected,this,&chatCliant::on_connect_slots);
//disconnected
connect(socket,&QTcpSocket::disconnected,this,&chatCliant::on_disconnect_slots);
//当客户端接收到服务器发的消息后
connect(socket, &QTcpSocket::readyRead, this, &chatCliant::on_readyRead_slot);
//连接服务器
void chatCliant::on_connectBin_clicked()
{
QString ip=ui->ipEdit->text();
quint16 port= ui->portEdit->text().toInt();
qDebug()<<"dddd";
if(isOk == false)
{
//连接服务器
socket->connectToHost(QHostAddress(ip),port);
//一旦连接成功,就会触发一个connected的信号,在该信号中处理逻辑
//将按钮文本改为断开连接
ui->connectBin->setText("断开服务器");
isOk = true;
ui->userNameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
}else
{
userName=ui->userNameEdit->text();
QString mes =userName + "退出群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器我滚了
//断开服务器
socket->disconnectFromHost();
//一旦连接成功,就会触发一个disconnected的信号
//将按钮文本改为"连接服务器"
ui->connectBin->setText("连接服务器");
isOk =false;
ui->userNameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
}
}
//connected信号对应槽函数的定义
void chatCliant::on_connect_slots()
{
userName=ui->userNameEdit->text();
QString mes =userName + "加入群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器我来了
}
//disconnected信号对应槽函数的定义
void chatCliant::on_disconnect_slots()
{
}
//readyRead信号对应槽函数的定义
void chatCliant::on_readyRead_slot()
{
//获取套接字中的数据
QString mes = QString::fromLocal8Bit( socket->readAll() );
//将数据显示在listwidget中
ui->listWidget->addItem(mes);
}
//发送按钮对应的槽函数
void chatCliant::on_pushButton_clicked()
{
userName = ui->userNameEdit->text();
QString mes = userName + ": " + ui->mesEdit->text();
//发送给服务器
socket->write(mes.toLocal8Bit());
//清空消息内容
ui->mesEdit->clear();
}