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
- #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
http://blog.csdn.net/wsj18808050/article/details/42778751
Qt:基于TCP和UDP的局域网P2P(局域网)通讯封装的更多相关文章
- Java Socket实现基于TCP和UDP多线程通信
		
一.通过Socket实现TCP编程 1.1 TCP编程 TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据.基于TCP协议实现网络通信的类有客户端的Socket类和服务器端的ServerSo ...
 - Qt基于tcp协议网络编程
		
基于Qt网络编程: 基于tcp协议 c/s模式编程 所需要的类:QTcpServer QTcpSocket 利用qt基于tcp协议编写c/s模式程序: 两个类中的信号: QTcpServer : ne ...
 - 基于TCP和UDP的socket
		
为什么学习socket 你自己现在完全可以写一些小程序了,但是前面的学习和练习,我们写的代码都是在自己的电脑上运行的,虽然我们学过了模块引入,文件引入import等等,我可以在程序中获取到另一个文件的 ...
 - 基于TCP与UDP协议的socket通信
		
基于TCP与UDP协议的socket通信 C/S架构与初识socket 在开始socket介绍之前,得先知道一个Client端/服务端架构,也就是 C/S 架构,互联网中处处充满了 C/S 架构(Cl ...
 - Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
		
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
 - 轨迹系列——Socket总结及实现基于TCP或UDP的809协议方法
		
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在上一篇博客中我详细介绍了809协议的内容.809协议规范了通 ...
 - 轨迹系列7——Socket总结及实现基于TCP或UDP的809协议方法
		
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在上一篇博客中我详细介绍了809协议的内容.809协议规范了通 ...
 - Node.js权威指南 (7) - 实现基于TCP与UDP的数据通信
		
7.1 使用net模块实现基于TCP的数据通信 / 136 7.1.1 创建TCP服务器 / 136 7.1.2 socket端口对象 / 142 7.1.3 创建TCP客户端 / 151 7.1.4 ...
 - 基于tcp和udp协议的套接字
		
socket:是在应用层和传输层之间的一个抽象层,它把TCP/IP层的复杂的操作封装抽象,并提供一些接口供应用层调用 套接字:被设计用于同一台主机上多个应用程序之间的通信,被称为进程之间通信或IPC ...
 - 初识Socket通信:基于TCP和UDP协议学习网络编程
		
学习笔记: 1.基于TCP协议的Socket网络编程: (1)Socket类构造方法:在客户端和服务器端建立连接 Socket s = new Socket(hostName,port);以主机名和端 ...
 
随机推荐
- php汉字转Unicode编码函数
			
/** * $str 原始字符串 * $encoding 原始字符串的编码,默认GBK * $prefix 编码后的前缀,默认"&#" * $postfix 编码后的后缀, ...
 - Linux 终端颜色高亮
			
昨天在改一些东西时,不小心将root下的一些配置文件删掉了.导致启动终端后,字完全一个颜色,没有区分.在网上找到的都是 改整体颜色的.但实际上这时应该搜Linux终端高亮才能找到解决办法.在这里再列出 ...
 - 在mysql 中两种锁定问题
			
mysql 中15.2.10.5 中描述了两个问题,且分别给出了解决办法. 1.向子表中写入数据,但写入之前需确保父表中存在其相应信息. 可能出现,在已经读取父表中的数据,但另一请求将其删除. 办法: ...
 - Centos DNS重启失效的解决
			
在KT的毒妇配置的时候,通过yum安装了桌面,默认安装了Gnome,在没重启前还一切正常,重启以后接着配置的时候,发现没法网络访问了,ping测试一 下,host unkown;基本可以确定是DNS的 ...
 - J2SE知识点摘记(二)
			
1. 对象的声明 "类名 对象名 = new 类名();"例子:Person P;//先声明一个Person类的对象p p=new Person();//用new关键字实例化 ...
 - 迁移到MSYS2 与 Qt 工具链注意的几个事情(注意链接顺序,并且人造mingw工具链所没有的局部midl.exe命令)
			
Microsoft Visual Studio 2015社区版提供了强大的开发体验,且 Qt 提供了预编译版本.然而,由于客户提出兼容Windows XP ~ Windows 8.1 这样宽泛的环境要 ...
 - Centos6.5 telnet wireshark
			
yum -y install telnet-server telnet vim /etc/xinted.d/telnet disable = no vim /etc/pam.d/remote #aut ...
 - find the safest road
			
find the safest road Time Limit : 10000/5000ms (Java/Other) Memory Limit : 32768/32768K (Java/Othe ...
 - Service的基本组成
			
Service与Activity的最大区别就是一有界面,一个没有界面. 如果某些程序操作很消耗时间,那么可以将这些程序定义在Service之中,这样就可以完成程序的后台运行, 其实Service就是一 ...
 - Login failed for user 'NT AUTHORITY\NETWORK SERVICE'的解决方法
			
1.打开SQL Server Manegement Studio 2.在 Security - logins 中 NETWORK SERVICE 3.双击该用户 Server Roles 中 勾选 ...