• Qt:基于TCP和UDP的局域网P2P(局域网)通讯封装


    封装了一个类,可以进行在局域网进行P2P通讯(仅局域网可用)

    也就是说,假设局域网中有10台电脑,那么从本机发出的数据,将依次派发到这10台电脑(目前的设计中包括自己这台)

    在使用方面,构造的时候给端口和一些参数,然后只需要管send槽和accepted信号就可以了

    特性/原理介绍:

    1.UDP搜索

    2.TCP通讯(短连接)

    3.自带心跳包,自动维护可用ip

    4.TCP工作线程为单独的线程,稳定

    5.完全P2P,无需服务器

    注意:

    1.一台电脑只能使用单开,多开无法监听端口,就无法使用

    2.用到了C++11语法,所以请务必开启11模式,不然会编译报错

    3.使用前请在pro文件中加入

        QT += network concurrent

        CONFIG += c++11

    上源码:

    Jason_LanSocket.h

    [cpp] view plaincopy
     
    1. #ifndef __JasonQt_LanSocket_h__  
    2. #define __JasonQt_LanSocket_h__  
    3.   
    4. // Qt lib import  
    5. #include <QMap>  
    6. #include <QTcpSocket>  
    7. #include <QTcpServer>  
    8. #include <QUdpSocket>  
    9. #include <QNetworkAddressEntry>  
    10. #include <QtConcurrent>  
    11.   
    12. class JasonQt_LanSocket_TcpListen: public QTcpServer  
    13. {  
    14.     Q_OBJECT  
    15.   
    16. public:  
    17.     void incomingConnection(qintptr socketDescriptor);  
    18.   
    19. signals:  
    20.     void newConnect(const qintptr socketDescriptor);  
    21. };  
    22.   
    23. class JasonQt_LanSocket: public QObject  
    24. {  
    25.     Q_OBJECT  
    26.   
    27. private:  
    28.     quint16 m_udpPort;  
    29.     quint16 m_tcpPort;  
    30.     quint16 m_pingInterval;  
    31.     quint16 m_pingTimeout;  
    32.   
    33.     QTimer m_timerPing;  
    34.   
    35.     QUdpSocket m_udpListen;  
    36.     JasonQt_LanSocket_TcpListen m_tcpListen;  
    37.   
    38.     QThreadPool m_threadPool;  
    39.   
    40.     QNetworkAddressEntry m_NetworkAddressEntry;  
    41.     QMap<quint32, qint64> m_availableIp;  
    42.   
    43. public:  
    44.     JasonQt_LanSocket(const quint16 &udpPort, const quint16 &tcpPort,  
    45.                       const int &pingInterval = 1000, const int &pingTimeout = 10000,  
    46.                       const quint8 &threadPoolCount = 20);  
    47.   
    48.     bool begin(void);  
    49.   
    50.     static QNetworkAddressEntry getNetworkAddressEntry(void);  
    51.   
    52. public slots:  
    53.     void send(const QByteArray &data);  
    54.   
    55.     void ping(void);  
    56.   
    57. private slots:  
    58.     void udpNewConnect(void);  
    59.   
    60.     void tcpNewConnect(const qintptr &socketDescriptor);  
    61.   
    62. signals:  
    63.     void accepted(const QHostAddress address, const QByteArray data);  
    64.   
    65.     void newConnect(const QHostAddress address);  
    66.   
    67.     void disConnect(const QHostAddress address);  
    68.   
    69.     void sendSucceed(const QHostAddress address);  
    70. };  
    71.   
    72. #endif//__JasonQt_LanSocket_h__  

    Jason_LanSocket.cpp

    [cpp] view plaincopy
     
    1. #include "JasonQt_LanSocket.h"  
    2.   
    3. // JasonQt_LanSocket_TcpListen  
    4. void JasonQt_LanSocket_TcpListen::incomingConnection(qintptr socketDescriptor)  
    5. {  
    6.     emit newConnect(socketDescriptor);  
    7. }  
    8.   
    9. // JasonQt_LanSocket  
    10. JasonQt_LanSocket::JasonQt_LanSocket(const quint16 &udpPort, const quint16 &tcpPort,  
    11.                                      const int &pingInterval, const int &pingTimeout,  
    12.                                      const quint8 &threadPoolCount):  
    13.     m_udpPort(udpPort),  
    14.     m_tcpPort(tcpPort),  
    15.     m_pingInterval(pingInterval),  
    16.     m_pingTimeout(pingTimeout)  
    17. {  
    18.     connect(&m_timerPing, SIGNAL(timeout()), this, SLOT(ping()));  
    19.     connect(&m_udpListen, SIGNAL(readyRead()), this, SLOT(udpNewConnect()));  
    20.     connect(&m_tcpListen, SIGNAL(newConnect(qintptr)), this, SLOT(tcpNewConnect(qintptr)));  
    21.   
    22.     m_threadPool.setMaxThreadCount(threadPoolCount);  
    23. }  
    24.   
    25. bool JasonQt_LanSocket::begin(void)  
    26. {  
    27.     m_NetworkAddressEntry = getNetworkAddressEntry();  
    28.   
    29.     if(!m_NetworkAddressEntry.ip().toIPv4Address() || !m_udpListen.bind(QHostAddress::Any, m_udpPort) || !m_tcpListen.listen(QHostAddress::Any, m_tcpPort))  
    30.     {  
    31.         m_timerPing.stop();  
    32.         return false;  
    33.     }  
    34.   
    35.     m_timerPing.start(m_pingInterval);  
    36.   
    37.     return true;  
    38. }  
    39.   
    40. QNetworkAddressEntry JasonQt_LanSocket::getNetworkAddressEntry(void)  
    41. {  
    42.     auto allInterfaces = QNetworkInterface::allInterfaces();  
    43.   
    44.     // Scan en0  
    45.     for(const auto &interface: allInterfaces)  
    46.     {  
    47.         if(interface.name().indexOf("en0") != -1)  
    48.         {  
    49.             for(const auto &entry: interface.addressEntries())  
    50.             {  
    51.                 if(entry.ip().toIPv4Address())  
    52.                 {  
    53.                     return entry;  
    54.                 }  
    55.             }  
    56.         }  
    57.     }  
    58.   
    59.     // Scan other  
    60.     for(const auto &interface: allInterfaces)  
    61.     {  
    62.         for(const auto &entry: interface.addressEntries())  
    63.         {  
    64.             if(entry.ip().toIPv4Address())  
    65.             {  
    66.                 if(entry.ip().toString().indexOf("10.0.") == 0)  
    67.                 {  
    68.                     return entry;  
    69.                 }  
    70.                 else if(entry.ip().toString().indexOf("192.168.") == 0)  
    71.                 {  
    72.                     return entry;  
    73.                 }  
    74.             }  
    75.         }  
    76.     }  
    77.   
    78.     return QNetworkAddressEntry();  
    79. }  
    80.   
    81. void JasonQt_LanSocket::send(const QByteArray &data)  
    82. {  
    83.     for(auto it = m_availableIp.begin(); it != m_availableIp.end(); it++)  
    84.     {  
    85.         QtConcurrent::run(&m_threadPool, [=](const QHostAddress &address, const QByteArray &data)  
    86.         {  
    87.             auto socket = new QTcpSocket;  
    88.   
    89.             socket->connectToHost(address, m_tcpPort);  
    90.             if(!socket->waitForConnected(5000))     { socket->deleteLater(); return; }  
    91.   
    92.             socket->write(QString::number(data.size()).toLatin1());  
    93.             if(!socket->waitForBytesWritten(5000))  { socket->deleteLater(); return; }  
    94.   
    95.             if(!socket->waitForReadyRead(5000))     { socket->deleteLater(); return; }  
    96.             if(socket->readAll() != "OK")           { socket->deleteLater(); return; }  
    97.   
    98.             socket->write(data);  
    99.             if(!socket->waitForBytesWritten(5000))  { socket->deleteLater(); return; }  
    100.   
    101.             socket->waitForReadyRead(5000);  
    102.   
    103.             emit sendSucceed(address);  
    104.   
    105.             QTimer::singleShot(5000, socket, SLOT(deleteLater()));  
    106.         }, QHostAddress(it.key()), data);  
    107.     }  
    108. }  
    109.   
    110. void JasonQt_LanSocket::ping(void)  
    111. {  
    112.     auto &¤tTime = QDateTime::currentDateTime().toMSecsSinceEpoch();  
    113.     for(auto it = m_availableIp.begin(); it != m_availableIp.end(); it++)  
    114.     {  
    115.         if((currentTime - it.value()) > m_pingTimeout)  
    116.         {  
    117.             emit disConnect(QHostAddress(it.key()));  
    118.             m_availableIp.erase(it);  
    119.             it = m_availableIp.begin();  
    120.         }  
    121.     }  
    122.   
    123.     QJsonObject data;  
    124.     data.insert("Type", "Ping");  
    125.     data.insert("Ip", QString::number(m_NetworkAddressEntry.ip().toIPv4Address()));  
    126.   
    127.     auto socket = new QUdpSocket;  
    128.     socket->writeDatagram(QJsonDocument(data).toJson(), m_NetworkAddressEntry.broadcast(), m_udpPort);  
    129.     QTimer::singleShot(1000, socket, SLOT(deleteLater()));  
    130. }  
    131.   
    132. void JasonQt_LanSocket::udpNewConnect(void)  
    133. {  
    134.     while(m_udpListen.hasPendingDatagrams())  
    135.     {  
    136.         QByteArray datagram;  
    137.   
    138.         datagram.resize(m_udpListen.pendingDatagramSize());  
    139.         m_udpListen.readDatagram(datagram.data(), datagram.size());  
    140.   
    141.         QJsonObject data = QJsonDocument::fromJson(datagram).object();  
    142.   
    143.         if(data.contains("Type") && (data.value("Type").toString() == "Ping") && data.contains("Ip"))  
    144.         {  
    145.             if(m_availableIp.find(data.value("Ip").toString().toUInt()) == m_availableIp.end())  
    146.             {  
    147.                 emit newConnect(QHostAddress(data.value("Ip").toString().toUInt()));  
    148.             }  
    149.             m_availableIp[data.value("Ip").toString().toUInt()] = QDateTime::currentDateTime().toMSecsSinceEpoch();  
    150.         }  
    151.     }  
    152. }  
    153.   
    154. void JasonQt_LanSocket::tcpNewConnect(const qintptr &socketDescriptor)  
    155. {  
    156.     QtConcurrent::run(&m_threadPool, [=](const qintptr &socketDescriptor)  
    157.     {  
    158.         auto socket = new QTcpSocket;  
    159.         int psckageSize = -1;  
    160.         QByteArray buf;  
    161.   
    162.         if(!socket->setSocketDescriptor(socketDescriptor)) { socket->deleteLater(); return; }  
    163.         if(!socket->waitForConnected(5000)) { socket->deleteLater(); return; }  
    164.   
    165.         if(!socket->waitForReadyRead(5000)) { socket->deleteLater(); return; }  
    166.         psckageSize = socket->readAll().toInt();  
    167.   
    168.         socket->write("OK");  
    169.         socket->waitForBytesWritten(5000);  
    170.   
    171.         while(socket->waitForReadyRead(5000))  
    172.         {  
    173.             buf.append(socket->readAll());  
    174.         }  
    175.   
    176.         if(buf.size() != psckageSize) { socket->deleteLater(); return; }  
    177.   
    178.         socket->write("OK");  
    179.         socket->waitForBytesWritten(5000);  
    180.   
    181.         emit accepted(socket->peerAddress(), buf);  
    182.   
    183.         QTimer::singleShot(1000, socket, SLOT(deleteLater()));  
    184.     }, socketDescriptor);  
    185. }  

    我也写了一个示例工程,可以到下方链接中下载

    http://download.csdn.net/detail/wsj18808050/8369201

    http://blog.csdn.net/wsj18808050/article/details/42778751

  • 相关阅读:
    [转]谁抢了我的焦点
    VBA 对比两行数据
    VBA 自动得到分数
    VBA Excel 对比两列数据
    将图片读到二进制
    [转]常用字符与ASCII代码对照表
    [转]Java 运算符的优先级
    SqlBulkCopy 快速插入数据
    多列转一行
    C# 线程小结
  • 原文地址:https://www.cnblogs.com/findumars/p/5034560.html
Copyright © 2020-2023  润新知