Qt的UDP编程

来源:互联网 发布:js当窗口大小变化 编辑:程序博客网 时间:2024/06/05 22:52

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

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

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


程序代码如下:

widget.h

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QUdpSocket>namespace Ui {class Widget;}enum MessageType {Message, NewParticipant, ParticipantLeft, FileName, Refuse};class Widget : public QWidget{    Q_OBJECTpublic:    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 <QHostInfo>#include <QMessageBox>#include <QScrollBar>#include <QDateTime>#include <QNetworkInterface>#include <QProcess>#include <QTableWidgetItem>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<QHostAddress> 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 <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    Widget w;    w.show();    return a.exec();}
注意:在qt中的信号与槽机制中,通过鼠标操作来关联槽,在生成的代码中是没有connect的,以按钮sendButton为例,生成的槽函数为on_sendButton_click(),当你在构造函数中再一次用connect关联时,会触发两次,导致会弹出“发送内容为空”的对话框。


0 0