浅谈 Qt 中 UDP 之 UdpSocket通信实例

  • Post author:
  • Post category:其他



浅谈 Qt 中 UDP  写这篇博客的原因是Java大作业最近完成了一个简单的聊天室。也是基于UDP的。正好我们在学习Qt。所以我想能不能再qt中同样实现这样一个问题。于是我进行的代码的编辑。以及其他等方面的思考和学习。







UDP(User Datagram Protocol即用户数据报协议)是一个轻量级的,不可靠的,面向数据报的无连接协议。我们现在几乎每个人都使用的QQ,其聊天时就是使用UDP协议进行消息发送的。就像QQ那样,当有很多用户,发送的大部分都是短消息,要求能及时响应,并且对安全性要求不是很高的情况下使用UDP协议。在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人十分不满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。所以qq这种对保密要求并不太高的聊天程序就是使用的UDP协议。





在Qt中提供了QUdpSocket 类来进行UDP数据报(datagrams)的发送和接收。这里我们还要了解一个名词Socket,也就是常说的“套接字”。Socket简单地说,就是一个IP地址加一个port端口  。因为我们要传输数据,就要知道往哪个机子上传送,而IP地址确定了一台主机,但是这台机子上可能运行着各种各样的网络程序,我们要往哪个程序中发送呢?这时就要使用一个端口来指定UDP程序。所以说,Socket指明了数据报传输的路径。这些和Java中的情况基本一致。不再继续介绍了。




由于刚接触不久,所以还是以看代码来学习。这次主要是学Qt下UDP的编程,且熟悉一些Qt下代码的编写流程。



我想试验的程序实现的用户之间的通信。此时得有客户端和服务器端的区别了。每个用户登录既是客户端又是服务器端。

服务器端

:建立一个UDP Socket并绑定在固定端口后,用信号与槽的方式进行监听是否有数据来临。如果用,接收其数据并分析数据的消息类型,如果消息是新用户登录则更新用户列表并在聊天显示窗口中添加新用户上线通知;如果是用户下线,则在用户列表中删除该用户且在聊天显示窗口中显示下线通知;如果是聊天消息,则接收该消息并且在窗口中显示。

客户端

:首先当客户端登录时,获取本机的用户名,计算机名和ip地址,并广播给局域网的服务器更新用户列表。然后当客户端需要发送信息时,则在聊天输入栏中输入信息并按发送键发送聊天内容,当然于此同时也广播本地系统的各种信息。



下面的源码虽然没有实现多个用户之间的通信。但是也是完成了简单的单播。程序运行时候,要先运行接收端,再运行发送端就可以实现简单的广播。而写出可视化界面的多人聊天服务器才是我想做的问题。我可以贴出我在Java中所学习的代码。加以对照学习。毕竟语言的学习都是互通的。



qt源码如下:



发送端代码main.cpp


#include <QByteArray>
#include <QCoreApplication>
#include <QHostAddress>
#include <QUdpSocket>

const quint16 PORT = 2333;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QUdpSocket qus;
//  qus.bind(QHostAddress("127.0.0.1"), PORT+1);
    QByteArray msg = "Hello world!";
    std::cout << "--- Sender ---" << std::endl;
    for(int i=0; i<100; ++i)
        qus.writeDatagram(msg, QHostAddress("127.0.0.1"), PORT);

    return a.exec();
}


接收端UdpReceiver.h

#ifndef UDPRECEIVER_H
#define UDPRECEIVER_H

#include <QObject>
#include <QUdpSocket>

class UdpReceiver : public QObject
{
    Q_OBJECT

public:
    UdpReceiver(QObject *p = 0);
    ~UdpReceiver();

public slots:
    void receive();

private:
    QUdpSocket *uSocket;
};

#endif // UDPRECEIVER_H


UdpReceiver.cpp

#include <QByteArray>
#include <iostream>
#include "UdpReceiver.h"

const quint16 PORT = 2333;

UdpReceiver::UdpReceiver(QObject *p) :
    QObject(p)
{
    uSocket = new QUdpSocket;
    uSocket->bind(QHostAddress("127.0.0.1"), PORT);
    connect(uSocket, SIGNAL(readyRead()), this, SLOT(receive()));
}

UdpReceiver::~UdpReceiver()
{
    delete uSocket;
}

void UdpReceiver::receive()
{
    QByteArray ba;
    while(uSocket->hasPendingDatagrams())
    {
        ba.resize(uSocket->pendingDatagramSize());
        uSocket->readDatagram(ba.data(), ba.size());
        std::cout << ba.data() << std::endl;
    }
}


mian.cpp

#include <QCoreApplication>
#include "udpreceiver.h"
#include <iostream>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    UdpReceiver ur;
    std::cout << "--- Recevier ---" << std::endl;

    return a.exec();
}

此代码来源为

点击打开链接

工程结果为




通过我初步的学习我想知道我如何才能够将上面的单播升级为互播。这是我接下来要思考的问题




版权声明:本文为weixin_42216430原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。