为了实现两个电脑互相发信息,需要使用两个客户端和一个服务器。
一个客户端用于连接服务器并向其发送数据,另一个客户端也用于连接服务器并接收数据。在这种情况下,服务器就起到了转发消息的作用。
因此,需要实现一个TCP服务器和两个TCP客户端,其中一个客户端用于发送消息,另一个客户端用于接收消息。当有一方发送消息时,服务器就会将该消息转发给另一方。
具体步骤如下:
- 实现TCP服务器
可以通过继承QTcpServer类来实现TCP服务器。具体代码示例:
class MyTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = nullptr);
protected:
void incomingConnection(qintptr socketDescriptor) override;
private slots:
void readData();
private:
QList<QTcpSocket *> m_clients;
};
MyTcpServer::MyTcpServer(QObject *parent) : QTcpServer(parent)
{
}
void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << "New client connected!";
// 创建新的socket与客户端进行通信
QTcpSocket *client = new QTcpSocket(this);
client->setSocketDescriptor(socketDescriptor);
connect(client, &QTcpSocket::readyRead, this, &MyTcpServer::readData);
// 将新的socket加入到列表中
m_clients.append(client);
}
void MyTcpServer::readData()
{
QObject *senderObj = sender();
if (senderObj == nullptr) {
return;
}
QTcpSocket *client = qobject_cast<QTcpSocket *>(senderObj);
if (client == nullptr) {
return;
}
// 从客户端读取数据
QByteArray data = client->readAll();
// 转发给其他客户端
for (QTcpSocket *otherClient : m_clients) {
if (otherClient != client && otherClient->state() == QAbstractSocket::ConnectedState) {
otherClient->write(data);
}
}
}
在incomingConnection()函数中,当有新的客户端连接时,就会创建一个新的QTcpSocket对象与其进行通信,并将该socket加入到m_clients列表中。
在readData()函数中,当有客户端发送数据时,服务器就会将该数据转发给所有其他的已连接客户端。
- 实现TCP客户端
需要实现两个TCP客户端:一个用于向服务器发送消息,另一个用于接收来自服务器转发的消息。
代码示例:
class MyTcpClient : public QObject
{
Q_OBJECT
public:
explicit MyTcpClient(QObject *parent = nullptr);
signals:
void dataReceived(const QString &data);
public slots:
void connectToHost(const QString &hostName, quint16 port);
void sendData(const QString &data);
private slots:
void readData();
private:
QTcpSocket *m_socket;
};
MyTcpClient::MyTcpClient(QObject *parent) : QObject(parent)
{
}
void MyTcpClient::connectToHost(const QString &hostName, quint16 port)
{
m_socket = new QTcpSocket(this);
connect(m_socket, &QTcpSocket::readyRead, this, &MyTcpClient::readData);
m_socket->connectToHost(hostName, port);
}
void MyTcpClient::sendData(const QString &data)
{
if (m_socket != nullptr && m_socket->state() == QAbstractSocket::ConnectedState) {
QByteArray bytes = data.toUtf8();
m_socket->write(bytes);
}
}
void MyTcpClient::readData()
{
QObject *senderObj = sender();
if (senderObj == nullptr) {
return;
}
QTcpSocket *socket = qobject_cast<QTcpSocket *>(senderObj);
if (socket == nullptr) {
return;
}
// 从服务器接收数据
QByteArray data = socket->readAll();
// 发送信号通知UI更新
emit dataReceived(QString(data));
}
其中,一个客户端用于向服务器发送消息,另一个客户端用于接收来自服务器转发的消息。在MyTcpClient类中可以定义一个信号dataReceived(),当有新的数据传入时就会触发该信号。
- 在UI中使用TCP客户端
在UI中,可以通过实例化两个MyTcpClient对象来分别作为发送方和接收方。
具体代码示例:
class MainWindow : public QMainWindow
{
public:
explicit MainWindow(QWidget *parent = nullptr);
private slots:
void on_sendButton_clicked();
void onDataReceived(const QString &data);
private:
Ui::MainWindow *ui;
MyTcpClient *m_sender;
MyTcpClient *m_receiver;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_sender = new MyTcpClient(this);
connect(m_sender, &MyTcpClient::dataReceived, this, &MainWindow::onDataReceived);
m_receiver = new MyTcpClient(this);
connect(m_receiver, &MyTcpClient::dataReceived, this, &MainWindow::onDataReceived);
// 连接到服务器
m_sender->connectToHost("127.0.0.1", 1234);
m_receiver->connectToHost("127.0.0.1", 1234);
}
void MainWindow::on_sendButton_clicked()
{
QString message = ui->messageEdit->toPlainText();
m_sender->sendData(message);
}
void MainWindow::onDataReceived(const QString &data)
{
ui->textBrowser->append(data);
}
在UI中,当用户点击发送按钮时,就会将消息通过m_sender对象发送给服务器。而当有数据传入时,就会通过m_receiver对象来接收数据,并将其显示在UI的textBrowser控件中。
需要注意的是,在实现TCP客户端和服务器时,需要考虑网络延迟、网络异常等情况。因此,在实际应用中需要对异常情况进行处理,以保证程序的稳定性和健壮性。