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);以主机名和端 ...
随机推荐
- linux下socket编程-UDP
下面是UDP的服务器的代码: /* server.c */ #include <stdio.h> #include <string.h> #include <netine ...
- 文件搜索查找功能VC++
1.搜索指定文件夹下的文件名和路径 #undef UNICODE #include <iostream> #include <string> #include <vect ...
- 【原】YUI Test自动化测试实例详解
测试在软件开发中至关重要,目前针对不同的开发语言,都有比较成熟的测试框架,如jUnit,cUnit,cppUnit,nUnit等,我们统称为xUnit,他们的都遵守统一的规则: 针对代码测试 断言 启 ...
- Best Financing(HD4833)
每笔收入产生的收益是独立的. 计算所有点的收益率,累计. #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<al ...
- Android之Adapter用法总结
http://blog.csdn.net/fznpcy/article/details/8658155 Android之Adapter用法总结 1.概念 Adapter是连接后端数据和前端显示的适配器 ...
- 本地化SilverLight应用程序(多语言支持)
原文 http://www.cnblogs.com/seaworm/archive/2010/11/30/1892325.html 利用资源文件(Resources File)使SilverLight ...
- Android HandlerThread的用法
HandlerThread 继承自Thread,内部封装了Looper. 首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerTh ...
- 练习3.20 a 将中缀表达式转换为后缀表达式
//将中缀表达式转换为后缀表达式 int main() { ; ]={,,,,,,,}; char tmp; PtrToStack s; s = CreateStack( MaxSize ); ) { ...
- db2 for linux
https://www6.software.ibm.com/sdfdl/v2/regs2/db2pmopn/db2_v101/expc/Xa.2/Xb.aA_60_-idYiSFeSuWlF5-w4v ...
- hdu 4740
题目链接 老虎左拐,老鼠右拐,碰到不能走的拐一次,如果还不能走就停下,自己走过的不能走,求相遇的坐标或-1 一个停下之后,另一个还可以走 #include <cstdio> #includ ...