TCP服务器一对多实例
- 服务器的搭建步骤
-
- 1.实例化QTcpServer对象
- 2.监听
- 3.绑定客户端连接的信号和槽
- 4.自定客户端连接的槽函数并绑定客户端会发出信号的槽函数
- 5.处理客户端发送过来的消息
- 6.处理客户端断开连接
- 7.服务器退出
- 客户端的搭建步骤
- 源码
-
- qtcpserver.h
- qtcpserver.cpp
- main.cpp
- 实例效果如下图
编程环境 VS2008 + Qt4.7
代码思路:用QList<QTcpSocket *> socketClient将所有连接上来的客户端Socket描述符都保存起来,当服务器接收到一个客户端发来的消息的时候,就把此消息发送给其他所有的客户端,当一个客户端断开连接发出disconnected()信号的时候,就把这个描述符从链表中删掉并释放掉
服务器的搭建步骤
1.实例化QTcpServer对象
QTcpServer *MyServer = new QTcpServer(this);
// 可以将QTcpServer描述符理解为监听描述符,用于监听
2.监听
MyServer->listen(QHostAddress::Any,1997);
// QHostAddress::Any -- 监听所有地址
// 1997 -- 端口号,可自定
3.绑定客户端连接的信号和槽
connect(MyServer,SIGNAL(newConnection()),this,SLOT(handleConnect()),Qt::UniqueConnection);
// newConnection()[signal] -- 如果有新连接上来的客户端就会触发此信号
4.自定客户端连接的槽函数并绑定客户端会发出信号的槽函数
// 客户端会emit的信号
// disconnected()[signal] -- 客户端断开连接
// readyRead()[signal] -- 客户端发送消息
void QtServer::handleConnect()
{
QTcpSocket *client = new QTcpSocket(this);
client = MyServer->nextPendingConnection();
//用一个QList把所有连接上来的客户端描述符保存起来
socketClient.append(client);
connect(client,SIGNAL(readyRead()),this,SLOT(return_data()),Qt::UniqueConnection);
connect(client, SIGNAL(disconnected()),this,SLOT(handleDisconnect()));
}
5.处理客户端发送过来的消息
//将接收到的信息转发到其他的客户端
void QtServer::return_data()
{
char *buffer = new char[1024];
memset(buffer,0,1024);
QTcpSocket * sendclient = (QTcpSocket*)sender();//获取触发此槽函数的客户端的Socket
sendclient->read(buffer,1024);
//遍历socketClient,把接收到的信息转发到其他所有的客户端
foreach(QTcpSocket *sock,socketClient)
{
if(sock != sendclient)//判断此客户端socket是否为发送方
sock->write(buffer);
}
QString ip = sendclient->peerAddress().toString();
ui.recv_textEdit->append(ip+" : "+buffer);//将客户端发送过来的消息显示在主窗口的textEdit上
}
6.处理客户端断开连接
void QtServer::handleDisconnect()
{
QTcpSocket * sendclient = (QTcpSocket*)sender();
sendclient->close();//关闭此描述符
socketClient.removeOne(sendclient);//链表剔除此元素
}
7.服务器退出
//遍历链表一项一项断开连接并关闭
void QtServer::on_exit_pushButton_clicked()
{
foreach(QTcpSocket *sock,socketClient)
{
sock->disconnectFromHost();
sock->close();
}
MyServer->close();
this->close();
}
服务器的所有基本操作完成,客户端的操作可以看我之前的文章,里面有详细的介绍
客户端的搭建步骤
见我之前的博客,在此不再叙述 https://blog.csdn.net/weixin_46276101/article/details/113877603
源码
qtcpserver.h
//qtcpserver.h
#ifndef QTSERVER_H
#define QTSERVER_H
#include <QtGui/QMainWindow>
#include "ui_qtserver.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QStringList>
#include <QString>
#include <QDebug>
#include <QList>
#include <QString>
#include <cstdlib>
class QtServer : public QMainWindow
{
Q_OBJECT
public:
QtServer(QWidget *parent = 0, Qt::WFlags flags = 0);
~QtServer();
private slots:
void on_listen_pushButton_clicked();//点击开始监听
void on_exit_pushButton_clicked();//点击退出
void handleConnect();
void return_data();
void handleDisconnect();
private:
Ui::QtServerClass ui;
QTcpServer *MyServer;
QStandardItemModel *ItemModel;//操作ListView需要操作ItemModel
QStringList client_ip;
QList<QTcpSocket *> socketClient;//用于存放链接上来的客户端的Socket描述符
};
#endif // QTSERVER_H
qtcpserver.cpp
#include "qtserver.h"
QtServer::QtServer(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
MyServer = new QTcpServer(this);
ItemModel = new QStandardItemModel(this);
//为了安全起见在关闭前需要释放资源,禁止点击窗口直接左上角的X关闭,必须要点击exit按钮
setWindowFlags(Qt::CustomizeWindowHint|Qt::WindowMinimizeButtonHint|Qt::WindowMaximizeButtonHint);
socketClient.clear();
connect(ui.listen_pushButton,SIGNAL(clicked()),this,SLOT(on_listen_pushButton_clicked()),Qt::UniqueConnection);
connect(ui.exit_pushButton,SIGNAL(clicked()),this,SLOT(on_exit_pushButton_clicked()),Qt::UniqueConnection);
}
QtServer::~QtServer()
{
delete ItemModel;
delete MyServer;
}
void QtServer::on_listen_pushButton_clicked()
{
if(!MyServer->listen(QHostAddress::Any,1997))
{
QMessageBox::information(NULL,"Listen",QObject::tr("Listen error"));
}
else
{
//Qt::UniqueConnection -- 防止信号和槽多次连接
connect(MyServer,SIGNAL(newConnection()),this,SLOT(handleConnect()),Qt::UniqueConnection);
}
}
void QtServer::handleConnect()
{
QTcpSocket *client = new QTcpSocket(this);
client = MyServer->nextPendingConnection();
socketClient.append(client);
client_ip.clear();
QString ip = client->peerAddress().toString();
client_ip.append(ip);
//连接上来的客户端的ip地址显示在主窗口的listView中
for(int i = 0;i < client_ip.size();i++)
{
QString string = static_cast<QString>(client_ip.at(i));
QStandardItem *item = new QStandardItem(string);
ItemModel->appendRow(item);//加入每行的值
}
ui.client_listView->setModel(ItemModel);
connect(client,SIGNAL(readyRead()),this,SLOT(return_data()),Qt::UniqueConnection);
connect(client, SIGNAL(disconnected()),this,SLOT(handleDisconnect()));
}
//将接收到的信息转发到其他的客户端
void QtServer::return_data()
{
char *buffer = new char[1024];
memset(buffer,0,1024);
QTcpSocket * sendclient = (QTcpSocket*)sender();//获取触发此槽函数的客户端的Socket
sendclient->read(buffer,1024);
foreach(QTcpSocket *sock,socketClient)
{
if(sock != sendclient)
sock->write(buffer);
}
QString ip = sendclient->peerAddress().toString();
ui.recv_textEdit->append(ip+" : "+buffer);
}
void QtServer::handleDisconnect()
{
QTcpSocket * sendclient = (QTcpSocket*)sender();
QString ip = sendclient->peerAddress().toString();//获取ip
sendclient->close();//关闭此socket
socketClient.removeOne(sendclient);//从链表中剔除
//主窗口的listView移除此行
QList<QStandardItem *> tList = ItemModel->findItems (ip);
QStandardItem *tItem = tList.at(0);
int row = tItem->row();
ItemModel->removeRow(row);
}
void QtServer::on_exit_pushButton_clicked()
{
foreach(QTcpSocket *sock,socketClient)
{
sock->disconnectFromHost();
sock->close();
}
MyServer->close();
this->close();
}
main.cpp
#include "qtserver.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtServer w;
w.show();
return a.exec();
}
实例效果如下图
另外求助一下各位大佬,我的主窗口上的textEdit为什么显示中文的时候是乱码,应该怎么解决