首先声明此文章为学习Qt的网络通讯找的例子,仅供学习用,以下为自己总结,原作者的连接如下:GitHub - manfredipist/QTcpSocket: A simple Qt client-server TCP architecture to transfer data between peersA simple Qt client-server TCP architecture to transfer data between peers - GitHub - manfredipist/QTcpSocket: A simple Qt client-server TCP architecture to transfer data between peershttps://github.com/manfredipist/QTcpSocket
解决的问题:
在学习网络通讯时,Qt给你封装好了QTcpSocket类,来进行网络套接字通讯,经常会有需求进行一对多的功能,一台服务器,对多台客户端的开发,应用到实践中
如何实现:
实现分为:1、客户端 Client
2、服务器端 Server
约定的数据格式头
fileType:attachment 、 message
QString("fileType:message,fileName:null,fileSize:%1;").arg(str.size()).toUtf8()
代码块解析:
客户端 Client
.h文件
//1:读数据
void readSocket();
//2:断开连接
void discardSocket();
//3:错误连接
void displayError(QAbstractSocket::SocketError socketError);
//4:发送数据
void sendMessage();
.cpp文件
//1:连接
socket->connectToHost(QHostAddress::LocalHost,8080);
//2:读取数据在readyRead槽下
void MainWindow::readSocket()
{
QByteArray buffer;
QDataStream socketStream(socket);
socketStream.setVersion(QDataStream::Qt_5_7);
socketStream.startTransaction();
socketStream >> buffer;
QString header = buffer.mid(0,128);
QString fileType = header.split(",")[0].split(":")[1];
buffer = buffer.mid(128);
if(fileType=="attachment"){
//TODO
}else if(fileType=="message"){
//TODO
QString message = QString("%1 :: %2").arg(socket->socketDescriptor()).arg(QString::fromStdString(buffer.toStdString()));
}
}
//3:发送数据
void Mainindow::sendMessage()
{
//1:组装数据
QString str = ui->lineEdit_message->text();
QDataStream socketStream(socket);
socketStream.setVersion(QDataStream::Qt_5_7);
QByteArray header;
header.prepend(QString("fileType:message,fileName:null,fileSize:%1;").arg(str.size()).toUtf8());
header.resize(128);
//2:发送数据的包封装方式
QByteArray byteArray = str.toUtf8();
byteArray.prepend(header);
//3:数据发送
socketStream << byteArray;
}
服务器端 Server
1:监听端口
m_server = new QTcpServer();
m_server->listen(QHostAddress::Any, 8080)
2:当有客户端client连接时,发出newConnection 信号,由于要进行多客户端功能,得把客户端给存起来
void MainWindow::appendToSocketList(QTcpSocket* socket)
{
connection_set.insert(socket);
connect(socket, &QTcpSocket::readyRead, this, &MainWindow::readSocket);
connect(socket, &QTcpSocket::disconnected, this, &MainWindow::discardSocket);
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
ui->comboBox_receiver->addItem(QString::number(socket->socketDescriptor()));
displayMessage(QString("INFO :: Client with sockd:%1 has just entered the room").arg(socket->socketDescriptor()));
}
void MainWindow::newConnection()
{
while (m_server->hasPendingConnections())
appendToSocketList(m_server->nextPendingConnection());
}
3:readSocket()功能与客户端client一致,唯一区别,打印的时候,带上了客户端连接的唯一标识:socket->socketDescriptor
4:reinterpret_cast<>用法将sender()转换成socket对象
reinterpret_cast与static_cast_云之舟_的博客-CSDN博客_reinterpret_cast
5:分发消息的机制
void MainWindow::sendMessage(QTcpSocket* socket)
{
if(socket)
{
if(socket->isOpen())
{
QString str = ui->lineEdit_message->text();
QDataStream socketStream(socket);
socketStream.setVersion(QDataStream::Qt_5_7);
QByteArray header;
header.prepend(QString("fileType:message,fileName:null,fileSize:%1;").arg(str.size()).toUtf8());
header.resize(128);
QByteArray byteArray = str.toUtf8();
byteArray.prepend(header);
socketStream.setVersion(QDataStream::Qt_5_7);
socketStream << byteArray;
}
else
QMessageBox::critical(this,"QTCPServer","Socket doesn't seem to be opened");
}
else
QMessageBox::critical(this,"QTCPServer","Not connected");
}
void MainWindow::on_pushButton_sendMessage_clicked()
{
QString receiver = ui->comboBox_receiver->currentText();
if(receiver=="Broadcast")
{
foreach (QTcpSocket* socket,connection_set)
{
sendMessage(socket);
}
}
else
{
foreach (QTcpSocket* socket,connection_set)
{
if(socket->socketDescriptor() == receiver.toLongLong())
{
sendMessage(socket);
break;
}
}
}
ui->lineEdit_message->clear();
}