mqttHander ;
50 |
51 |
52 | private int initalDelay ;
53 |
54 | private int period ;
55 |
56 | private int bossThread;
57 |
58 | private int workThread;
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/ssl/SecureSocketSslContextFactory.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.ssl;
2 |
3 |
4 | import org.jboss.netty.util.internal.SystemPropertyUtil;
5 |
6 | import javax.net.ssl.*;
7 | import java.security.KeyStore;
8 | import java.security.SecureRandom;
9 |
10 | /**
11 | * Creates a bogus {@link SSLContext}. A client-side context created by this
12 | * factory accepts any certificate even if it is invalid. A server-side context
13 | * created by this factory sends a bogus certificate defined in {@link }.
14 | *
15 | * You will have to create your context differently in a real world application.
16 | *
17 | *
Client Certificate Authentication
18 | *
19 | * To enable client certificate authentication:
20 | *
21 | * Enable client authentication on the server side by calling
22 | * {@link SSLEngine#setNeedClientAuth(boolean)} before creating
23 | * {@link }.
24 | * When initializing an {@link SSLContext} on the client side,
25 | * specify the {@link KeyManager} that contains the client certificate as
26 | * the first argument of {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}.
27 | * When initializing an {@link SSLContext} on the server side,
28 | * specify the proper {@link TrustManager} as the second argument of
29 | * {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
30 | * to validate the client certificate.
31 | *
32 | */
33 | public final class SecureSocketSslContextFactory {
34 |
35 | private static final String PROTOCOL = "TLS";
36 | private static final SSLContext SERVER_CONTEXT;
37 | private static final SSLContext CLIENT_CONTEXT;
38 |
39 | static {
40 | String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
41 | if (algorithm == null) {
42 | algorithm = "SunX509";
43 | }
44 |
45 | SSLContext serverContext;
46 | SSLContext clientContext;
47 | try {
48 | //
49 | //SecureSocketSslContextFactory.class.getResourceAsStream("/securesocket.jks")
50 | KeyStore ks = KeyStore.getInstance("JKS");
51 | ks.load(SecureSocketKeyStore.asInputStream(),
52 | SecureSocketKeyStore.getKeyStorePassword());
53 |
54 | // Set up key manager factory to use our key store
55 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
56 | kmf.init(ks, SecureSocketKeyStore.getCertificatePassword());
57 |
58 | // Initialize the SSLContext to work with our key managers.
59 | serverContext = SSLContext.getInstance(PROTOCOL);
60 | serverContext.init(kmf.getKeyManagers(), null, null);
61 | } catch (Exception e) {
62 | throw new Error(
63 | "Failed to initialize the server-side SSLContext", e);
64 | }
65 |
66 | try {
67 | clientContext = SSLContext.getInstance(PROTOCOL);
68 | clientContext.init(null, SecureSokcetTrustManagerFactory.getTrustManagers(), null);
69 | } catch (Exception e) {
70 | throw new Error(
71 | "Failed to initialize the client-side SSLContext", e);
72 | }
73 |
74 | SERVER_CONTEXT = serverContext;
75 | CLIENT_CONTEXT = clientContext;
76 | }
77 |
78 | public static SSLContext getServerContext() {
79 | return SERVER_CONTEXT;
80 | }
81 |
82 | public static SSLContext getClientContext() {
83 | return CLIENT_CONTEXT;
84 | }
85 |
86 | private SecureSocketSslContextFactory() {
87 | // Unused
88 | }
89 | }
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/ssl/SecureSokcetTrustManagerFactory.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.ssl;
2 |
3 | import javax.net.ssl.ManagerFactoryParameters;
4 | import javax.net.ssl.TrustManager;
5 | import javax.net.ssl.TrustManagerFactorySpi;
6 | import javax.net.ssl.X509TrustManager;
7 | import java.security.InvalidAlgorithmParameterException;
8 | import java.security.KeyStore;
9 | import java.security.KeyStoreException;
10 | import java.security.cert.X509Certificate;
11 |
12 | /**
13 | * Bogus {@link TrustManagerFactorySpi} which accepts any certificate
14 | * even if it is invalid.
15 | */
16 | public class SecureSokcetTrustManagerFactory extends TrustManagerFactorySpi {
17 |
18 | private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() {
19 | @Override
20 | public X509Certificate[] getAcceptedIssuers() {
21 | return new X509Certificate[0];
22 | }
23 |
24 | @Override
25 | public void checkClientTrusted(X509Certificate[] chain, String authType) {
26 | // Always trust - it is an example.
27 | // You should do something in the real world.
28 | // You will reach here only if you enabled client certificate auth,
29 | // as described in SecureChatSslContextFactory.
30 | System.err.println(
31 | "UNKNOWN CLIENT CERTIFICATE: " + chain[0].getSubjectDN());
32 | }
33 |
34 | @Override
35 | public void checkServerTrusted(X509Certificate[] chain, String authType) {
36 | // Always trust - it is an example.
37 | // You should do something in the real world.
38 | System.err.println(
39 | "UNKNOWN SERVER CERTIFICATE: 222 " + chain[0].getSubjectDN());
40 | }
41 | };
42 |
43 | public static TrustManager[] getTrustManagers() {
44 | return new TrustManager[] { DUMMY_TRUST_MANAGER };
45 | }
46 |
47 | @Override
48 | protected TrustManager[] engineGetTrustManagers() {
49 | return getTrustManagers();
50 | }
51 |
52 | @Override
53 | protected void engineInit(KeyStore keystore) throws KeyStoreException {
54 | // Unused
55 | }
56 |
57 | @Override
58 | protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
59 | throws InvalidAlgorithmParameterException {
60 | // Unused
61 | }
62 | }
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/ssl/StreamReader.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.ssl;
2 |
3 | import java.io.InputStream;
4 |
5 | public class StreamReader {
6 |
7 |
8 | public String toByteArray(InputStream fin)
9 | {
10 | int i = -1;
11 | StringBuilder buf = new StringBuilder();
12 | try{
13 | while((i=fin.read())!=-1){
14 | if(buf.length()>0) buf.append(",");
15 | buf.append("(byte)");
16 | buf.append(i);
17 | }
18 |
19 | }catch(Throwable e){
20 | ;
21 | }
22 |
23 | return buf.toString();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/ssl/X509CertTool.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.ssl;
2 |
3 | import sun.security.x509.*;
4 |
5 | import java.io.IOException;
6 | import java.math.BigInteger;
7 | import java.security.GeneralSecurityException;
8 | import java.security.KeyPair;
9 | import java.security.PrivateKey;
10 | import java.security.SecureRandom;
11 | import java.security.cert.X509Certificate;
12 | import java.util.Date;
13 |
14 |
15 | /*
16 | * This class would require rt.jar in the class path in order to
17 | * generated it alternative is using keytool.
18 | */
19 |
20 | public class X509CertTool {
21 |
22 | /**
23 | * Create a self-signed X.509 Certificate
24 | * @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
25 | * @param pair the KeyPair
26 | * @param days how many days from now the Certificate is valid for
27 | * @param algorithm the signing algorithm, eg "SHA1withRSA"
28 | */
29 | @SuppressWarnings("restriction")
30 | X509Certificate generateCertificate(String dn, KeyPair pair, int days,
31 | String algorithm) throws GeneralSecurityException, IOException {
32 | PrivateKey privkey = pair.getPrivate();
33 | X509CertInfo info = new X509CertInfo();
34 | Date from = new Date();
35 | Date to = new Date(from.getTime() + days * 86400000l);
36 | CertificateValidity interval = new CertificateValidity(from, to);
37 | BigInteger sn = new BigInteger(64, new SecureRandom());
38 | X500Name owner = new X500Name(dn);
39 |
40 | info.set(X509CertInfo.VALIDITY, interval);
41 | info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
42 | info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
43 | info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
44 | info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
45 | info.set(X509CertInfo.VERSION, new CertificateVersion(
46 | CertificateVersion.V3));
47 | AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
48 | info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
49 |
50 | // Sign the cert to identify the algorithm that's used.
51 | X509CertImpl cert = new X509CertImpl(info);
52 | cert.sign(privkey, algorithm);
53 |
54 | // Update the algorith, and resign.
55 | algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
56 | info.set(CertificateAlgorithmId.NAME + "."
57 | + CertificateAlgorithmId.ALGORITHM, algo);
58 | cert = new X509CertImpl(info);
59 | cert.sign(privkey, algorithm);
60 | return cert;
61 | }
62 |
63 | public static void main(String[] args) {
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/util/ByteBufUtil.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.util;
2 |
3 | import io.netty.buffer.ByteBuf;
4 |
5 | /**
6 | * 跨线程情况下 byteBuf 需要转换成byte[]
7 | *
8 | * @author lxr
9 | * @create 2017-11-29 9:07
10 | **/
11 | public class ByteBufUtil {
12 |
13 | public static byte[] copyByteBuf(ByteBuf byteBuf){
14 | byte[] bytes = new byte[byteBuf.readableBytes()];
15 | byteBuf.readBytes(bytes);
16 | return bytes;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/util/IdWorker.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.util;
2 |
3 | import java.lang.management.ManagementFactory;
4 | import java.net.InetAddress;
5 | import java.net.NetworkInterface;
6 |
7 | /**
8 | * 全局id生成器
9 | *
10 | * @author lxr
11 | * @create 2017-11-23 19:38
12 | **/
13 | public class IdWorker {
14 |
15 | // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
16 | private final static long twepoch = 1288834974657L;
17 | // 机器标识位数
18 | private final static long workerIdBits = 5L;
19 | // 数据中心标识位数
20 | private final static long datacenterIdBits = 5L;
21 | // 机器ID最大值
22 | private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
23 | // 数据中心ID最大值
24 | private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
25 | // 毫秒内自增位
26 | private final static long sequenceBits = 12L;
27 | // 机器ID偏左移12位
28 | private final static long workerIdShift = sequenceBits;
29 | // 数据中心ID左移17位
30 | private final static long datacenterIdShift = sequenceBits + workerIdBits;
31 | // 时间毫秒左移22位
32 | private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
33 |
34 | private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
35 | /* 上次生产id时间戳 */
36 | private static long lastTimestamp = -1L;
37 | // 0,并发控制
38 | private long sequence = 0L;
39 |
40 | private final long workerId;
41 | // 数据标识id部分
42 | private final long datacenterId;
43 |
44 | public IdWorker(){
45 | this.datacenterId = getDatacenterId(maxDatacenterId);
46 | this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
47 | }
48 | /**
49 | * @param workerId
50 | * 工作机器ID
51 | * @param datacenterId
52 | * 序列号
53 | */
54 | public IdWorker(long workerId, long datacenterId) {
55 | if (workerId > maxWorkerId || workerId < 0) {
56 | throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
57 | }
58 | if (datacenterId > maxDatacenterId || datacenterId < 0) {
59 | throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
60 | }
61 | this.workerId = workerId;
62 | this.datacenterId = datacenterId;
63 | }
64 | /**
65 | * 获取下一个ID
66 | *
67 | * @return
68 | */
69 | public synchronized long nextId() {
70 | long timestamp = timeGen();
71 | if (timestamp < lastTimestamp) {
72 | throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
73 | }
74 |
75 | if (lastTimestamp == timestamp) {
76 | // 当前毫秒内,则+1
77 | sequence = (sequence + 1) & sequenceMask;
78 | if (sequence == 0) {
79 | // 当前毫秒内计数满了,则等待下一秒
80 | timestamp = tilNextMillis(lastTimestamp);
81 | }
82 | } else {
83 | sequence = 0L;
84 | }
85 | lastTimestamp = timestamp;
86 | // ID偏移组合生成最终的ID,并返回ID
87 | long nextId = ((timestamp - twepoch) << timestampLeftShift)
88 | | (datacenterId << datacenterIdShift)
89 | | (workerId << workerIdShift) | sequence;
90 |
91 | return nextId;
92 | }
93 |
94 | private long tilNextMillis(final long lastTimestamp) {
95 | long timestamp = this.timeGen();
96 | while (timestamp <= lastTimestamp) {
97 | timestamp = this.timeGen();
98 | }
99 | return timestamp;
100 | }
101 |
102 | private long timeGen() {
103 | return System.currentTimeMillis();
104 | }
105 |
106 | /**
107 | *
108 | * 获取 maxWorkerId
109 | *
110 | */
111 | protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
112 | StringBuffer mpid = new StringBuffer();
113 | mpid.append(datacenterId);
114 | String name = ManagementFactory.getRuntimeMXBean().getName();
115 | if (!name.isEmpty()) {
116 | /*
117 | * GET jvmPid
118 | */
119 | mpid.append(name.split("@")[0]);
120 | }
121 | /*
122 | * MAC + PID 的 hashcode 获取16个低位
123 | */
124 | return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
125 | }
126 |
127 | /**
128 | *
129 | * 数据标识id部分
130 | *
131 | */
132 | protected static long getDatacenterId(long maxDatacenterId) {
133 | long id = 0L;
134 | try {
135 | InetAddress ip = InetAddress.getLocalHost();
136 | NetworkInterface network = NetworkInterface.getByInetAddress(ip);
137 | if (network == null) {
138 | id = 1L;
139 | } else {
140 | byte[] mac = network.getHardwareAddress();
141 | id = ((0x000000FF & (long) mac[mac.length - 1])
142 | | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
143 | id = id % (maxDatacenterId + 1);
144 | }
145 | } catch (Exception e) {
146 | System.out.println(" getDatacenterId: " + e.getMessage());
147 | }
148 | return id;
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/util/MessageId.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.util;
2 |
3 | import ch.qos.logback.core.net.SyslogOutputStream;
4 |
5 | import java.util.concurrent.atomic.AtomicInteger;
6 |
7 | /**
8 | * 生成messgaeId
9 | *
10 | * @author lxr
11 | * @create 2017-11-23 19:43
12 | **/
13 | public class MessageId {
14 |
15 | private static AtomicInteger index = new AtomicInteger(1);
16 | /**
17 | * 获取messageId
18 | * @return id
19 | */
20 | public static int messageId(){
21 | for (;;) {
22 | int current = index.get();
23 | int next = (current >= Integer.MAX_VALUE ? 0: current + 1);
24 | if (index.compareAndSet(current, next)) {
25 | return current;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/util/RemotingUtil.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.util;
2 |
3 | /*
4 | * Licensed to the Apache Software Foundation (ASF) under one or more
5 | * contributor license agreements. See the NOTICE file distributed with
6 | * this work for additional information regarding copyright ownership.
7 | * The ASF licenses this file to You under the Apache License, Version 2.0
8 | * (the "License"); you may not use this file except in compliance with
9 | * the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import java.io.IOException;
24 | import java.lang.reflect.Method;
25 | import java.net.*;
26 | import java.nio.channels.Selector;
27 | import java.nio.channels.SocketChannel;
28 | import java.nio.channels.spi.SelectorProvider;
29 | import java.util.ArrayList;
30 | import java.util.Enumeration;
31 |
32 | public class RemotingUtil {
33 | public static final String OS_NAME = System.getProperty("os.name");
34 |
35 | private static final Logger log = LoggerFactory.getLogger(RemotingUtil.class);
36 | private static boolean isLinuxPlatform = false;
37 | private static boolean isWindowsPlatform = false;
38 |
39 | static {
40 | if (OS_NAME != null && OS_NAME.toLowerCase().contains("linux")) {
41 | isLinuxPlatform = true;
42 | }
43 |
44 | if (OS_NAME != null && OS_NAME.toLowerCase().contains("windows")) {
45 | isWindowsPlatform = true;
46 | }
47 | }
48 |
49 | public static boolean isWindowsPlatform() {
50 | return isWindowsPlatform;
51 | }
52 |
53 | public static Selector openSelector() throws IOException {
54 | Selector result = null;
55 |
56 | if (isLinuxPlatform()) {
57 | try {
58 | final Class> providerClazz = Class.forName("sun.nio.ch.EPollSelectorProvider");
59 | if (providerClazz != null) {
60 | try {
61 | final Method method = providerClazz.getMethod("provider");
62 | if (method != null) {
63 | final SelectorProvider selectorProvider = (SelectorProvider) method.invoke(null);
64 | if (selectorProvider != null) {
65 | result = selectorProvider.openSelector();
66 | }
67 | }
68 | } catch (final Exception e) {
69 | log.warn("Open ePoll Selector for linux platform exception", e);
70 | }
71 | }
72 | } catch (final Exception e) {
73 | // ignore
74 | }
75 | }
76 |
77 | if (result == null) {
78 | result = Selector.open();
79 | }
80 |
81 | return result;
82 | }
83 |
84 | public static boolean isLinuxPlatform() {
85 | return isLinuxPlatform;
86 | }
87 |
88 | public static String getLocalAddress() {
89 | try {
90 | // Traversal Network interface to get the first non-loopback and non-private address
91 | Enumeration enumeration = NetworkInterface.getNetworkInterfaces();
92 | ArrayList ipv4Result = new ArrayList();
93 | ArrayList ipv6Result = new ArrayList();
94 | while (enumeration.hasMoreElements()) {
95 | final NetworkInterface networkInterface = enumeration.nextElement();
96 | final Enumeration en = networkInterface.getInetAddresses();
97 | while (en.hasMoreElements()) {
98 | final InetAddress address = en.nextElement();
99 | if (!address.isLoopbackAddress()) {
100 | if (address instanceof Inet6Address) {
101 | ipv6Result.add(normalizeHostAddress(address));
102 | } else {
103 | ipv4Result.add(normalizeHostAddress(address));
104 | }
105 | }
106 | }
107 | }
108 |
109 | // prefer ipv4
110 | if (!ipv4Result.isEmpty()) {
111 | for (String ip : ipv4Result) {
112 | if (ip.startsWith("127.0") || ip.startsWith("192.168")) {
113 | continue;
114 | }
115 |
116 | return ip;
117 | }
118 |
119 | return ipv4Result.get(ipv4Result.size() - 1);
120 | } else if (!ipv6Result.isEmpty()) {
121 | return ipv6Result.get(0);
122 | }
123 | //If failed to find,fall back to localhost
124 | final InetAddress localHost = InetAddress.getLocalHost();
125 | return normalizeHostAddress(localHost);
126 | } catch (Exception e) {
127 | log.error("Failed to obtain local address", e);
128 | }
129 |
130 | return null;
131 | }
132 |
133 | public static String normalizeHostAddress(final InetAddress localHost) {
134 | if (localHost instanceof Inet6Address) {
135 | return "[" + localHost.getHostAddress() + "]";
136 | } else {
137 | return localHost.getHostAddress();
138 | }
139 | }
140 |
141 | public static SocketAddress string2SocketAddress(final String addr) {
142 | String[] s = addr.split(":");
143 | InetSocketAddress isa = new InetSocketAddress(s[0], Integer.parseInt(s[1]));
144 | return isa;
145 | }
146 |
147 | public static String socketAddress2String(final SocketAddress addr) {
148 | StringBuilder sb = new StringBuilder();
149 | InetSocketAddress inetSocketAddress = (InetSocketAddress) addr;
150 | sb.append(inetSocketAddress.getAddress().getHostAddress());
151 | sb.append(":");
152 | sb.append(inetSocketAddress.getPort());
153 | return sb.toString();
154 | }
155 |
156 | public static SocketChannel connect(SocketAddress remote) {
157 | return connect(remote, 1000 * 5);
158 | }
159 |
160 | public static SocketChannel connect(SocketAddress remote, final int timeoutMillis) {
161 | SocketChannel sc = null;
162 | try {
163 | sc = SocketChannel.open();
164 | sc.configureBlocking(true);
165 | sc.socket().setSoLinger(false, -1);
166 | sc.socket().setTcpNoDelay(true);
167 | sc.socket().setReceiveBufferSize(1024 * 64);
168 | sc.socket().setSendBufferSize(1024 * 64);
169 | sc.socket().connect(remote, timeoutMillis);
170 | sc.configureBlocking(false);
171 | return sc;
172 | } catch (Exception e) {
173 | if (sc != null) {
174 | try {
175 | sc.close();
176 | } catch (IOException e1) {
177 | e1.printStackTrace();
178 | }
179 | }
180 | }
181 |
182 | return null;
183 | }
184 |
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/util/SpringBeanUtils.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.util;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 | /**
8 | * 获取 spring当前bean
9 | *
10 | * @author lxr
11 | * @create 2017-11-21 19:56
12 | **/
13 | @Component
14 | public class SpringBeanUtils implements ApplicationContextAware {
15 |
16 | private static ApplicationContext applicationContext;
17 |
18 | @Override
19 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
20 | if(SpringBeanUtils.applicationContext == null) {
21 | SpringBeanUtils.applicationContext = applicationContext;
22 | }
23 | }
24 |
25 | //获取applicationContext
26 | public static ApplicationContext getApplicationContext() {
27 | return applicationContext;
28 | }
29 |
30 | //通过name获取 Bean.
31 | public static Object getBean(String name){
32 | return getApplicationContext().getBean(name);
33 | }
34 |
35 | //通过class获取Bean.
36 | public static T getBean(Class clazz){
37 | return getApplicationContext().getBean(clazz);
38 | }
39 |
40 | //通过name,以及Clazz返回指定的Bean
41 | public static T getBean(String name,Class clazz){
42 | return getApplicationContext().getBean(name, clazz);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/iot_push_common/src/main/java/com/lxr/iot/zookeeper/ZkStateListener.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.zookeeper;
2 |
3 | import org.apache.curator.framework.CuratorFramework;
4 | import org.apache.curator.framework.state.ConnectionState;
5 |
6 | /**
7 | * zookeeper 监听
8 | *
9 | * @author lxr
10 | * @create 2017-11-16 9:44
11 | **/
12 | public interface ZkStateListener {
13 |
14 | default void connectedEvent(CuratorFramework curator, ConnectionState state) {
15 | }
16 |
17 | default void ReconnectedEvent(CuratorFramework curator, ConnectionState state) {
18 | }
19 |
20 | default void lostEvent(CuratorFramework curator, ConnectionState state) {
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/iot_push_server/iot_push_server.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/iot_push_server/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | iot_push
5 | com.lxr.iot
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | iot_push_server
11 | jar
12 |
13 | iot_push_server
14 | http://maven.apache.org
15 |
16 |
17 |
18 |
19 |
20 | com.lxr.iot
21 | iot_push_common
22 | 1.0-SNAPSHOT
23 |
24 |
25 | junit
26 | junit
27 | 3.8.1
28 | test
29 |
30 |
31 |
32 |
33 |
34 | org.apache.maven.plugins
35 | maven-compiler-plugin
36 | 3.3
37 |
38 | 1.8
39 | 1.8
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/auto/InitServer.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.auto;
2 |
3 | import com.lxr.iot.bootstrap.BootstrapServer;
4 | import com.lxr.iot.bootstrap.NettyBootstrapServer;
5 | import com.lxr.iot.properties.InitBean;
6 |
7 | /**
8 | * 初始化服务
9 | *
10 | * @author lxr
11 | * @create 2017-11-29 20:12
12 | **/
13 | public class InitServer {
14 |
15 | private InitBean serverBean;
16 |
17 | public InitServer(InitBean serverBean) {
18 | this.serverBean = serverBean;
19 | }
20 |
21 | BootstrapServer bootstrapServer;
22 |
23 | public void open(){
24 | if(serverBean!=null){
25 | bootstrapServer = new NettyBootstrapServer();
26 | bootstrapServer.setServerBean(serverBean);
27 | bootstrapServer.start();
28 | }
29 | }
30 |
31 |
32 | public void close(){
33 | if(bootstrapServer!=null){
34 | bootstrapServer.shutdown();
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/auto/ServerAutoConfigure.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.auto;
2 |
3 | import com.lxr.iot.enums.ProtocolEnum;
4 | import com.lxr.iot.properties.InitBean;
5 | import org.apache.commons.lang3.ObjectUtils;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
9 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 |
13 | /**
14 | * 自动化配置初始化服务
15 | *
16 | * @author lxr
17 | * @create 2017-11-29 19:52
18 | **/
19 | @Configuration
20 | @ConditionalOnClass
21 | @EnableConfigurationProperties({InitBean.class})
22 | public class ServerAutoConfigure {
23 |
24 |
25 | private static final int _BLACKLOG = 1024;
26 |
27 | private static final int CPU =Runtime.getRuntime().availableProcessors();
28 |
29 | private static final int SEDU_DAY =10;
30 |
31 | private static final int TIMEOUT =120;
32 |
33 | private static final int BUF_SIZE=10*1024*1024;
34 |
35 |
36 | public ServerAutoConfigure(){
37 |
38 | }
39 |
40 |
41 |
42 | @Bean(initMethod = "open", destroyMethod = "close")
43 | @ConditionalOnMissingBean
44 | public InitServer initServer(InitBean serverBean){
45 | if(!ObjectUtils.allNotNull(serverBean.getPort(),serverBean.getServerName())){
46 | throw new NullPointerException("not set port");
47 | }
48 | if(serverBean.getBacklog()<1){
49 | serverBean.setBacklog(_BLACKLOG);
50 | }
51 | if(serverBean.getBossThread()<1){
52 | serverBean.setBossThread(CPU);
53 | }
54 | if(serverBean.getInitalDelay()<0){
55 | serverBean.setInitalDelay(SEDU_DAY);
56 | }
57 | if(serverBean.getPeriod()<1){
58 | serverBean.setPeriod(SEDU_DAY);
59 | }
60 | if(serverBean.getHeart()<1){
61 | serverBean.setHeart(TIMEOUT);
62 | }
63 | if(serverBean.getRevbuf()<1){
64 | serverBean.setRevbuf(BUF_SIZE);
65 | }
66 | if(serverBean.getWorkThread()<1){
67 | serverBean.setWorkThread(CPU*2);
68 | }
69 | if(serverBean.getProtocol()==null){
70 | serverBean.setProtocol(ProtocolEnum.MQTT);
71 | }
72 | return new InitServer(serverBean);
73 | }
74 |
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/AbstractBootstrapServer.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap;
2 |
3 | import com.lxr.iot.bootstrap.coder.ByteBufToWebSocketFrameEncoder;
4 | import com.lxr.iot.bootstrap.coder.WebSocketFrameToByteBufDecoder;
5 | import com.lxr.iot.properties.InitBean;
6 | import com.lxr.iot.ssl.SecureSocketSslContextFactory;
7 | import com.lxr.iot.util.SpringBeanUtils;
8 | import io.netty.channel.ChannelPipeline;
9 | import io.netty.handler.codec.http.HttpObjectAggregator;
10 | import io.netty.handler.codec.http.HttpServerCodec;
11 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
12 | import io.netty.handler.codec.mqtt.MqttDecoder;
13 | import io.netty.handler.codec.mqtt.MqttEncoder;
14 | import io.netty.handler.ssl.SslHandler;
15 | import io.netty.handler.timeout.IdleStateHandler;
16 | import org.apache.commons.lang3.ObjectUtils;
17 | import org.jboss.netty.util.internal.SystemPropertyUtil;
18 |
19 | import javax.net.ssl.KeyManagerFactory;
20 | import javax.net.ssl.SSLContext;
21 | import javax.net.ssl.SSLEngine;
22 | import java.security.KeyStore;
23 | import java.util.concurrent.ExecutorService;
24 | import java.util.concurrent.Executors;
25 |
26 | /**
27 | * 抽象类 负责加载edec handler
28 | *
29 | * @author lxr
30 | * @create 2017-11-20 13:46
31 | **/
32 | public abstract class AbstractBootstrapServer implements BootstrapServer {
33 |
34 |
35 |
36 | private String PROTOCOL = "TLS";
37 |
38 | private SSLContext SERVER_CONTEXT;
39 |
40 | private static final String MQTT_CSV_LIST = "mqtt, mqttv3.1, mqttv3.1.1";
41 |
42 |
43 | /**
44 | *
45 | * @param channelPipeline channelPipeline
46 | * @param serverBean 服务配置参数
47 | */
48 | protected void initHandler(ChannelPipeline channelPipeline, InitBean serverBean){
49 | if(serverBean.isSsl()){
50 | if(!ObjectUtils.allNotNull(serverBean.getJksCertificatePassword(),serverBean.getJksFile(),serverBean.getJksStorePassword())){
51 | throw new NullPointerException("SSL file and password is null");
52 | }
53 | initSsl(serverBean);
54 | SSLEngine engine =
55 | SERVER_CONTEXT.createSSLEngine();
56 | engine.setUseClientMode(false);
57 | channelPipeline.addLast("ssl", new SslHandler(engine));
58 | }
59 |
60 | intProtocolHandler(channelPipeline,serverBean);
61 | channelPipeline.addLast(new IdleStateHandler(serverBean.getHeart(),0,0));
62 | channelPipeline.addLast( SpringBeanUtils.getBean(serverBean.getMqttHander()));
63 |
64 | }
65 |
66 | private void intProtocolHandler(ChannelPipeline channelPipeline,InitBean serverBean){
67 | switch (serverBean.getProtocol()){
68 | case MQTT:
69 | channelPipeline.addLast("encoder", MqttEncoder.INSTANCE);
70 | channelPipeline.addLast("decoder", new MqttDecoder());
71 | break;
72 | case MQTT_WS_MQTT:
73 | channelPipeline.addLast("httpCode", new HttpServerCodec());
74 | channelPipeline.addLast("aggregator", new HttpObjectAggregator(65536));
75 | channelPipeline.addLast("webSocketHandler",
76 | new WebSocketServerProtocolHandler("/", MQTT_CSV_LIST));
77 | channelPipeline.addLast("wsDecoder", new WebSocketFrameToByteBufDecoder());
78 | channelPipeline.addLast("wsEncoder", new ByteBufToWebSocketFrameEncoder());
79 | channelPipeline.addLast("decoder", new MqttDecoder());
80 | channelPipeline.addLast("encoder", MqttEncoder.INSTANCE);
81 | break;
82 | case MQTT_WS_PAHO:
83 | channelPipeline.addLast("httpCode", new HttpServerCodec());
84 | channelPipeline.addLast("aggregator", new HttpObjectAggregator(65536));
85 | channelPipeline.addLast("webSocketHandler",
86 | new WebSocketServerProtocolHandler("/mqtt", MQTT_CSV_LIST));
87 | channelPipeline.addLast("wsDecoder", new WebSocketFrameToByteBufDecoder());
88 | channelPipeline.addLast("wsEncoder", new ByteBufToWebSocketFrameEncoder());
89 | channelPipeline.addLast("decoder", new MqttDecoder());
90 | channelPipeline.addLast("encoder", MqttEncoder.INSTANCE);
91 | break;
92 | }
93 | }
94 |
95 | private void initSsl(InitBean serverBean){
96 | ExecutorService executorService = Executors.newCachedThreadPool();
97 | executorService.submit(() -> {});
98 | String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
99 | if (algorithm == null) {
100 | algorithm = "SunX509";
101 | }
102 | SSLContext serverContext;
103 | try {
104 | //
105 | KeyStore ks = KeyStore.getInstance("JKS");
106 | ks.load( SecureSocketSslContextFactory.class.getResourceAsStream(serverBean.getJksFile()),
107 | serverBean.getJksStorePassword().toCharArray());
108 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
109 | kmf.init(ks,serverBean.getJksCertificatePassword().toCharArray());
110 | serverContext = SSLContext.getInstance(PROTOCOL);
111 | serverContext.init(kmf.getKeyManagers(), null, null);
112 | } catch (Exception e) {
113 | throw new Error(
114 | "Failed to initialize the server-side SSLContext", e);
115 | }
116 | SERVER_CONTEXT = serverContext;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/BaseApi.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap;
2 |
3 | import javax.validation.constraints.NotNull;
4 | import java.util.Arrays;
5 | import java.util.Optional;
6 | import java.util.function.Consumer;
7 | import java.util.function.Predicate;
8 |
9 | /**
10 | * 逻辑操作封装
11 | *
12 | * @author lxr
13 | * @create 2017-11-27 9:12
14 | **/
15 | public interface BaseApi {
16 |
17 |
18 | default void doIfElse(T t, Predicate predicate, Consumer consumer){
19 | if(t!=null){
20 | if(predicate.test(t)){
21 | consumer.accept(t);
22 | }
23 | }
24 | }
25 |
26 |
27 | default void doIfElse(T t, Predicate predicate, Consumer consumer, Consumer consumer2){
28 | if(t!=null){
29 | if(predicate.test(t)){
30 | consumer.accept(t);
31 | }
32 | else{
33 | consumer2.accept(t);
34 | }
35 | }
36 | }
37 | default boolean doIf(T t, Predicate... predicates){
38 | if(t!=null){
39 | for(Predicate p:predicates){
40 | if(!p.test(t)){
41 | return false;
42 | }
43 | }
44 | return true;
45 | }
46 | return false;
47 | }
48 |
49 | default void doIfAnd(T t, Consumer consumer2, Predicate... predicates){
50 | boolean flag =true;
51 | if(t!=null){
52 | for(Predicate p:predicates){
53 | if(!p.test(t)){
54 | flag= false;
55 | break;
56 | }
57 | }
58 | }
59 | if(flag){
60 | consumer2.accept(t);
61 | }
62 | }
63 |
64 | default void doIfAnd1(@NotNull T t, @NotNull Consumer consumer2, @NotNull Predicate... predicates){
65 | Predicate one = predicates[0];
66 | int l;
67 | if((l=predicates.length)>1){
68 | for(int i=1;i topics);
28 |
29 |
30 | void loginSuccess(Channel channel, String deviceId, MqttConnectMessage mqttConnectMessage);
31 |
32 | void publishSuccess(Channel channel, MqttPublishMessage mqttPublishMessage);
33 |
34 | void closeSuccess(String deviceId,boolean isDisconnect);
35 |
36 | void sendWillMsg(WillMeaasge willMeaasge);
37 |
38 | String getDeviceId(Channel channel);
39 |
40 | void unsubscribe(String deviceId, List topics1);
41 |
42 | void doPubrel(Channel channel, int mqttMessage);
43 |
44 | void doPubrec(Channel channel, int mqttMessage);
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/NettyBootstrapServer.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap;
2 |
3 | import com.lxr.iot.ip.IpUtils;
4 | import com.lxr.iot.properties.InitBean;
5 | import com.lxr.iot.util.RemotingUtil;
6 | import io.netty.bootstrap.ServerBootstrap;
7 | import io.netty.buffer.PooledByteBufAllocator;
8 | import io.netty.channel.ChannelFutureListener;
9 | import io.netty.channel.ChannelInitializer;
10 | import io.netty.channel.ChannelOption;
11 | import io.netty.channel.EventLoopGroup;
12 | import io.netty.channel.epoll.Epoll;
13 | import io.netty.channel.epoll.EpollEventLoopGroup;
14 | import io.netty.channel.epoll.EpollServerSocketChannel;
15 | import io.netty.channel.nio.NioEventLoopGroup;
16 | import io.netty.channel.socket.SocketChannel;
17 | import io.netty.channel.socket.nio.NioServerSocketChannel;
18 | import lombok.Getter;
19 | import lombok.Setter;
20 |
21 | import java.util.concurrent.ThreadFactory;
22 | import java.util.concurrent.atomic.AtomicInteger;
23 |
24 | /**
25 | * netty 服务启动类
26 | *
27 | * @author lxr
28 | * @create 2017-11-18 14:03
29 | **/
30 | @Setter
31 | @Getter
32 | @lombok.extern.slf4j.Slf4j
33 | public class NettyBootstrapServer extends AbstractBootstrapServer {
34 |
35 | private InitBean serverBean;
36 |
37 | public InitBean getServerBean() {
38 | return serverBean;
39 | }
40 |
41 | public void setServerBean(InitBean serverBean) {
42 | this.serverBean = serverBean;
43 | }
44 |
45 | private EventLoopGroup bossGroup;
46 |
47 | private EventLoopGroup workGroup;
48 |
49 | ServerBootstrap bootstrap=null ;// 启动辅助类
50 |
51 | /**
52 | * 服务开启
53 | */
54 | public void start() {
55 | initEventPool();
56 | bootstrap.group(bossGroup, workGroup)
57 | .channel(useEpoll()?EpollServerSocketChannel.class:NioServerSocketChannel.class)
58 | .option(ChannelOption.SO_REUSEADDR, serverBean.isReuseaddr())
59 | .option(ChannelOption.SO_BACKLOG, serverBean.getBacklog())
60 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
61 | .option(ChannelOption.SO_RCVBUF, serverBean.getRevbuf())
62 | .childHandler(new ChannelInitializer() {
63 | protected void initChannel(SocketChannel ch) throws Exception {
64 | initHandler(ch.pipeline(),serverBean);
65 | }
66 | })
67 | .childOption(ChannelOption.TCP_NODELAY, serverBean.isTcpNodelay())
68 | .childOption(ChannelOption.SO_KEEPALIVE, serverBean.isKeepalive())
69 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
70 | bootstrap.bind(IpUtils.getHost(),serverBean.getPort()).addListener((ChannelFutureListener) channelFuture -> {
71 | if (channelFuture.isSuccess())
72 | log.info("服务端启动成功【" + IpUtils.getHost() + ":" + serverBean.getPort() + "】");
73 | else
74 | log.info("服务端启动失败【" + IpUtils.getHost() + ":" + serverBean.getPort() + "】");
75 | });
76 | }
77 | /**
78 | * 初始化EnentPool 参数
79 | */
80 | private void initEventPool(){
81 | bootstrap= new ServerBootstrap();
82 | if(useEpoll()){
83 | bossGroup = new EpollEventLoopGroup(serverBean.getBossThread(), new ThreadFactory() {
84 | private AtomicInteger index = new AtomicInteger(0);
85 |
86 | public Thread newThread(Runnable r) {
87 | return new Thread(r, "LINUX_BOSS_" + index.incrementAndGet());
88 | }
89 | });
90 | workGroup = new EpollEventLoopGroup(serverBean.getWorkThread(), new ThreadFactory() {
91 | private AtomicInteger index = new AtomicInteger(0);
92 |
93 | public Thread newThread(Runnable r) {
94 | return new Thread(r, "LINUX_WORK_" + index.incrementAndGet());
95 | }
96 | });
97 |
98 | }
99 | else {
100 | bossGroup = new NioEventLoopGroup(serverBean.getBossThread(), new ThreadFactory() {
101 | private AtomicInteger index = new AtomicInteger(0);
102 |
103 | public Thread newThread(Runnable r) {
104 | return new Thread(r, "BOSS_" + index.incrementAndGet());
105 | }
106 | });
107 | workGroup = new NioEventLoopGroup(serverBean.getWorkThread(), new ThreadFactory() {
108 | private AtomicInteger index = new AtomicInteger(0);
109 |
110 | public Thread newThread(Runnable r) {
111 | return new Thread(r, "WORK_" + index.incrementAndGet());
112 | }
113 | });
114 | }
115 | }
116 |
117 | /**
118 | * 关闭资源
119 | */
120 | public void shutdown() {
121 | if(workGroup!=null && bossGroup!=null ){
122 | try {
123 | bossGroup.shutdownGracefully().sync();// 优雅关闭
124 | workGroup.shutdownGracefully().sync();
125 | } catch (InterruptedException e) {
126 | log.info("服务端关闭资源失败【" + IpUtils.getHost() + ":" + serverBean.getPort() + "】");
127 | }
128 | }
129 | }
130 |
131 | private boolean useEpoll() {
132 | return RemotingUtil.isLinuxPlatform()
133 | && Epoll.isAvailable();
134 | }
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/ScheduledPool.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap;
2 |
3 | import com.lxr.iot.pool.Scheduled;
4 | import com.lxr.iot.properties.InitBean;
5 | import org.springframework.stereotype.Service;
6 |
7 | import java.util.concurrent.*;
8 |
9 | /**
10 | * 定时任务
11 | *
12 | * @author lxr
13 | * @create 2017-12-14 10:39
14 | **/
15 | @Service
16 | public class ScheduledPool implements Scheduled {
17 |
18 | private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(20);
19 |
20 |
21 | private final InitBean serverBean;
22 |
23 | public ScheduledPool(InitBean serverBean) {
24 | this.serverBean = serverBean;
25 | }
26 |
27 | public ScheduledFuture> submit(Runnable runnable){
28 | int initalDelay = serverBean.getInitalDelay();
29 | int period = serverBean.getPeriod();
30 | return scheduledExecutorService.scheduleAtFixedRate(runnable, initalDelay, period, TimeUnit.SECONDS);
31 | }
32 |
33 | // public static void main(String[] a) throws InterruptedException {
34 | // ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(100);
35 | // ScheduledFuture> schedule = scheduledExecutorService.schedule(new Runnable() {
36 | // @Override
37 | // public void run() {
38 | // System.out.print("123");
39 | // }
40 | // }, 2, TimeUnit.SECONDS);
41 | // }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/bean/MqttChannel.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.bean;
2 |
3 | import com.lxr.iot.enums.SessionStatus;
4 | import com.lxr.iot.enums.SubStatus;
5 | import io.netty.channel.Channel;
6 | import io.netty.util.AttributeKey;
7 | import lombok.Builder;
8 | import lombok.Getter;
9 | import lombok.Setter;
10 |
11 | import java.util.Optional;
12 | import java.util.Set;
13 | import java.util.concurrent.ConcurrentHashMap;
14 | import java.util.concurrent.atomic.AtomicInteger;
15 |
16 | /**
17 | * channel 封装类
18 | *
19 | * @author lxr
20 | * @create 2017-11-21 14:04
21 | **/
22 | @Builder
23 | @Getter
24 | @Setter
25 | public class MqttChannel {
26 |
27 | private transient volatile Channel channel;
28 |
29 |
30 | private String deviceId;
31 |
32 |
33 | private boolean isWill;
34 |
35 |
36 | private volatile SubStatus subStatus; // 是否订阅过主题
37 |
38 |
39 | private Set topic ;
40 |
41 |
42 |
43 | private volatile SessionStatus sessionStatus; // 在线 - 离线
44 |
45 |
46 |
47 | private volatile boolean cleanSession; // 当为 true 时 channel close 时 从缓存中删除 此channel
48 |
49 |
50 |
51 |
52 | private ConcurrentHashMap message ; // messageId - message(qos1) // 待确认消息
53 |
54 |
55 |
56 | private AtomicInteger index ;
57 |
58 |
59 | public int messageId(){
60 | for (;;) {
61 | int current = index.get();
62 | int next = (current >= Short.MAX_VALUE ? 0: current + 1);
63 | if (index.compareAndSet(current, next)) {
64 | return current;
65 | }
66 | }
67 | }
68 |
69 | private Set receive;
70 |
71 | public void addRecevice(int messageId){
72 | receive.add(messageId);
73 | }
74 |
75 | public boolean checkRecevice(int messageId){
76 | return receive.contains(messageId);
77 | }
78 |
79 | public boolean removeRecevice(int messageId){
80 | return receive.remove(messageId);
81 | }
82 |
83 |
84 | public void addSendMqttMessage(int messageId,SendMqttMessage msg){
85 | message.put(messageId,msg);
86 | }
87 |
88 |
89 | public SendMqttMessage getSendMqttMessage(int messageId){
90 | return message.get(messageId);
91 | }
92 |
93 |
94 | public void removeSendMqttMessage(int messageId){
95 | message.remove(messageId);
96 | }
97 |
98 |
99 | /**
100 | * 判断当前channel 是否登录过
101 | * @return
102 | */
103 | public boolean isLogin(){
104 | return Optional.ofNullable(this.channel).map(channel1 -> {
105 | AttributeKey _login = AttributeKey.valueOf("login");
106 | return channel1.isActive() && channel1.hasAttr(_login);
107 | }).orElse(false);
108 | }
109 |
110 | /**
111 | * 非正常关闭
112 | */
113 | public void close(){
114 | Optional.ofNullable(this.channel).ifPresent(channel1 -> channel1.close());
115 | }
116 |
117 | /**
118 | * 通道是否活跃
119 | * @return
120 | */
121 | public boolean isActive(){
122 | return channel!=null&&this.channel.isActive();
123 | }
124 |
125 |
126 |
127 | public boolean addTopic(Set topics){
128 | return topic.addAll(topics);
129 | }
130 |
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/bean/RetainMessage.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.bean;
2 |
3 | import io.netty.handler.codec.mqtt.MqttQoS;
4 | import lombok.Builder;
5 | import lombok.Data;
6 |
7 | /**
8 | * 保留消息
9 | * @author lxr
10 | * @create 2017-11-24 16:06
11 | **/
12 | @Builder
13 | @Data
14 | public class RetainMessage {
15 |
16 | private byte[] byteBuf;
17 |
18 | private MqttQoS qoS;
19 | public String getString(){
20 | return new String(byteBuf);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/bean/SendMqttMessage.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.bean;
2 |
3 | import com.lxr.iot.enums.ConfirmStatus;
4 | import io.netty.channel.Channel;
5 | import io.netty.handler.codec.mqtt.MqttQoS;
6 | import lombok.Builder;
7 | import lombok.Data;
8 |
9 | /**
10 | * mqtt 消息
11 | *
12 | * @author lxr
13 | * @create 2018-01-17 19:54
14 | **/
15 | @Builder
16 | @Data
17 | public class SendMqttMessage {
18 |
19 | private int messageId;
20 |
21 | private Channel channel;
22 |
23 | private volatile ConfirmStatus confirmStatus;
24 |
25 | private long time;
26 |
27 | private byte[] byteBuf;
28 |
29 | private boolean isRetain;
30 |
31 | private MqttQoS qos;
32 |
33 | private String topic;
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/bean/SessionMessage.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.bean;
2 |
3 | import io.netty.handler.codec.mqtt.MqttQoS;
4 | import lombok.Builder;
5 | import lombok.Data;
6 |
7 | /**
8 | * Session会话数据保存
9 | *
10 | * @author lxr
11 | * @create 2017-11-27 19:28
12 | **/
13 | @Builder
14 | @Data
15 |
16 | public class SessionMessage {
17 |
18 | private byte[] byteBuf;
19 |
20 | private MqttQoS qoS;
21 |
22 | private String topic;
23 |
24 |
25 | public String getString(){
26 | return new String(byteBuf);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/bean/WillMeaasge.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.bean;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | /**
7 | * 遗嘱消息
8 | *
9 | * @author lxr
10 | * @create 2017-11-23 15:08
11 | **/
12 | @Builder
13 | @Data
14 | public class WillMeaasge {
15 |
16 | private String willTopic;
17 |
18 | private String willMessage;
19 |
20 |
21 | private boolean isRetain;
22 |
23 | private int qos;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/channel/AbstractChannelService.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.channel;
2 |
3 | import com.google.common.cache.Cache;
4 | import com.google.common.cache.CacheBuilder;
5 | import com.lxr.iot.bootstrap.bean.MqttChannel;
6 | import com.lxr.iot.bootstrap.bean.RetainMessage;
7 | import com.lxr.iot.bootstrap.BaseApi;
8 | import com.lxr.iot.bootstrap.ChannelService;
9 | import com.lxr.iot.bootstrap.channel.cache.CacheMap;
10 | import com.lxr.iot.bootstrap.queue.MessageTransfer;
11 | import io.netty.channel.Channel;
12 | import io.netty.util.AttributeKey;
13 | import lombok.extern.slf4j.Slf4j;
14 | import org.apache.commons.lang3.StringUtils;
15 |
16 | import java.util.Collection;
17 | import java.util.Optional;
18 | import java.util.concurrent.ConcurrentHashMap;
19 | import java.util.concurrent.ConcurrentLinkedQueue;
20 | import java.util.concurrent.ExecutorService;
21 | import java.util.concurrent.Executors;
22 |
23 | /**
24 | * 抽象类
25 | *
26 | * @author lxr
27 | * @create 2017-12-12 20:01
28 | **/
29 | @Slf4j
30 | public abstract class AbstractChannelService extends PublishApiSevice implements ChannelService ,BaseApi {
31 |
32 |
33 | protected AttributeKey _login = AttributeKey.valueOf("login");
34 |
35 | protected AttributeKey _deviceId = AttributeKey.valueOf("deviceId");
36 |
37 | protected static char SPLITOR = '/';
38 |
39 | protected ExecutorService executorService =Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
40 |
41 |
42 | protected static CacheMap cacheMap= new CacheMap<>();
43 |
44 |
45 | protected static ConcurrentHashMap mqttChannels = new ConcurrentHashMap<>(); // deviceId - mqChannel 登录
46 |
47 |
48 | protected static ConcurrentHashMap> retain = new ConcurrentHashMap<>(); // topic - 保留消息
49 |
50 |
51 |
52 | protected static Cache> mqttChannelCache = CacheBuilder.newBuilder().maximumSize(100).build();
53 |
54 | public AbstractChannelService(MessageTransfer transfer ) {
55 | super(transfer);
56 | }
57 |
58 |
59 | protected Collection getChannels(String topic,TopicFilter topicFilter){
60 | try {
61 | return mqttChannelCache.get(topic, () -> topicFilter.filter(topic));
62 | } catch (Exception e) {
63 | log.info(String.format("guava cache key topic【%s】 channel value== null ",topic));
64 | }
65 | return null;
66 | }
67 |
68 |
69 | @FunctionalInterface
70 | interface TopicFilter{
71 | Collection filter(String topic);
72 | }
73 |
74 | protected boolean deleteChannel(String topic,MqttChannel mqttChannel){
75 | return Optional.ofNullable(topic).map(s -> {
76 | mqttChannelCache.invalidate(s);
77 | return cacheMap.delete(getTopic(s),mqttChannel);
78 | }).orElse(false);
79 | }
80 |
81 | protected boolean addChannel(String topic,MqttChannel mqttChannel)
82 | {
83 | return Optional.ofNullable(topic).map(s -> {
84 | mqttChannelCache.invalidate(s);
85 | return cacheMap.putData(getTopic(s),mqttChannel);
86 | }).orElse(false);
87 | }
88 |
89 | /**
90 | * 获取channel
91 | */
92 | public MqttChannel getMqttChannel(String deviceId){
93 | return Optional.ofNullable(deviceId).map(s -> mqttChannels.get(s))
94 | .orElse(null);
95 |
96 | }
97 |
98 | /**
99 | * 获取channelId
100 | */
101 | public String getDeviceId(Channel channel){
102 | return Optional.ofNullable(channel).map( channel1->channel1.attr(_deviceId).get())
103 | .orElse(null);
104 | }
105 |
106 |
107 |
108 | protected String[] getTopic(String topic) {
109 | return Optional.ofNullable(topic).map(s ->
110 | StringUtils.split(topic,SPLITOR)
111 | ).orElse(null);
112 | }
113 |
114 |
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/channel/ClientSessionService.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.channel;
2 |
3 | import com.lxr.iot.bootstrap.bean.SessionMessage;
4 | import org.springframework.stereotype.Service;
5 |
6 | import java.util.Optional;
7 | import java.util.concurrent.ConcurrentHashMap;
8 | import java.util.concurrent.ConcurrentLinkedQueue;
9 |
10 | /**
11 | * 会话保留处理
12 | *
13 | * @author lxr
14 | * @create 2017-11-23 11:21
15 | **/
16 | @Service
17 | public class ClientSessionService {
18 |
19 | private static ConcurrentHashMap> queueSession = new ConcurrentHashMap<>(); // 连接关闭后 保留此session 数据 deviceId
20 |
21 |
22 | public void saveSessionMsg(String deviceId, SessionMessage sessionMessage) {
23 | ConcurrentLinkedQueue sessionMessages = queueSession.getOrDefault(deviceId, new ConcurrentLinkedQueue<>());
24 | boolean flag;
25 | do{
26 | flag = sessionMessages.add(sessionMessage);
27 | }
28 | while (!flag);
29 | queueSession.put(deviceId,sessionMessages);
30 | }
31 |
32 | public ConcurrentLinkedQueue getByteBuf(String deviceId){
33 | return Optional.ofNullable(deviceId).map(s -> queueSession.get(s))
34 | .orElse(null);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/channel/PublishApiSevice.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.channel;
2 |
3 | import com.lxr.iot.bootstrap.bean.MqttChannel;
4 | import com.lxr.iot.bootstrap.bean.SendMqttMessage;
5 | import com.lxr.iot.bootstrap.bean.WillMeaasge;
6 | import com.lxr.iot.bootstrap.queue.MessageTransfer;
7 | import com.lxr.iot.enums.ConfirmStatus;
8 | import io.netty.buffer.Unpooled;
9 | import io.netty.channel.Channel;
10 | import io.netty.handler.codec.mqtt.*;
11 | import lombok.extern.slf4j.Slf4j;
12 |
13 | /**
14 | * 发送消息以及确认
15 | *
16 | * @author lxr
17 | * @create 2017-11-24 11:04
18 | **/
19 | @Slf4j
20 | public class PublishApiSevice {
21 |
22 | private final MessageTransfer transfer ;
23 |
24 | public PublishApiSevice(MessageTransfer transfer) {
25 | this.transfer = transfer;
26 | }
27 |
28 |
29 | /**
30 | * 写入遗嘱消息
31 | */
32 | protected void writeWillMsg(MqttChannel mqttChannel, WillMeaasge willMeaasge) {
33 | // dup保证消息可靠传输,默认为0,只占用一个字节,表示第一次发送。不能用于检测消息重复发送等
34 | switch (willMeaasge.getQos()){
35 | case 0: // qos0
36 | sendQos0Msg(mqttChannel.getChannel(),willMeaasge.getWillTopic(),willMeaasge.getWillMessage().getBytes());
37 | break;
38 | case 1: // qos1
39 | sendQosConfirmMsg(MqttQoS.AT_LEAST_ONCE,mqttChannel,willMeaasge.getWillTopic(),willMeaasge.getWillMessage().getBytes());
40 | break;
41 | case 2: // qos2
42 | sendQosConfirmMsg(MqttQoS.EXACTLY_ONCE,mqttChannel,willMeaasge.getWillTopic(),willMeaasge.getWillMessage().getBytes());
43 | break;
44 | }
45 |
46 |
47 | }
48 |
49 | protected void sendQosConfirmMsg(MqttQoS qos, MqttChannel mqttChannel, String topic, byte[] bytes) {
50 | if(mqttChannel.isLogin()){
51 | int messageId = mqttChannel.messageId();
52 | switch (qos){
53 | case AT_LEAST_ONCE:
54 | mqttChannel.addSendMqttMessage(messageId,sendQos1Msg(mqttChannel.getChannel(),topic,false,bytes,messageId));
55 | break;
56 | case EXACTLY_ONCE:
57 | mqttChannel.addSendMqttMessage(messageId,sendQos2Msg(mqttChannel.getChannel(),topic,false,bytes,messageId));
58 | break;
59 | }
60 | }
61 |
62 | }
63 |
64 |
65 | /**
66 | * 发送 qos1 类的消息
67 | */
68 | private SendMqttMessage sendQos1Msg(Channel channel, String topic,boolean isDup, byte[] byteBuf,int messageId){
69 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH,isDup, MqttQoS.AT_LEAST_ONCE,false,0);
70 | MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(topic,messageId );
71 | MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader,mqttPublishVariableHeader, Unpooled.wrappedBuffer(byteBuf));
72 | channel.writeAndFlush(mqttPublishMessage);
73 | return addQueue(channel,messageId,topic,byteBuf,MqttQoS.AT_LEAST_ONCE,ConfirmStatus.PUB);
74 | }
75 |
76 |
77 |
78 | /**
79 | * 发送 qos0 类的消息 byte
80 | */
81 | protected void sendQos0Msg(Channel channel, String topic, byte[] byteBuf){
82 | if(channel!=null){
83 | sendQos0Msg(channel,topic,byteBuf,0);
84 | }
85 | }
86 | private void sendQos0Msg(Channel channel, String topic, byte[] byteBuf,int messageId){
87 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH,false, MqttQoS.AT_MOST_ONCE,false,0);
88 | MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(topic,messageId );
89 | MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader,mqttPublishVariableHeader,Unpooled.wrappedBuffer(byteBuf));
90 | channel.writeAndFlush(mqttPublishMessage);
91 | }
92 |
93 |
94 |
95 |
96 | private SendMqttMessage sendQos2Msg(Channel channel, String topic,boolean isDup, byte[] byteBuf, int messageId) {
97 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH,isDup, MqttQoS.EXACTLY_ONCE,false,0);
98 | MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(topic,messageId );
99 | MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader,mqttPublishVariableHeader, Unpooled.wrappedBuffer(byteBuf));
100 | channel.writeAndFlush(mqttPublishMessage);
101 | return addQueue(channel,messageId,topic,byteBuf,MqttQoS.EXACTLY_ONCE,ConfirmStatus.PUB);
102 | }
103 |
104 |
105 | /**
106 | * 发送qos1 publish 确认消息
107 | */
108 | protected void sendPubBack(Channel channel,int messageId){
109 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBACK,false, MqttQoS.AT_MOST_ONCE,false,0x02);
110 | MqttMessageIdVariableHeader from = MqttMessageIdVariableHeader.from(messageId);
111 | MqttPubAckMessage mqttPubAckMessage = new MqttPubAckMessage(mqttFixedHeader,from);
112 | channel.writeAndFlush(mqttPubAckMessage);
113 | }
114 |
115 |
116 | /**
117 | * 发送qos2 publish 确认消息 第一步
118 | */
119 | protected void sendPubRec( MqttChannel mqttChannel,int messageId){
120 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBREC,false, MqttQoS.AT_LEAST_ONCE,false,0x02);
121 | MqttMessageIdVariableHeader from = MqttMessageIdVariableHeader.from(messageId);
122 | MqttPubAckMessage mqttPubAckMessage = new MqttPubAckMessage(mqttFixedHeader,from);
123 | Channel channel = mqttChannel.getChannel();
124 | channel.writeAndFlush(mqttPubAckMessage);
125 | SendMqttMessage sendMqttMessage = addQueue(channel, messageId, null, null, null, ConfirmStatus.PUBREC);
126 | mqttChannel.addSendMqttMessage(messageId,sendMqttMessage);
127 | }
128 |
129 | /**
130 | * 发送qos2 publish 确认消息 第二步
131 | */
132 | protected void sendPubRel(Channel channel,boolean isDup,int messageId){
133 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBREL,isDup, MqttQoS.AT_LEAST_ONCE,false,0x02);
134 | MqttMessageIdVariableHeader from = MqttMessageIdVariableHeader.from(messageId);
135 | MqttPubAckMessage mqttPubAckMessage = new MqttPubAckMessage(mqttFixedHeader,from);
136 | channel.writeAndFlush(mqttPubAckMessage);
137 | }
138 |
139 | /**
140 | * 发送qos2 publish 确认消息 第三步
141 | */
142 | protected void sendToPubComp(Channel channel,int messageId){
143 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBCOMP,false, MqttQoS.AT_MOST_ONCE,false,0x02);
144 | MqttMessageIdVariableHeader from = MqttMessageIdVariableHeader.from(messageId);
145 | MqttPubAckMessage mqttPubAckMessage = new MqttPubAckMessage(mqttFixedHeader,from);
146 | channel.writeAndFlush(mqttPubAckMessage);
147 | }
148 |
149 | private SendMqttMessage addQueue(Channel channel,int messageId,String topic,byte[] datas,MqttQoS mqttQoS,ConfirmStatus confirmStatus){
150 | SendMqttMessage build = SendMqttMessage.builder().
151 | channel(channel).
152 | confirmStatus(confirmStatus).
153 | messageId(messageId)
154 | .topic(topic)
155 | .qos(mqttQoS)
156 | .byteBuf(datas)
157 | .build();
158 | transfer.addQueue(build);
159 | return build;
160 | }
161 |
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/channel/WillService.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.channel;
2 |
3 | import com.lxr.iot.bootstrap.bean.WillMeaasge;
4 | import com.lxr.iot.bootstrap.BaseApi;
5 | import com.lxr.iot.bootstrap.ChannelService;
6 | import lombok.Getter;
7 | import lombok.NoArgsConstructor;
8 | import lombok.Setter;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.util.concurrent.ConcurrentHashMap;
15 |
16 | /**
17 | * 遗嘱消息处理
18 | *
19 | * @author lxr
20 | * @create 2017-11-23 11:20
21 | **/
22 | @Slf4j
23 | @Component
24 | @Setter
25 | @Getter
26 | @NoArgsConstructor
27 | public class WillService implements BaseApi {
28 |
29 |
30 | @Autowired
31 | ChannelService channelService;
32 |
33 | private static ConcurrentHashMap willMeaasges = new ConcurrentHashMap<>(); // deviceid -WillMeaasge
34 |
35 |
36 |
37 | /**
38 | * 保存遗嘱消息
39 | */
40 | public void save(String deviceid, WillMeaasge build) {
41 | willMeaasges.put(deviceid,build); // 替换旧的
42 | }
43 |
44 |
45 | public void doSend( String deviceId) { // 客户端断开连接后 开启遗嘱消息发送
46 | if(StringUtils.isNotBlank(deviceId)&&(willMeaasges.get(deviceId))!=null){
47 | WillMeaasge willMeaasge = willMeaasges.get(deviceId);
48 | channelService.sendWillMsg(willMeaasge); // 发送遗嘱消息
49 | if(!willMeaasge.isRetain()){ // 移除
50 | willMeaasges.remove(deviceId);
51 | log.info("deviceId will message["+willMeaasge.getWillMessage()+"] is removed");
52 | }
53 | }
54 | }
55 |
56 | /**
57 | * 删除遗嘱消息
58 | */
59 | public void del(String deviceid ) {willMeaasges.remove(deviceid);}
60 | }
61 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/channel/cache/CacheMap.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.channel.cache;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import java.util.concurrent.ConcurrentHashMap;
8 | import java.util.concurrent.CopyOnWriteArrayList;
9 |
10 | /**
11 | * 缓存操作
12 | *
13 | * @author lxr
14 | * @create 2017-12-02 13:48
15 | **/
16 | @Slf4j
17 | public class CacheMap {
18 |
19 | private ConcurrentHashMap> datas = new ConcurrentHashMap<>();
20 |
21 | public boolean putData(K[] topic, V v){
22 | if(topic.length==1){
23 | Node kvNode = buildOne(topic[0], v);
24 | if(kvNode!=null && kvNode.topic.equals(topic[0])){
25 | return true;
26 | }
27 | }
28 | else{
29 | Node kvNode = buildOne(topic[0], null);
30 | for(int i=1;i kvNode = datas.get(ks[0]);
48 | for(int i=1;i getData(K[] ks){
57 | if(ks.length==1){
58 | return datas.get(ks[0]).get();
59 | }
60 | else{
61 | Node node = datas.get(ks[0]);
62 | if(node!=null){
63 | List all = new ArrayList<>();
64 | all.addAll(node.get());
65 | for(int i=1;i buildOne(K k,V v){
79 |
80 | Node node = this.datas.computeIfAbsent(k, key -> {
81 | Node kObjectNode = new Node<>(k);
82 | return kObjectNode;
83 | });
84 | if(v!=null){
85 | node.put(v);
86 | }
87 | return node;
88 | }
89 |
90 |
91 |
92 | class Node{
93 |
94 | private final K topic;
95 |
96 |
97 | private volatile ConcurrentHashMap> map =new ConcurrentHashMap<>() ;
98 |
99 |
100 | List vs = new CopyOnWriteArrayList<>();
101 |
102 |
103 | public K getTopic() {return topic;}
104 |
105 | Node(K topic) {
106 | this.topic = topic;
107 | }
108 |
109 | public boolean delValue(V v){
110 | return vs.remove(v);
111 | }
112 |
113 | public Node putNextValue(K k,V v){
114 | Node kvNode = map.computeIfAbsent(k, key -> {
115 | Node node = new Node<>(k);
116 | return node;
117 | });
118 | if(v!=null){
119 | kvNode.put(v);
120 | }
121 | return kvNode;
122 | }
123 |
124 |
125 | public Node getNext(K k){
126 | return map.get(k);
127 | }
128 |
129 |
130 | public boolean put(V v){
131 | return vs.add(v);
132 | }
133 |
134 |
135 | public List get(){
136 | return vs;
137 | }
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/coder/ByteBufToWebSocketFrameEncoder.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.coder;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.handler.codec.MessageToMessageEncoder;
6 | import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * ByteBufToWebSocketFrameEncoder
12 | *
13 | * @author lxr
14 | * @create 2017-11-20 13:46
15 | **/
16 | public class ByteBufToWebSocketFrameEncoder extends MessageToMessageEncoder {
17 |
18 |
19 | @Override
20 | protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List out) throws Exception {
21 | if (byteBuf == null) {
22 | return;
23 | }
24 | BinaryWebSocketFrame result = new BinaryWebSocketFrame();
25 | result.content().writeBytes(byteBuf);
26 | out.add(result);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/coder/WebSocketFrameToByteBufDecoder.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.coder;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.handler.codec.MessageToMessageDecoder;
6 | import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * WebSocketFrameToByteBufDecoder
12 | *
13 | * @author lxr
14 | * @create 2017-11-20 13:46
15 | **/
16 | public class WebSocketFrameToByteBufDecoder extends MessageToMessageDecoder {
17 |
18 | @Override
19 | protected void decode(ChannelHandlerContext channelHandlerContext, BinaryWebSocketFrame wsFrame, List out) throws Exception {
20 | ByteBuf buf = wsFrame.content();
21 | buf.retain();
22 | out.add(buf);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/handler/DefaultMqttHandler.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.handler;
2 |
3 | import com.lxr.iot.bootstrap.ChannelService;
4 | import com.lxr.iot.bootstrap.bean.MqttChannel;
5 | import com.lxr.iot.exception.NoFindHandlerException;
6 | import com.lxr.iot.mqtt.MqttHander;
7 | import com.lxr.iot.mqtt.MqttHandlerIntf;
8 | import com.lxr.iot.mqtt.ServerMqttHandlerService;
9 | import com.lxr.iot.properties.ConnectOptions;
10 | import io.netty.channel.Channel;
11 | import io.netty.channel.ChannelHandler;
12 | import io.netty.channel.ChannelHandlerContext;
13 | import io.netty.handler.codec.mqtt.*;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.stereotype.Component;
17 |
18 | /**
19 | * 默认 mqtthandler处理
20 | *
21 | * @author lxr
22 | * @create 2017-11-20 13:58
23 | **/
24 |
25 | @ChannelHandler.Sharable
26 | @Slf4j
27 | @Component
28 | public class DefaultMqttHandler extends MqttHander {
29 |
30 |
31 | private final MqttHandlerIntf mqttHandlerApi;
32 |
33 | @Autowired
34 | ChannelService channelService;
35 |
36 |
37 | public DefaultMqttHandler(MqttHandlerIntf mqttHandlerApi) {
38 | super(mqttHandlerApi);
39 | this.mqttHandlerApi = mqttHandlerApi;
40 | }
41 |
42 | @Override
43 | public void doMessage(ChannelHandlerContext channelHandlerContext, MqttMessage mqttMessage) {
44 | Channel channel = channelHandlerContext.channel();
45 | ServerMqttHandlerService serverMqttHandlerService;
46 | if(mqttHandlerApi instanceof ServerMqttHandlerService){
47 | serverMqttHandlerService =(ServerMqttHandlerService)mqttHandlerApi;
48 | }
49 | else{
50 | throw new NoFindHandlerException("server handler 不匹配");
51 | }
52 | MqttFixedHeader mqttFixedHeader = mqttMessage.fixedHeader();
53 | if(mqttFixedHeader.messageType().equals(MqttMessageType.CONNECT)){
54 | if(!serverMqttHandlerService.login(channel, (MqttConnectMessage) mqttMessage)){
55 | channel.close();
56 | }
57 | return ;
58 | }
59 | MqttChannel mqttChannel = channelService.getMqttChannel(channelService.getDeviceId(channel));
60 | if(mqttChannel!=null && mqttChannel.isLogin()){
61 | switch (mqttFixedHeader.messageType()){
62 | case PUBLISH:
63 | serverMqttHandlerService.publish(channel, (MqttPublishMessage) mqttMessage);
64 | break;
65 | case SUBSCRIBE:
66 | serverMqttHandlerService.subscribe(channel, (MqttSubscribeMessage) mqttMessage);
67 | break;
68 | case PINGREQ:
69 | serverMqttHandlerService.pong(channel);
70 | break;
71 | case DISCONNECT:
72 | serverMqttHandlerService.disconnect(channel);
73 | break;
74 | case UNSUBSCRIBE:
75 | serverMqttHandlerService.unsubscribe(channel,(MqttUnsubscribeMessage)mqttMessage);
76 | break;
77 | case PUBACK:
78 | mqttHandlerApi.puback(channel,mqttMessage);
79 | break;
80 | case PUBREC:
81 | mqttHandlerApi.pubrec(channel,mqttMessage);
82 | break;
83 | case PUBREL:
84 | mqttHandlerApi.pubrel(channel,mqttMessage);
85 | break;
86 | case PUBCOMP:
87 | mqttHandlerApi.pubcomp(channel,mqttMessage);
88 | break;
89 | default:
90 | break;
91 | }
92 | }
93 | }
94 |
95 |
96 |
97 | @Override
98 | public void channelActive(ChannelHandlerContext ctx) throws Exception {
99 | log.info("【DefaultMqttHandler:channelActive】"+ctx.channel().remoteAddress().toString()+"链接成功");
100 | }
101 |
102 | @Override
103 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
104 | log.error("exception",cause);
105 | mqttHandlerApi.close(ctx.channel());
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/queue/DisruptorMessageStarter.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.queue;
2 |
3 | import com.lmax.disruptor.BlockingWaitStrategy;
4 | import com.lmax.disruptor.EventHandler;
5 | import com.lmax.disruptor.RingBuffer;
6 | import com.lmax.disruptor.YieldingWaitStrategy;
7 | import com.lmax.disruptor.dsl.Disruptor;
8 | import com.lmax.disruptor.dsl.ProducerType;
9 | import com.lmax.disruptor.util.DaemonThreadFactory;
10 | import org.springframework.beans.factory.DisposableBean;
11 | import org.springframework.stereotype.Component;
12 |
13 |
14 | @Component
15 | public class DisruptorMessageStarter implements MessageStarter , DisposableBean {
16 |
17 |
18 | private Disruptor disruptor = new Disruptor<>(MessageEvent::new,
19 | 1024, DaemonThreadFactory.INSTANCE, ProducerType.MULTI,
20 | new BlockingWaitStrategy());
21 |
22 | private final EventHandler eventHandler;
23 |
24 | public DisruptorMessageStarter(EventHandler eventHandler) {
25 | this.eventHandler = eventHandler;
26 | disruptor.handleEventsWith(eventHandler);
27 | disruptor.start();
28 | }
29 |
30 |
31 | @Override
32 | public RingBuffer getRingBuffer() {
33 | return disruptor.getRingBuffer();
34 | }
35 |
36 | @Override
37 | public void shutdown() {
38 | disruptor.shutdown();
39 | }
40 |
41 |
42 | @Override
43 | public void destroy() throws Exception {
44 | shutdown();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/queue/MessageEvent.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.queue;
2 |
3 | import com.lxr.iot.bootstrap.bean.SendMqttMessage;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class MessageEvent {
8 |
9 | private SendMqttMessage message;
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/queue/MessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.queue;
2 |
3 |
4 | import com.lmax.disruptor.EventHandler;
5 | import com.lxr.iot.bootstrap.bean.SendMqttMessage;
6 | import io.netty.buffer.Unpooled;
7 | import io.netty.channel.Channel;
8 | import io.netty.handler.codec.mqtt.*;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component
12 | public class MessageHandler implements EventHandler {
13 |
14 | private final MessageTransfer messageTransfer;
15 |
16 | public MessageHandler(MessageTransfer messageTransfer) {
17 | this.messageTransfer = messageTransfer;
18 | }
19 |
20 |
21 | @Override
22 | public void onEvent(MessageEvent messageEvent, long l, boolean b) throws Exception {
23 | SendMqttMessage message=messageEvent.getMessage();
24 | if(message.getChannel().isActive()){
25 | switch (message.getConfirmStatus()){
26 | case PUB:
27 | pubMessage(message.getChannel(),message);
28 | break;
29 | case PUBREL:
30 | sendAck(MqttMessageType.PUBREL,message);
31 | break;
32 | case PUBREC:
33 | sendAck(MqttMessageType.PUBREC,message);
34 | break;
35 | }
36 | }
37 | }
38 |
39 | private void pubMessage(Channel channel, SendMqttMessage mqttMessage){
40 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH,true, mqttMessage.getQos(),mqttMessage.isRetain(),0);
41 | MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(mqttMessage.getTopic(),mqttMessage.getMessageId());
42 | MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader,mqttPublishVariableHeader, Unpooled.wrappedBuffer(mqttMessage.getByteBuf()));
43 | channel.writeAndFlush(mqttPublishMessage);
44 | }
45 |
46 | protected void sendAck(MqttMessageType type,SendMqttMessage mqttMessage){
47 | MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(type,true, MqttQoS.AT_LEAST_ONCE,false,0x02);
48 | MqttMessageIdVariableHeader from = MqttMessageIdVariableHeader.from(mqttMessage.getMessageId());
49 | MqttPubAckMessage mqttPubAckMessage = new MqttPubAckMessage(mqttFixedHeader,from);
50 | mqttMessage.getChannel().writeAndFlush(mqttPubAckMessage);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/queue/MessageStarter.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.queue;
2 |
3 | import com.lmax.disruptor.RingBuffer;
4 |
5 | public interface MessageStarter {
6 |
7 | RingBuffer getRingBuffer();
8 |
9 | void shutdown();
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/java/com/lxr/iot/bootstrap/queue/MessageTransfer.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.bootstrap.queue;
2 |
3 | import com.lmax.disruptor.RingBuffer;
4 | import com.lxr.iot.bootstrap.bean.SendMqttMessage;
5 | import io.netty.channel.Channel;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Component;
8 | import reactor.core.Disposable;
9 | import reactor.core.publisher.Mono;
10 |
11 | import java.time.Duration;
12 | import java.util.Optional;
13 | import java.util.concurrent.ConcurrentHashMap;
14 |
15 | @Component
16 | public class MessageTransfer {
17 |
18 | private ConcurrentHashMap> concurrentHashMap = new ConcurrentHashMap<>();
19 |
20 | @Autowired
21 | private MessageStarter messageStarter;
22 |
23 | public void addQueue(SendMqttMessage sendMqttMessage){
24 | RingBuffer ringBuffer= messageStarter.getRingBuffer();
25 | ConcurrentHashMap qos=concurrentHashMap.computeIfAbsent(sendMqttMessage.getChannel().id().toString(),(key)->{
26 | ConcurrentHashMap map=new ConcurrentHashMap<>();
27 | return map;
28 | });
29 | qos.put(sendMqttMessage.getMessageId(),
30 | Mono.fromRunnable(()->{
31 | ringBuffer.publishEvent((event, sequence) -> event.setMessage(sendMqttMessage));
32 | qos.remove(sendMqttMessage.getMessageId());
33 | })
34 | .delaySubscription(Duration.ofSeconds(10)).subscribe());
35 | }
36 |
37 | public void removeQueue(Channel channel,Integer messageId){
38 | Optional.ofNullable(concurrentHashMap.get(channel.id().toString()))
39 | .ifPresent(map-> Optional.ofNullable(map.get(messageId))
40 | .ifPresent(disposable -> {
41 | disposable.dispose();
42 | map.remove(messageId);
43 | }));
44 | }
45 |
46 |
47 |
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/iot_push_server/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | com.lxr.iot.auto.ServerAutoConfigure
--------------------------------------------------------------------------------
/iot_push_server_starter_test/iot_push_server_starter.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/iot_push_server_starter_test/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | iot_push
5 | com.lxr.iot
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | iot_push_server_starter
11 | jar
12 |
13 | iot_push_server_starter
14 | http://maven.apache.org
15 |
16 |
17 | UTF-8
18 |
19 |
20 |
21 |
22 | com.lxr.iot
23 | iot_push_server
24 | 1.0-SNAPSHOT
25 |
26 |
27 | junit
28 | junit
29 | 3.8.1
30 | test
31 |
32 |
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-compiler-plugin
38 | 3.3
39 |
40 | 1.8
41 | 1.8
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-maven-plugin
47 |
48 | com.lxr.iot.ServerApplication
49 |
50 |
51 |
52 |
53 | repackage
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/iot_push_server_starter_test/src/main/java/com/lxr/iot/DefaultAutoService.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot;
2 |
3 | import com.lxr.iot.bootstrap.BaseAuthService;
4 | import org.springframework.stereotype.Service;
5 |
6 | /**
7 | * @author lxr
8 | * @create 2018-02-09 14:58
9 | **/
10 |
11 | @Service
12 | public class DefaultAutoService implements BaseAuthService{
13 | @Override
14 | public boolean authorized(String username, String password) {
15 | return true;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/iot_push_server_starter_test/src/main/java/com/lxr/iot/ServerApplication.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 | import org.springframework.context.ConfigurableApplicationContext;
5 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
6 |
7 | import static org.springframework.boot.SpringApplication.run;
8 |
9 | /**
10 | * 启动类
11 | *
12 | * @author lxr
13 | * @create 2017-11-18 13:54
14 | **/
15 | @SpringBootApplication
16 | @EnableAspectJAutoProxy //注解开启对aspectJ的支持
17 | public class ServerApplication {
18 | public static void main(String[] args) {
19 | ConfigurableApplicationContext run = run(ServerApplication.class, args);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iot_push_server_starter_test/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 |
2 | lxr:
3 | iot:
4 | server:
5 | serverName: test #服务名
6 | port: 1884 #端口
7 | keepalive: true #Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。可以将此功能视为TCP的心跳机制,需要注意的是:默认的心跳间隔是7200s即2小时。Netty默认关闭该功能
8 | reuseaddr: true #地址复用,默认值False。有四种情况可以使用:(1).当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你希望启动的程序的socket2要占用该地址和端口,比如重启服务且保持先前端口。(2).有多块网卡或用IP Alias技术的机器在同一端口启动多个进程,但每个进程绑定的本地IP地址不能相同。(3).单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。(4).完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。
9 | tcpNodelay: true #TCP参数,立即发送数据,默认值为Ture(Netty默认为True而操作系统默认为False)。该值设置Nagle算法的启用,改算法将小的碎片数据连接成更大的报文来最小化所发送的报文的数量,如果需要发送一些较小的报文,则需要禁用该算法。Netty默认禁用该算法,从而最小化报文传输延时。
10 | sndbuf: 10485760 # Socket参数,TCP数据发送缓冲区大小。
11 | revbuf: 10485760 # Socket参数,TCP数据接收缓冲区大小。
12 | heart: 180 # 读超时时间
13 | backlog: 1024 # Socket参数,服务端接受连接的队列长度,如果队列已满,客户端连接将被拒绝
14 | ssl: false # 使用ssl加密
15 | mqttHander: com.lxr.iot.bootstrap.handler.DefaultMqttHandler # 默认处理
16 | initalDelay: 10 # mqtt qos1 qos2 消息 重发延迟
17 | protocol: MQTT # MQTT MQTT_WS_MQTT(mqtt.js) MQTT_WS_PAHO(paho.js)
18 | period: 10 # mqtt qos1 qos2 消息 重发周期
19 | jksFile: /securesocket.jks # ssl 加密 jks文件地址
20 | jksStorePassword: mu$tch8ng3 # 读取jks密码
21 | jksCertificatePassword: inc0rrect # 读取私钥密码
22 | logging:
23 | level:
24 | io.netty: debug
--------------------------------------------------------------------------------
/iot_push_server_starter_test/src/main/resources/securesocket.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1ssqq1lxr/iot_push/f65d6ef642c7fb8da329c01957d2adab7765fdde/iot_push_server_starter_test/src/main/resources/securesocket.jks
--------------------------------------------------------------------------------
/iot_push_test/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | iot_push
5 | com.lxr.iot
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | iot_push_test
11 | jar
12 |
13 | iot_push_test
14 | http://maven.apache.org
15 |
16 |
17 | UTF-8
18 |
19 |
20 |
21 |
22 | com.lxr.iot
23 | iot_push_client
24 | 1.0-SNAPSHOT
25 |
26 |
27 | com.lxr.iot
28 | iot_push_common
29 | 1.0-SNAPSHOT
30 |
31 |
32 | junit
33 | junit
34 | 3.8.1
35 | test
36 |
37 |
38 | org.eclipse.paho
39 | org.eclipse.paho.client.mqttv3
40 | 1.1.1
41 |
42 |
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-compiler-plugin
48 | 3.3
49 |
50 | 1.8
51 | 1.8
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/java/com/lxr/iot/client/MyListener.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.client;
2 |
3 | import com.lxr.iot.auto.MqttListener;
4 | import com.lxr.iot.auto.MqttMessageListener;
5 | import io.netty.handler.codec.mqtt.MqttQoS;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Service;
8 |
9 | /**
10 | * @author lxr
11 | * @create 2018-01-12 15:14
12 | **/
13 | @Slf4j
14 | @Service
15 | @MqttMessageListener(qos = MqttQoS.AT_LEAST_ONCE,topic = "/t1/t2")
16 | public class MyListener implements MqttListener{
17 | @Override
18 | public void callBack(String topic, String msg) {
19 | log.info("============================="+topic+msg);
20 | }
21 |
22 | @Override
23 | public void callThrowable(Throwable e) {
24 | log.info("exception",e);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/java/com/lxr/iot/client/main.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.client;
2 |
3 | import com.lxr.iot.auto.MqttListener;
4 | import com.lxr.iot.bootstrap.MqttProducer;
5 | import com.lxr.iot.bootstrap.Producer;
6 | import com.lxr.iot.properties.ConnectOptions;
7 |
8 | /**
9 | * 测试
10 | *
11 | * @author lxr
12 | * @create 2018-01-10 10:09
13 | **/
14 | public class main {
15 |
16 | public static void main(String[] strings) throws InterruptedException {
17 | Producer producer = new MqttProducer();
18 | ConnectOptions connectOptions = new ConnectOptions();
19 | connectOptions.setBacklog(1024);
20 | connectOptions.setConnectTime(1000l);
21 | connectOptions.setSsl(false);
22 | connectOptions.setServerIp("192.168.91.1");
23 | connectOptions.setPort(1884);
24 | connectOptions.setBossThread(1);
25 | connectOptions.setWorkThread(8);
26 | connectOptions.setMinPeriod(10);
27 | connectOptions.setRevbuf(1024);
28 | connectOptions.setSndbuf(1024);
29 | connectOptions.setTcpNodelay(true);
30 | connectOptions.setKeepalive(true);
31 | ConnectOptions.MqttOpntions mqttOpntions = new ConnectOptions.MqttOpntions();
32 | mqttOpntions.setClientIdentifier("111");
33 | mqttOpntions.setHasPassword(false);
34 | mqttOpntions.setHasPassword(false);
35 | mqttOpntions.setClientIdentifier("client-2");
36 | connectOptions.setMqtt(mqttOpntions);
37 | producer.setMqttListener(new MqttListener() {
38 | @Override
39 | public void callBack(String topic, String msg) {
40 | System.out.print("========================================"+topic+msg);
41 | }
42 | @Override
43 | public void callThrowable(Throwable e) {
44 |
45 | }
46 | });
47 | producer.connect(connectOptions);
48 | // producer.sub(SubMessage.builder().qos(MqttQoS.AT_LEAST_ONCE).topic("/t1/t2").build());
49 | producer.pub("/test","123123",2);
50 | producer.pub("/haha","123213123",2);
51 | Thread.sleep(1000000l);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/java/com/lxr/iot/paho/MqttClientProducerTest.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.paho;
2 |
3 | import org.eclipse.paho.client.mqttv3.*;
4 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
5 |
6 | import java.io.UnsupportedEncodingException;
7 | import java.util.Random;
8 | import java.util.concurrent.ExecutorService;
9 | import java.util.concurrent.Executors;
10 |
11 | /**
12 | * 测试客户端
13 | *
14 | * @author lxr
15 | * @create 2017-11-28 14:14
16 | **/
17 | public class MqttClientProducerTest {
18 |
19 | private static int qos = 1; //只有一次
20 | private static String broker = "tcp://127.0.0.1:8882";
21 | private static String userName = "smqtt";
22 | private static String passWord = "smqtt";
23 |
24 |
25 | static ExecutorService service = Executors.newFixedThreadPool(100);
26 |
27 | private static MqttClient connect(String clientId, String userName,
28 | String password) throws MqttException {
29 | MemoryPersistence persistence = new MemoryPersistence();
30 | MqttConnectOptions connOpts = new MqttConnectOptions();
31 | connOpts.setCleanSession(true);
32 | connOpts.setUserName(userName);
33 | connOpts.setPassword(password.toCharArray());
34 | connOpts.setConnectionTimeout(10);
35 | connOpts.setKeepAliveInterval(20);
36 | // SSLSocketFactory socketFactory = SecureSocketSslContextFactory.getClientContext().getSocketFactory();
37 | // connOpts.setSocketFactory(socketFactory);
38 | connOpts.setWill("test/lxr", "haha".getBytes(), 0, false);
39 | // String[] uris = {"tcp://10.100.124.206:1883","tcp://10.100.124.207:1883"};
40 | // connOpts.setServerURIs(uris); //起到负载均衡和高可用的作用
41 | MqttClient mqttClient = new MqttClient(broker, clientId, persistence);
42 | mqttClient.setCallback(new PushCallback("test"));
43 | mqttClient.connect(connOpts);
44 | return mqttClient;
45 | }
46 |
47 | private static void pub(MqttClient sampleClient, String msg, String topic)
48 | throws MqttPersistenceException, MqttException {
49 | MqttMessage message = null;
50 | try {
51 | message = new MqttMessage(msg.getBytes("utf-8"));
52 | } catch (UnsupportedEncodingException e) {
53 | e.printStackTrace();
54 | }
55 | message.setQos(qos);
56 | message.setRetained(true);
57 | sampleClient.publish(topic, message);
58 | }
59 |
60 | private static void publish(String str, String clientId, String topic) throws MqttException {
61 | MqttClient mqttClient = connect(clientId, userName, passWord);
62 | if (mqttClient != null) {
63 |
64 | for (; ; ) {
65 | pub(mqttClient, str, topic);
66 | try {
67 | Thread.sleep(10);
68 |
69 | } catch (InterruptedException e) {
70 | e.printStackTrace();
71 | }
72 |
73 | }
74 | }
75 |
76 | // if (mqttClient != null) {
77 | // mqttClient.connect();
78 | // }
79 | }
80 |
81 | public static void main(String[] args) throws MqttException, InterruptedException {
82 | for(int i =0 ;i<100;i++){
83 | final int index = i;
84 | service.execute((()->{
85 | try {
86 | publish("message content"+index, String.valueOf(new Random().nextInt(100000000)), "test/"+index);
87 | } catch (MqttException e) {
88 | e.printStackTrace();
89 | }
90 | }));
91 |
92 | }
93 |
94 | }
95 | }
96 |
97 | class PushCallback implements MqttCallback {
98 |
99 |
100 | private String threadId;
101 |
102 | public PushCallback(String threadId) {
103 | this.threadId = threadId;
104 | }
105 |
106 | public void connectionLost(Throwable cause) {
107 |
108 | }
109 |
110 | public void deliveryComplete(IMqttDeliveryToken token) {
111 | // System.out.println("deliveryComplete---------" + token.isComplete());
112 | }
113 |
114 | public void messageArrived(String topic, MqttMessage message) throws Exception {
115 | String msg = new String(message.getPayload());
116 | System.out.println(topic + " " + msg);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/java/com/lxr/iot/paho/comsumer2/MqttClientConsumerTest.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.paho.comsumer2;
2 |
3 | import com.lxr.iot.ssl.SecureSocketSslContextFactory;
4 | import org.eclipse.paho.client.mqttv3.*;
5 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
6 |
7 | import javax.net.ssl.SSLSocketFactory;
8 | import java.util.concurrent.ExecutorService;
9 | import java.util.concurrent.Executors;
10 |
11 | /**
12 | * 测试客户端
13 | *
14 | * @author lxr
15 | * @create 2017-11-28 14:14
16 | **/
17 | public class MqttClientConsumerTest {
18 |
19 | private static int qos = 1; //只有一次
20 | private static String broker = "tcp://127.0.0.1:8882";
21 | private static String userName = "smqtt";
22 | private static String passWord = "smqtt";
23 | static ExecutorService service = Executors.newFixedThreadPool(100);
24 |
25 |
26 |
27 |
28 | private static MqttClient connect(String clientId, String userName,
29 | String password) throws MqttException {
30 | MemoryPersistence persistence = new MemoryPersistence();
31 | MqttConnectOptions connOpts = new MqttConnectOptions();
32 | connOpts.setCleanSession(false);
33 | connOpts.setUserName(userName);
34 | connOpts.setPassword(password.toCharArray());
35 | connOpts.setConnectionTimeout(10);
36 | connOpts.setKeepAliveInterval(20);
37 | // SSLSocketFactory socketFactory = SecureSocketSslContextFactory.getClientContext().getSocketFactory();
38 | // connOpts.setSocketFactory(socketFactory);
39 | // String[] uris = {"tcp://10.100.124.206:1883","tcp://10.100.124.207:1883"};
40 | // connOpts.setServerURIs(uris); //起到负载均衡和高可用的作用
41 | MqttClient mqttClient = new MqttClient(broker, clientId, persistence);
42 | mqttClient.setCallback(new PushCallback("test"));
43 | mqttClient.connect(connOpts);
44 | return mqttClient;
45 | }
46 |
47 | private static void sub(MqttClient sampleClient, String msg, String topic)
48 | throws MqttPersistenceException, MqttException {
49 | sampleClient.subscribe(topic);
50 | }
51 |
52 | private static void sub(String str,String clientId,String topic) throws MqttException{
53 | MqttClient mqttClient = connect(clientId,userName,passWord);
54 |
55 | if (mqttClient != null) {
56 | sub(mqttClient, str, topic);
57 | System.out.println(topic+" " + str);
58 | }
59 |
60 | // if (mqttClient != null) {
61 | // mqttClient.connect();
62 | // }
63 | }
64 |
65 | public static void main(String[] args) throws MqttException {
66 | for(int i=0;i<100;i++){
67 | final int index = i;
68 | service.execute(()->{
69 | try {
70 | sub("message content","client-id-"+index,"test/"+index);
71 | } catch (MqttException e) {
72 |
73 | }
74 | });
75 | }
76 | }
77 | }
78 |
79 | class PushCallback implements MqttCallback {
80 |
81 |
82 | private String threadId;
83 | public PushCallback(String threadId){
84 | this.threadId = threadId;
85 | }
86 |
87 | public void connectionLost(Throwable cause) {
88 |
89 | }
90 |
91 | public void deliveryComplete(IMqttDeliveryToken token) {
92 | // System.out.println("deliveryComplete---------" + token.isComplete());
93 | }
94 |
95 | public void messageArrived(String topic, MqttMessage message) throws Exception {
96 | String msg = new String(message.getPayload());
97 | System.out.println(topic + " " + msg);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/java/com/lxr/iot/paho/consumer/MqttClientConsumerTest1.java:
--------------------------------------------------------------------------------
1 | package com.lxr.iot.paho.consumer;
2 |
3 | import com.lxr.iot.ssl.SecureSocketSslContextFactory;
4 | import org.eclipse.paho.client.mqttv3.*;
5 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
6 |
7 | import javax.net.ssl.SSLSocketFactory;
8 |
9 | /**
10 | * 测试客户端
11 | *
12 | * @author lxr
13 | * @create 2017-11-28 14:14
14 | **/
15 | public class MqttClientConsumerTest1 {
16 |
17 | private static int qos = 0; //只有一次
18 | private static String broker = "ssl://127.0.0.1:8882";
19 | private static String userName = "smqtt";
20 | private static String passWord = "smqtt";
21 |
22 |
23 | private static MqttClient connect(String clientId, String userName,
24 | String password) throws MqttException {
25 | MemoryPersistence persistence = new MemoryPersistence();
26 | MqttConnectOptions connOpts = new MqttConnectOptions();
27 | connOpts.setCleanSession(true);
28 | connOpts.setUserName(userName);
29 | connOpts.setPassword(password.toCharArray());
30 | connOpts.setConnectionTimeout(10);
31 | connOpts.setKeepAliveInterval(20);
32 | SSLSocketFactory socketFactory = SecureSocketSslContextFactory.getClientContext().getSocketFactory();
33 | connOpts.setSocketFactory(socketFactory);
34 | // String[] uris = {"tcp://10.100.124.206:1883","tcp://10.100.124.207:1883"};
35 | // connOpts.setServerURIs(uris); //起到负载均衡和高可用的作用
36 | MqttClient mqttClient = new MqttClient(broker, clientId, persistence);
37 | mqttClient.setCallback(new PushCallback("test1"));
38 | mqttClient.connect(connOpts);
39 | return mqttClient;
40 | }
41 |
42 | private static void sub(MqttClient sampleClient, String msg, String topic)
43 | throws MqttPersistenceException, MqttException {
44 | sampleClient.subscribe(topic);
45 | }
46 |
47 | private static void sub(String str,String clientId,String topic) throws MqttException{
48 | MqttClient mqttClient = connect(clientId,userName,passWord);
49 |
50 | if (mqttClient != null) {
51 | sub(mqttClient, str, topic);
52 | System.out.println(topic+" " + str);
53 | }
54 |
55 | // if (mqttClient != null) {
56 | // mqttClient.connect();
57 | // }
58 | }
59 |
60 | public static void main(String[] args) throws MqttException {
61 | sub("message content","client-id-0","/test/haha");
62 | }
63 | }
64 |
65 | class PushCallback implements MqttCallback {
66 |
67 |
68 | private String threadId;
69 | public PushCallback(String threadId){
70 | this.threadId = threadId;
71 | }
72 |
73 | public void connectionLost(Throwable cause) {
74 |
75 | }
76 |
77 | public void deliveryComplete(IMqttDeliveryToken token) {
78 | // System.out.println("deliveryComplete---------" + token.isComplete());
79 | }
80 |
81 | public void messageArrived(String topic, MqttMessage message) throws Exception {
82 | String msg = new String(message.getPayload());
83 | System.out.println(topic + " " + msg);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 |
2 | lxr:
3 | iot:
4 | client:
5 | connectTime: 10 # 链接超时
6 | serverIp: 127.0.0.1
7 | port: 1884 #端口
8 | keepalive: true #Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。可以将此功能视为TCP的心跳机制,需要注意的是:默认的心跳间隔是7200s即2小时。Netty默认关闭该功能
9 | reuseaddr: true #地址复用,默认值False。有四种情况可以使用:(1).当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你希望启动的程序的socket2要占用该地址和端口,比如重启服务且保持先前端口。(2).有多块网卡或用IP Alias技术的机器在同一端口启动多个进程,但每个进程绑定的本地IP地址不能相同。(3).单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。(4).完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。
10 | tcpNodelay: true #TCP参数,立即发送数据,默认值为Ture(Netty默认为True而操作系统默认为False)。该值设置Nagle算法的启用,改算法将小的碎片数据连接成更大的报文来最小化所发送的报文的数量,如果需要发送一些较小的报文,则需要禁用该算法。Netty默认禁用该算法,从而最小化报文传输延时。
11 | sndbuf: 10485760 # Socket参数,TCP数据发送缓冲区大小。
12 | revbuf: 10485760 # Socket参数,TCP数据接收缓冲区大小。
13 | heart: 60 # 读超时时间
14 | backlog: 1024 # Socket参数,服务端接受连接的队列长度,如果队列已满,客户端连接将被拒绝
15 | ssl: true # 使用ssl加密
16 | initalDelay: 10 # mqtt qos1 qos2 消息 重发延迟
17 | period: 10 # mqtt qos1 qos2 消息 重发周期
18 | jksFile: /securesocket.jks # ssl 加密 jks文件地址
19 | jksStorePassword: mu$tch8ng3 # 读取jks密码
20 | jksCertificatePassword: inc0rrect # 读取私钥密码
21 | workThread: 1
22 | mqtt:
23 | clientIdentifier: client-1
24 | isWillFlag: false
25 | isCleanSession: true
26 | keepAliveTimeSeconds: 3000
27 | hasUserName: false
28 | hasPassword: false
29 | willTopic: /test # isWillFlag = true 时候配置
30 | willMessage: 123123 # isWillFlag = true 时候配置
31 | password: 123 # hasPassword = true 时候配置
32 | userName: 123 # hasUserName = true 时候配置
33 | isWillRetain: true # isWillFlag = true 时候配置
34 | willQos: 0 # isWillFlag = true 时候配置
35 | KeepAliveTime: 10 # 心跳时长
36 |
37 | server:
38 | port: 8989
39 | logging:
40 | level:
41 | io.netty: debug
42 |
--------------------------------------------------------------------------------
/iot_push_test/src/main/resources/securesocket.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1ssqq1lxr/iot_push/f65d6ef642c7fb8da329c01957d2adab7765fdde/iot_push_test/src/main/resources/securesocket.jks
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.lxr.iot
6 | iot_push
7 | 1.0-SNAPSHOT
8 |
9 | iot_push_common
10 | iot_push_server
11 | iot_push_test
12 | iot_push_client
13 | iot_push_client_starter_test
14 | iot_push_server_starter_test
15 |
16 | pom
17 |
18 | iot_push
19 | http://maven.apache.org
20 |
21 |
22 | UTF-8
23 | ${encoding}
24 | ${encoding}
25 | 1.8
26 | 1.5.3.RELEASE
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------