Qt:基于TCP和UDP的局域网P2P(局域网)通讯封装
2015-01-16 16:25
633 查看
封装了一个类,可以进行在局域网进行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
Jason_LanSocket.cpp
我也写了一个示例工程,可以到下方链接中下载
http://download.csdn.net/detail/wsj18808050/8369201
也就是说,假设局域网中有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
#ifndef __JasonQt_LanSocket_h__ #define __JasonQt_LanSocket_h__ // Qt lib import #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" // JasonQt_LanSocket_TcpListen void JasonQt_LanSocket_TcpListen::incomingConnection(qintptr socketDescriptor) { emit newConnect(socketDescriptor); } // JasonQt_LanSocket 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(); // Scan en0 for(const auto &interface: allInterfaces) { if(interface.name().indexOf("en0") != -1) { for(const auto &entry: interface.addressEntries()) { if(entry.ip().toIPv4Address()) { return entry; } } } } // Scan other 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
相关文章推荐
- Qt:基于TCP和UDP的局域网P2P(局域网)通讯封装
- 基于Qt编写TCP通讯程序测试程序之超级详细教程
- Android实现基于TCP和UDP协议的即时通讯,含android端和服务器端
- Android实现基于TCP和UDP协议的即时通讯,含android端和服务器端
- 基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据
- 基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据
- 基于QT的TCP通讯
- 基于Qt的P2P局域网聊天及文件传送软件设计
- android实现基于TCP和UDP协议的即时通讯,含android端和服务器端
- 基于Qt的P2P局域网聊天及文件传送软件设计
- 基于socket的TCP和UDP通讯的简单建立
- Qt之局域网UDP通讯
- 基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据
- VB.NET C#实现基于UDP的免服务器局域网多客户端点对点通讯
- 基于Qt的P2P局域网聊天及文件传送软件设计
- [原][osg][osgEarth]基于qt代码实现:TCP|UDP与飞行模拟软件JSBSim的通信,现实模型飞行!
- 基于TCP/IP的局域网多用户通信
- [已更新至0.1正式版]基于TCP的P2P视频聊天程序
- Windows套接字编程:基于TCP和UDP协议
- 基于UDP的通讯协议