封裝了一個類,能夠進行在局域網進行P2P通信(僅局域網可用)c++
也就是說,假設局域網中有10臺電腦,那麼從本機發出的數據,將依次派發到這10臺電腦(目前的設計中包括本身這臺)服務器
在使用方面,構造的時候給端口和一些參數,而後只須要管send槽和accepted信號就能夠了app
特性/原理介紹:socket
1.UDP搜索tcp
2.TCP通信(短鏈接)ui
3.自帶心跳包,自動維護可用ipthis
4.TCP工做線程爲單獨的線程,穩定spa
5.徹底P2P,無需服務器.net
注意:線程
1.一臺電腦只能使用單開,多開沒法監聽端口,就沒法使用
2.用到了C++11語法,因此請務必開啓11模式,否則會編譯報錯
3.使用前請在pro文件中加入
QT += network concurrent
CONFIG += c++11
上源碼:
Jason_LanSocket.h
- #ifndef __JasonQt_LanSocket_h__
- #define __JasonQt_LanSocket_h__
-
- #include <QMap>
- #include <QTcpSocket>
- #include <QTcpServer>
- #include <QUdpSocket>
- #include <QNetworkAddressEntry>
- #include <QtConcurrent>
-
- class JasonQt_LanSocket_TcpListen: public QTcpServer
- {
- Q_OBJECT
-
- public:
- void incomingConnection(qintptr socketDescriptor);
-
- signals:
- void newConnect(const qintptr socketDescriptor);
- };
-
- class JasonQt_LanSocket: public QObject
- {
- Q_OBJECT
-
- private:
- quint16 m_udpPort;
- quint16 m_tcpPort;
- quint16 m_pingInterval;
- quint16 m_pingTimeout;
-
- QTimer m_timerPing;
-
- QUdpSocket m_udpListen;
- JasonQt_LanSocket_TcpListen m_tcpListen;
-
- QThreadPool m_threadPool;
-
- QNetworkAddressEntry m_NetworkAddressEntry;
- QMap<quint32, qint64> m_availableIp;
-
- public:
- JasonQt_LanSocket(const quint16 &udpPort, const quint16 &tcpPort,
- const int &pingInterval = 1000, const int &pingTimeout = 10000,
- const quint8 &threadPoolCount = 20);
-
- bool begin(void);
-
- static QNetworkAddressEntry getNetworkAddressEntry(void);
-
- public slots:
- void send(const QByteArray &data);
-
- void ping(void);
-
- private slots:
- void udpNewConnect(void);
-
- void tcpNewConnect(const qintptr &socketDescriptor);
-
- signals:
- void accepted(const QHostAddress address, const QByteArray data);
-
- void newConnect(const QHostAddress address);
-
- void disConnect(const QHostAddress address);
-
- void sendSucceed(const QHostAddress address);
- };
-
- #endif//__JasonQt_LanSocket_h__
Jason_LanSocket.cpp
- #include "JasonQt_LanSocket.h"
-
- void JasonQt_LanSocket_TcpListen::incomingConnection(qintptr socketDescriptor)
- {
- emit newConnect(socketDescriptor);
- }
-
- JasonQt_LanSocket::JasonQt_LanSocket(const quint16 &udpPort, const quint16 &tcpPort,
- const int &pingInterval, const int &pingTimeout,
- const quint8 &threadPoolCount):
- m_udpPort(udpPort),
- m_tcpPort(tcpPort),
- m_pingInterval(pingInterval),
- m_pingTimeout(pingTimeout)
- {
- connect(&m_timerPing, SIGNAL(timeout()), this, SLOT(ping()));
- connect(&m_udpListen, SIGNAL(readyRead()), this, SLOT(udpNewConnect()));
- connect(&m_tcpListen, SIGNAL(newConnect(qintptr)), this, SLOT(tcpNewConnect(qintptr)));
-
- m_threadPool.setMaxThreadCount(threadPoolCount);
- }
-
- bool JasonQt_LanSocket::begin(void)
- {
- m_NetworkAddressEntry = getNetworkAddressEntry();
-
- if(!m_NetworkAddressEntry.ip().toIPv4Address() || !m_udpListen.bind(QHostAddress::Any, m_udpPort) || !m_tcpListen.listen(QHostAddress::Any, m_tcpPort))
- {
- m_timerPing.stop();
- return false;
- }
-
- m_timerPing.start(m_pingInterval);
-
- return true;
- }
-
- QNetworkAddressEntry JasonQt_LanSocket::getNetworkAddressEntry(void)
- {
- auto allInterfaces = QNetworkInterface::allInterfaces();
-
-
- for(const auto &interface: allInterfaces)
- {
- if(interface.name().indexOf("en0") != -1)
- {
- for(const auto &entry: interface.addressEntries())
- {
- if(entry.ip().toIPv4Address())
- {
- return entry;
- }
- }
- }
- }
-
-
- for(const auto &interface: allInterfaces)
- {
- for(const auto &entry: interface.addressEntries())
- {
- if(entry.ip().toIPv4Address())
- {
- if(entry.ip().toString().indexOf("10.0.") == 0)
- {
- return entry;
- }
- else if(entry.ip().toString().indexOf("192.168.") == 0)
- {
- return entry;
- }
- }
- }
- }
-
- return QNetworkAddressEntry();
- }
-
- void JasonQt_LanSocket::send(const QByteArray &data)
- {
- for(auto it = m_availableIp.begin(); it != m_availableIp.end(); it++)
- {
- QtConcurrent::run(&m_threadPool, [=](const QHostAddress &address, const QByteArray &data)
- {
- auto socket = new QTcpSocket;
-
- socket->connectToHost(address, m_tcpPort);
- if(!socket->waitForConnected(5000)) { socket->deleteLater(); return; }
-
- socket->write(QString::number(data.size()).toLatin1());
- if(!socket->waitForBytesWritten(5000)) { socket->deleteLater(); return; }
-
- if(!socket->waitForReadyRead(5000)) { socket->deleteLater(); return; }
- if(socket->readAll() != "OK") { socket->deleteLater(); return; }
-
- socket->write(data);
- if(!socket->waitForBytesWritten(5000)) { socket->deleteLater(); return; }
-
- socket->waitForReadyRead(5000);
-
- emit sendSucceed(address);
-
- QTimer::singleShot(5000, socket, SLOT(deleteLater()));
- }, QHostAddress(it.key()), data);
- }
- }
-
- void JasonQt_LanSocket::ping(void)
- {
- auto &¤tTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
- for(auto it = m_availableIp.begin(); it != m_availableIp.end(); it++)
- {
- if((currentTime - it.value()) > m_pingTimeout)
- {
- emit disConnect(QHostAddress(it.key()));
- m_availableIp.erase(it);
- it = m_availableIp.begin();
- }
- }
-
- QJsonObject data;
- data.insert("Type", "Ping");
- data.insert("Ip", QString::number(m_NetworkAddressEntry.ip().toIPv4Address()));
-
- auto socket = new QUdpSocket;
- socket->writeDatagram(QJsonDocument(data).toJson(), m_NetworkAddressEntry.broadcast(), m_udpPort);
- QTimer::singleShot(1000, socket, SLOT(deleteLater()));
- }
-
- void JasonQt_LanSocket::udpNewConnect(void)
- {
- while(m_udpListen.hasPendingDatagrams())
- {
- QByteArray datagram;
-
- datagram.resize(m_udpListen.pendingDatagramSize());
- m_udpListen.readDatagram(datagram.data(), datagram.size());
-
- QJsonObject data = QJsonDocument::fromJson(datagram).object();
-
- if(data.contains("Type") && (data.value("Type").toString() == "Ping") && data.contains("Ip"))
- {
- if(m_availableIp.find(data.value("Ip").toString().toUInt()) == m_availableIp.end())
- {
- emit newConnect(QHostAddress(data.value("Ip").toString().toUInt()));
- }
- m_availableIp[data.value("Ip").toString().toUInt()] = QDateTime::currentDateTime().toMSecsSinceEpoch();
- }
- }
- }
-
- void JasonQt_LanSocket::tcpNewConnect(const qintptr &socketDescriptor)
- {
- QtConcurrent::run(&m_threadPool, [=](const qintptr &socketDescriptor)
- {
- auto socket = new QTcpSocket;
- int psckageSize = -1;
- QByteArray buf;
-
- if(!socket->setSocketDescriptor(socketDescriptor)) { socket->deleteLater(); return; }
- if(!socket->waitForConnected(5000)) { socket->deleteLater(); return; }
-
- if(!socket->waitForReadyRead(5000)) { socket->deleteLater(); return; }
- psckageSize = socket->readAll().toInt();
-
- socket->write("OK");
- socket->waitForBytesWritten(5000);
-
- while(socket->waitForReadyRead(5000))
- {
- buf.append(socket->readAll());
- }
-
- if(buf.size() != psckageSize) { socket->deleteLater(); return; }
-
- socket->write("OK");
- socket->waitForBytesWritten(5000);
-
- emit accepted(socket->peerAddress(), buf);
-
- QTimer::singleShot(1000, socket, SLOT(deleteLater()));
- }, socketDescriptor);
- }
我也寫了一個示例工程,能夠到下方連接中下載
http://download.csdn.net/detail/wsj18808050/8369201
http://blog.csdn.net/wsj18808050/article/details/42778751