游戏攻略网站怎么做,杭州动漫设计公司最新招聘,沈阳seo公司,网站建设的毕业设计选题管理系统IoT是什么The Internet of things的简称IoT#xff0c;即是物联网的意思IoT推送系统的设计比如说#xff0c;像一些智能设备#xff0c;需要通过APP或者微信中的小程序等#xff0c;给设备发送一条指令#xff0c;让这个设备下载或者播放音乐#xff0c;那么需要做什么才…IoT是什么The Internet of things的简称IoT即是物联网的意思IoT推送系统的设计比如说像一些智能设备需要通过APP或者微信中的小程序等给设备发送一条指令让这个设备下载或者播放音乐那么需要做什么才可以完成上面的任务呢首先需要推送服务器这个服务器主要负责消息的分发不处理业务消息设备会连接到推送服务器APP通过把指令发送到推送服务器然后推送服务器再把指令分发给相应的设备。可是当买设备的人越来越多推送服务器所能承受的压力就越大这个时候就需要对推送服务器做集群一台不行就搞十台那么还有一个问题就是推送服务器增加了设备如何找到相应的服务器然后和服务器建立连接呢注册中心可以解决这个问题每一台服务器都注册到注册中心上设备会请求注册中心得到推送服务器的地址然后再和服务器建立连接。而且还会有相应的redis集群用来记录设备订阅的主题以及设备的信息APP发送指令到设备其实就是发送了一串数据相应的会提供推送API提供一些接口通过接口把数据发送过去而推送API不是直接去连接推送服务器的中间还会有MQ集群主要用来消息的存储推送API推送消息到MQ推送服务器从MQ中订阅消息以上就是简单的IoT推送系统的设计。下面看下结构图注意设备连接到注册中心的是短连接设备和推送服务器建立的连接是长连接心跳检测机制简述心跳检测心跳检测就是判断对方是否还存活一般采用定时的发送一些简单的包如果在指定的时间段内没有收到对方的回应则判断对方已经挂掉Netty提供了IdleStateHandler类来实现心跳简单的使用如下pipeline.addFirst(new IdleStateHandler(0, 0, 1, TimeUnit.SECONDS));下面是IdleStateHandler的构造函数public IdleStateHandler( long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) { this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);}四个参数说明readerIdleTime读超时时间writerIdleTime写超时时间allIdleTime所有事件超时时间TimeUnit unit超时时间单位心跳检测机制代码示例简单示例 服务端static final int BEGIN_PORT 8088; static final int N_PORT 100; public static void main(String[] args) { new PingServer().start(BEGIN_PORT, N_PORT); } public void start(int beginPort, int nPort) { System.out.println(启动服务....); EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEventLoopGroup(); ServerBootstrap bootstrap new ServerBootstrap(); bootstrap.handler(new LoggingHandler(LogLevel.INFO)); bootstrap.group(bossGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.childOption(ChannelOption.SO_REUSEADDR, true); bootstrap.childHandler(new ChannelInitializer() { Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline ch.pipeline(); pipeline.addFirst(new IdleStateHandler(0, 0, 1, TimeUnit.SECONDS)); pipeline.addLast(new PingHandler()); //每个连接都有个ConnectionCountHandler对连接记数进行增加 pipeline.addLast(new ConnectionCountHandler()); } }); bootstrap.bind(beginPort).addListener((ChannelFutureListener) future - { System.out.println(端口绑定成功: beginPort); }); System.out.println(服务已启动!);}public class PingHandler extends SimpleUserEventChannelHandler { private static final ByteBuf PING_BUF Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(ping.getBytes())); private int count; Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf (ByteBuf) msg; byte[] data new byte[buf.readableBytes()]; buf.readBytes(data); String str new String(data); if (pong.equals(str)) { System.out.println(ctx ---- str); count--; } ctx.fireChannelRead(msg); } Override protected void eventReceived(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception { if (evt.state() ALL_IDLE) { if (count 3) { System.out.println(检测到客户端连接无响应断开连接 ctx.channel()); ctx.close(); return; } count; System.out.println(ctx.channel() ---- ping); ctx.writeAndFlush(PING_BUF.duplicate()); } ctx.fireUserEventTriggered(evt); }}客户端//服务端的IP private static final String SERVER_HOST localhost; static final int BEGIN_PORT 8088; static final int N_PORT 100; public static void main(String[] args) { new PoneClient().start(BEGIN_PORT, N_PORT); } public void start(final int beginPort, int nPort) { System.out.println(客户端启动....); EventLoopGroup eventLoopGroup new NioEventLoopGroup(); final Bootstrap bootstrap new Bootstrap(); bootstrap.group(eventLoopGroup); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.SO_REUSEADDR, true); bootstrap.handler(new ChannelInitializer() { Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new PongHandler()); } }); int index 0; int port; String serverHost System.getProperty(server.host, SERVER_HOST); ChannelFuture channelFuture bootstrap.connect(serverHost, beginPort); channelFuture.addListener((ChannelFutureListener) future - { if (!future.isSuccess()) { System.out.println(连接失败退出!); System.exit(0); } }); try { channelFuture.get(); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }public class PongHandler extends SimpleChannelInboundHandler { private static final ByteBuf PONG_BUF Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(pong.getBytes())); Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { ByteBuf buf (ByteBuf) msg; byte[] data new byte[buf.readableBytes()]; buf.readBytes(data); String str new String(data); if (ping.equals(str)) { ctx.writeAndFlush(PONG_BUF.duplicate()); } }}服务端输出结果百万长连接优化连接优化代码示例服务端 static final int BEGIN_PORT 11000; static final int N_PORT 100; public static void main(String[] args) { new Server().start(BEGIN_PORT, N_PORT); } public void start(int beginPort, int nPort) { System.out.println(启动服务....); EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEventLoopGroup(); ServerBootstrap bootstrap new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.childOption(ChannelOption.SO_REUSEADDR, true); bootstrap.childHandler(new ChannelInitializer() { Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline ch.pipeline(); //每个连接都有个ConnectionCountHandler对连接记数进行增加 pipeline.addLast(new ConnectionCountHandler()); } }); //这里开启 10000到100099这100个端口 for (int i 0; i nPort; i) { int port beginPort i; bootstrap.bind(port).addListener((ChannelFutureListener) future - { System.out.println(端口绑定成功: port); }); } System.out.println(服务已启动!); }客户端//服务端的IP private static final String SERVER_HOST 192.168.231.129; static final int BEGIN_PORT 11000; static final int N_PORT 100; public static void main(String[] args) { new Client().start(BEGIN_PORT, N_PORT); } public void start(final int beginPort, int nPort) { System.out.println(客户端启动....); EventLoopGroup eventLoopGroup new NioEventLoopGroup(); final Bootstrap bootstrap new Bootstrap(); bootstrap.group(eventLoopGroup); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.SO_REUSEADDR, true); int index 0; int port; String serverHost System.getProperty(server.host, SERVER_HOST); //从10000的端口开始按端口递增的方式进行连接 while (!Thread.interrupted()) { port beginPort index; try { ChannelFuture channelFuture bootstrap.connect(serverHost, port); channelFuture.addListener((ChannelFutureListener) future - { if (!future.isSuccess()) { System.out.println(连接失败退出!); System.exit(0); } }); channelFuture.get(); } catch (Exception e) { } if (index nPort) { index 0; } } }ConnectionCountHandler类public class ConnectionCountHandler extends ChannelInboundHandlerAdapter { //这里用来对连接数进行记数,每两秒输出到控制台 private static final AtomicInteger nConnection new AtomicInteger(); static { Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() - { System.out.println(连接数: nConnection.get()); }, 0, 2, TimeUnit.SECONDS); } Override public void channelActive(ChannelHandlerContext ctx) { nConnection.incrementAndGet(); } Override public void channelInactive(ChannelHandlerContext ctx) { nConnection.decrementAndGet(); }}上述的代码会打包成jar放到linux上运行对于上述的优化来说程序方面的就暂时不做下面会从操作系统层面进行优化让其支撑起百万连接。TCP连接四元组在优化之前先来看下网络里的一个小知识TCP连接四元组 服务器的IP服务器的POST客户端的IP客户端的POST端口的范围一般是1到65535配置优化现在在虚拟机上安装两个linux系统配置分别是地址CPU内存JDK作用192.168.15.130VM-4核8G1.8客户端192.168.15.128VM-4核8G1.8服务端启动服务端 java -Xmx4g -Xms4g -cp network-study-1.0-SNAPSHOT-jar-with-dependencies.jar com.dongnaoedu.network.netty.million.Server out.log 21 启动客户端 java -Xmx4g -Xms4g -Dserver.host192.168.15.128 -cp network-study-1.0-SNAPSHOT-jar-with-dependencies.jar com.dongnaoedu.network.netty.million.Client启动服务端后可以使用tail -f命令查看out.log中的日志客户端启动后如果报了以下错误需要修改系统的文件最大句柄和进程的文件最大句柄Caused by: java.io.IOException: Too many open files at sun.nio.ch.FileDispatcherImpl.init(Native Method) at sun.nio.ch.FileDispatcherImpl.(FileDispatcherImpl.java:35) ... 8 more优化系统最大句柄 查看操作系统最大文件句柄数执行命令cat /proc/sys/fs/file-max查看最大句柄数是否满足需要如果不满足通过vim /etc/sysctl.conf命令插入如下配置fs.file-max 1000000设置单进程打开的文件最大句柄数执行命令ulimit -a查看当前设置是否满足要求[roottest-server2 download]# ulimit -a | grep open filesopen files (-n) 1024当并发接入的Tcp连接数超过上限时就会提示“Too many open files”所有的新客户端接入将会失败。通过vim /etc/security/limits.conf 修改配置参数* soft nofile 1000000* hard nofile 1000000修改配置参数后注销生效。如果程序被中断或报了异常java.io.IOException: 设备上没有空间 at sun.nio.ch.EPollArrayWrapper.epollCtl(Native Method) at sun.nio.ch.EPollArrayWrapper.updateRegistrations(EPollArrayWrapper.java:299) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:268) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) at sun.nio.ch.SelectorImpl.selectNow(SelectorImpl.java:105) at io.netty.channel.nio.SelectedSelectionKeySetSelector.selectNow(SelectedSelectionKeySetSelector.java:56) at io.netty.channel.nio.NioEventLoop.selectNow(NioEventLoop.java:750) at io.netty.channel.nio.NioEventLoop$1.get(NioEventLoop.java:71) at io.netty.channel.DefaultSelectStrategy.calculateStrategy(DefaultSelectStrategy.java:30) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:426) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)此时可以查看操作系统的日志more /var/log/messages或在程序启动时执行tail -f /var/log/messages 监控日志。如果日志中出现以下内容说明需要优化TCP/IP参数Jun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned socketsJun 4 16:55:01 localserver kernel: TCP: too many orphaned sockets优化TCP/IP相关参数查看客户端端口范围限制cat /proc/sys/net/ipv4/ip_local_port_range通过vim /etc/sysctl.conf 修改网络参数客户端修改端口范围的限制net.ipv4.ip_local_port_range 1024 65535优化TCP参数net.ipv4.tcp_mem 786432 2097152 3145728net.ipv4.tcp_wmem 4096 4096 16777216net.ipv4.tcp_rmem 4096 4096 16777216net.ipv4.tcp_keepalive_time 1800net.ipv4.tcp_keepalive_intvl 20net.ipv4.tcp_keepalive_probes 5net.ipv4.tcp_tw_reuse 1net.ipv4.tcp_tw_recycle 1net.ipv4.tcp_fin_timeout 30参数说明:net.ipv4.tcp_mem 分配给tcp连接的内存单位是page(1个Page通常是4KB可以通过getconf PAGESIZE命令查看)三个值分别是最小、默认、和最大。比如以上配置中的最大是3145728那分配给tcp的最大内存31457284 / 1024 / 1024 12GB。一个TCP连接大约占7.5KB粗略可以算出百万连接≈7.51000000/41875000 3145728足以满足测试所需。net.ipv4.tcp_wmem 为每个TCP连接分配的写缓冲区内存大小单位是字节。三个值分别是最小、默认、和最大。net.ipv4.tcp_rmem 为每个TCP连接分配的读缓冲区内存大小单位是字节。三个值分别是最小、默认、和最大。net.ipv4.tcp_keepalive_time 最近一次数据包发送与第一次keep alive探测消息发送的事件间隔用于确认TCP连接是否有效。net.ipv4.tcp_keepalive_intvl: 在未获得探测消息响应时发送探测消息的时间间隔。net.ipv4.tcp_keepalive_probes 判断TCP连接失效连续发送的探测消息个数达到之后判定连接失效。net.ipv4.tcp_tw_reuse 是否允许将TIME_WAIT Socket 重新用于新的TCP连接默认为0表示关闭。net.ipv4.tcp_tw_recycle 是否开启TIME_WAIT Socket 的快速回收功能默认为0表示关闭。net.ipv4.tcp_fin_timeout 套接字自身关闭时保持在FIN_WAIT_2 状态的时间。默认为60。转载于https://juejin.im/post/6861560765200105486作者狐言不胡言