QT示例:基于TCP 点对多通讯(server,clients)
一、服务器server
因为对于客户端来说,只能连接一个服务器。而对于服务器来说,它是面向多连接的,如何协调处理多客户端连接就显得尤为重要。
- 注意问题:
每个新加入的客户端,服务器给其分配一个SocketDescriptor后,就会emit newConnection()信号,但分配好的SocketDecriptor并没有通过newConnection()信号传递,所以用户得不到这个客户端标识SocketDescriptor。同样的,每当服务器收到新的消息时,客户端会emit readReady()信号,然而readReady()信号也没有传递SocketDescriptor, 这样的话,服务器端即使接收到消息,也不知道这个消息是从哪个客户端发出的。 - 解决的方法:
- 通过重写==[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor)==,获取soketDescriptor。自定义TcpClient类继承QTcpSocket,并将获得的soketDescriptor作为类成员。 这个方法的优点是:可以获取到soketDescriptor,灵活性高。缺点是:需要重写函数、自定义类。
- 在newConnection()信号对应的槽函数中,通过QTcpSocket *QTcpServer::nextPendingConnection()函数获取 新连接的客户端:Returns the next pending connection as a connected QTcpSocket object. 虽然仍然得不到soketDescriptor,**但可以通过QTcpSocket类的peerAddress()和peerPort()成员函数获取客户端的IP和端口号,同样是唯一标识。 **优点:无需重写函数和自定义类,代码简洁。缺点:无法获得SocketDecriptor,灵活性差。
本文示例为第二种方法:
1).pro 添加:
QT += network
2)主函数 main.cpp 添加:
#include "mytcpserver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyTcpServer w;
w.show();
return a.exec();
}
3)MyTcpServer.h 添加:
#include "mytcpserver.h"
#include "ui_mytcpserver.h"
MyTcpServer::MyTcpServer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyTcpServer)
{
ui->setupUi(this);
// 一 、创建QTcpSever对象;
tcpServer = new QTcpServer(this);
ui->edtIP->setText(QNetworkInterface().allAddresses().at(1).toString()); //获取本地IP
ui->btnConnect->setEnabled(true);
ui->btnSend->setEnabled(false);
// 设置默认按钮样式
ui->btnConnect->setStyleSheet("");
connect(tcpServer, &QTcpServer::newConnection, this, &MyTcpServer::NewConnectionSlot);
}
MyTcpServer::~MyTcpServer()
{
delete ui;
}
// 二、监听--断开
void MyTcpServer::on_btnConnect_clicked()
{
if(ui->btnConnect->text()=="监听")
{
bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());
if(ok)
{
ui->btnConnect->setText("断开");
ui->btnConnect->setStyleSheet("color: red;");
ui->btnSend->setEnabled(true);
}
}
else
{
for(int i=0; i<tcpClient.length(); i++) // 断开所有连接