封装了一个类,可以进行在局域网进行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

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

Jason_LanSocket.cpp

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

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

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

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

Qt:基于TCP和UDP的局域网P2P(局域网)通讯封装的更多相关文章

  1. Java Socket实现基于TCP和UDP多线程通信

    一.通过Socket实现TCP编程 1.1 TCP编程 TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据.基于TCP协议实现网络通信的类有客户端的Socket类和服务器端的ServerSo ...

  2. Qt基于tcp协议网络编程

    基于Qt网络编程: 基于tcp协议 c/s模式编程 所需要的类:QTcpServer QTcpSocket 利用qt基于tcp协议编写c/s模式程序: 两个类中的信号: QTcpServer : ne ...

  3. 基于TCP和UDP的socket

    为什么学习socket 你自己现在完全可以写一些小程序了,但是前面的学习和练习,我们写的代码都是在自己的电脑上运行的,虽然我们学过了模块引入,文件引入import等等,我可以在程序中获取到另一个文件的 ...

  4. 基于TCP与UDP协议的socket通信

    基于TCP与UDP协议的socket通信 C/S架构与初识socket 在开始socket介绍之前,得先知道一个Client端/服务端架构,也就是 C/S 架构,互联网中处处充满了 C/S 架构(Cl ...

  5. Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型

    Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...

  6. 轨迹系列——Socket总结及实现基于TCP或UDP的809协议方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在上一篇博客中我详细介绍了809协议的内容.809协议规范了通 ...

  7. 轨迹系列7——Socket总结及实现基于TCP或UDP的809协议方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在上一篇博客中我详细介绍了809协议的内容.809协议规范了通 ...

  8. 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 ...

  9. 基于tcp和udp协议的套接字

    socket:是在应用层和传输层之间的一个抽象层,它把TCP/IP层的复杂的操作封装抽象,并提供一些接口供应用层调用 套接字:被设计用于同一台主机上多个应用程序之间的通信,被称为进程之间通信或IPC ...

  10. 初识Socket通信:基于TCP和UDP协议学习网络编程

    学习笔记: 1.基于TCP协议的Socket网络编程: (1)Socket类构造方法:在客户端和服务器端建立连接 Socket s = new Socket(hostName,port);以主机名和端 ...

随机推荐

  1. Python的基础--对象

    对象(Objects)是python中数据的抽象,python中所有的数据均可以用对象或者是对象之间的关系来表示.每个对象均有标识符(identity).类型(type).值(value). 标识符. ...

  2. python基础:列表生成式和生成器

    列表生成式(List Comprehension) 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成 list ...

  3. JavaScript判断IE各版本完美解决方案

    解决方案 IE知道自身毛病很多,于是提供的一套官方的HTML hack方式: <!--[if IE]> // 全部IE版本可见 <![endif]--> <!--[if ...

  4. 关于Git和Github

    英文原文:Ten Things You Didn't Know Git And GitHub Could Do Git 和 GitHub 都是非常强大的工具.即使你已经使用他们很长时间,你也很有可能不 ...

  5. not valid for Running the scheme

    The run destination iPhone6 Plus is not valid for Running the scheme 'MyApp’. Phone6 Plus's iOS 8.0 ...

  6. bootstrap简章

    系统整理一遍bootstrap 的东西 1/  设置页面为H5文档类型 <!DOCTYPE html> <html lang="zh-CN"> ... &l ...

  7. Hibernate 多表关联映射- 一对多关系映射(one-to-many)

    Hibernage.cfg.xml: <hibernate-configuration> <session-factory name="sessionFactory&quo ...

  8. 排颜色问题——数组 leetcode lintcode

    问题描写叙述: 给一个数组,而且数组里面元素的值仅仅可能是0,1,2,然后如今把这个数组排序. 第二种表述: 现有n个红白蓝三种不同颜色的小球,乱序排列在一起,请通过两两交换随意两个球,使得从左至右, ...

  9. Tomcat7配置数据源(Oracle)

    修改../conf/content.xml <?xml version='1.0' encoding='utf-8'?> <!-- The contents of this file ...

  10. 新浪云-PHP实现上传原图,缩略图

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> < ...