Qt的UDP编程

实现的是用户登录既是服务器端也是客户端。

服务器端:创建UDP端口,绑定固定端口,用信号和槽机制来监听是否有数据来临,如果有,读取数据的消息类型,如果是新用户登录消息,读取新用户信息,在用户列表中添加用户信息,如果是聊天信息,读取信息,显示在聊天窗口中。如果是下线信息,就读取用户信息,用户列表中删除,流程如下:

Qt的UDP编程_第1张图片

客户端:登录时获取用户名、主机名和IP地址,并广播给局域网中的服务器,更新用户列表。当用聊天信息有发送时,将用户名、主机名和IP地址及聊天信息广播出去,流程如下:

Qt的UDP编程_第2张图片


程序代码如下:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 

namespace Ui {
class Widget;
}

enum MessageType {Message, NewParticipant, ParticipantLeft, FileName, Refuse};

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void newParticipant(QString userName, QString localHostName, QString ipAddress);
    void participantLeft(QString userNme, QString localHostName, QString time);
    void sendMessage(MessageType type, QString serverAddress = "");
    QString getIP();
    QString getUserName();
    QString getMessage();

private slots:
    void prcessPendingDatagrams();
    void on_sendButton_clicked();

private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket;
    quint16 port;

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    udpSocket = new QUdpSocket(this);
    port = 45454;

    udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    connect(udpSocket,SIGNAL(readyRead()), this, SLOT(prcessPendingDatagrams()));
    sendMessage(NewParticipant);

}

Widget::~Widget()
{
    delete ui;
}


void Widget::sendMessage(MessageType type, QString serverAddress)
{
    QByteArray data;
    QDataStream out(&data, QIODevice::WriteOnly);
    QString localHostName = QHostInfo::localHostName();
    QString address = getIP();
    out << type << getUserName() << localHostName;

    switch (type) {
    case Message:

        if (ui->messageTextEdit->toPlainText() == "") {
            QMessageBox::warning(0, QStringLiteral("警告"), QStringLiteral("发送内容不能为空"), QMessageBox::Ok);
            return;
        }
        out << address << getMessage();
        ui->messageBrowser->verticalScrollBar()->setValue(ui->messageBrowser->verticalScrollBar()->maximum());
        break;
    case NewParticipant:
        out << address;
        break;
    case ParticipantLeft:
        break;
    case FileName:
        break;
    case Refuse:
        break;
    }
    udpSocket->writeDatagram(data, data.length(), QHostAddress::Broadcast, port);
}

void Widget::prcessPendingDatagrams()
{
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size());
        QDataStream in(&datagram, QIODevice::ReadOnly);
        int messageType;
        in >> messageType;
        QString userName, localHostName, ipAddress, message;
        QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");

        switch (messageType) {
        case Message:
            in >> userName >> localHostName >> ipAddress >> message;
            ui->messageBrowser->setTextColor(Qt::blue);
            ui->messageBrowser->setCurrentFont(QFont("Times New Roman", 12));
            ui->messageBrowser->append("[" + localHostName + "]" + time);
            ui->messageBrowser->append(message);
            break;
        case NewParticipant:
            in >> userName >> localHostName >> ipAddress;
            newParticipant(userName, localHostName,ipAddress);
            break;
        case ParticipantLeft:
            in >> userName >> localHostName;
            participantLeft(userName, localHostName, time);
            break;
        case FileName:
        case Refuse:
            break;
        }
    }
}

void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
{
    bool isEmpty = ui->userTableWidget->findItems(localHostName, Qt::MatchExactly).isEmpty();
    if (isEmpty) {
        QTableWidgetItem* user = new QTableWidgetItem(userName);
        QTableWidgetItem* host = new QTableWidgetItem(localHostName);
        QTableWidgetItem* ip = new QTableWidgetItem(ipAddress);

        ui->userTableWidget->insertRow(0);
        ui->userTableWidget->setItem(0, 0, user);
        ui->userTableWidget->setItem(0, 1, host);
        ui->userTableWidget->setItem(0, 2, ip);
        ui->messageBrowser->setTextColor(Qt::gray);
        ui->messageBrowser->setCurrentFont(QFont("Times New Roman", 10));

        ui->messageBrowser->append(QStringLiteral("%1 在线!").arg(userName));
        ui->userNumLabel->setText(QStringLiteral("在线人数:%1").arg(ui->userTableWidget->rowCount()));

    }
}

void Widget::participantLeft(QString userNme, QString localHostName, QString time)
{
    int rowNum = ui->userTableWidget->findItems(localHostName, Qt::MatchExactly).first()->row();
    ui->userTableWidget->removeRow(rowNum);
    ui->messageBrowser->setTextColor(Qt::gray);
    ui->messageBrowser->setCurrentFont(QFont("Times New Roman", 10));
    ui->messageBrowser->append(QStringLiteral("%1 于 %2离开").arg(userNme).arg(time));
    ui->userNumLabel->setText(QStringLiteral("在线人数:%1").arg(ui->userTableWidget->rowCount()));
}

QString Widget::getIP()
{
    QList list = QNetworkInterface::allAddresses();

    foreach(QHostAddress address, list) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol) return address.toString();
    }

    return 0;
}


QString Widget::getUserName()
{
    QStringList envVariables;
    envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*" << "HOSTNAME.*" << "DOMAINNAM.*";
    QStringList environment = QProcess::systemEnvironment();
    foreach (QString string, environment) {
        int index = environment.indexOf(QRegExp(string));
        if (index != -1) {
            QStringList stringList = environment.at(index).split('=');
            if (stringList.size() == 2) {
                return stringList.at(1);
            }
        }
    }

    return "unknown";
}

QString Widget::getMessage()
{
    QString msg = ui->messageTextEdit->toHtml();
    ui->messageTextEdit->clear();
    ui->messageTextEdit->setFocus();

    return msg;
}

void Widget::on_sendButton_clicked()
{
    sendMessage(Message);
}

main.cpp

#include "widget.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}
注意:在qt中的信号与槽机制中,通过鼠标操作来关联槽,在生成的代码中是没有connect的,以按钮sendButton为例,生成的槽函数为on_sendButton_click(),当你在构造函数中再一次用connect关联时,会触发两次,导致会弹出“发送内容为空”的对话框。


你可能感兴趣的:(Qt)