精华内容
下载资源
问答
  • 维持长连接

    千次阅读 2010-04-19 11:03:00
    现成的长连接应用--Connection:keep-alive 在HTTp协议请求和响应中加入这条就能维持长连接。再封装HTTP消息数据体的消息应用就显的非常简单易用 Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的...

     

    现成的长连接应用--Connection:keep-alive
    在HTTp协议请求和响应中加入这条就能维持长连接。
    再封装HTTP消息数据体的消息应用就显的非常简单易用

    Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。市场上 的大部分Web服务器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,这里存在另外一个问题:虽然为客户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep- Alive功能对资源利用的影响尤其突出。 此功能为HTTP 1.1预设的功能,HTTP 1.0加上Keep-Alive header也可以提供HTTP的持续作用功能。


    Keep-Alive: timeout=5, max=100
    timeout:过期时间5秒(对应httpd.conf里的参数是:KeepAliveTimeout),max是最多一百次请求,强制断掉连接
    就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。见下面的四个图,注意看Date的值(前后时间差都是在5秒之 内)!



    Tomcat中的相关设置,在server.xml 中的Connector 元素中。
    keepAliveTimeout:
    The number of milliseconds this Connector will wait for another HTTP request before closing the connection. The default value is to use the value that has been set for the connectionTimeout attribute.

    maxKeepAliveRequests:
    The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.

    **************************************************************************************

    在网页开发过程中,Keep-Alive是HTTP协议中非常重要的一个属性。大家知道HTTP构建在TCP之上。在HTTP早期实现中,每个 HTTP请求都要打开一个socket连接。这种做效率很低,因为一个Web 页面中的很多HTTP请求都指向同一个服务器。例如,很多为Web页面中的图片发起的请求都指向一个通用的图片服务器。持久连接的引入解决了多对已请求服务器导致的socket连接低效性的问题。它使浏览器可以再一个单独的连接上进行多个请求。浏览器和服务器使用Connection头ilai指出对 Keep-Alive的支持。

     

    笔者在去年遇到一个跟Keep-Alive的问题:

     

    问题现象: 一个JSP页面,居然要耗时40多秒。网页中有大量的图片的CSS

     

    问题解决: 原因也找了半天,原来Apache配置里面,把Keep-Alive的开关关闭了。这个是个大问题,工程师为什么要关闭它,原来他考虑的太简单了,我们知道Apache适合处于短连接的请求,处理时间越短,并发数才能上去,原来他是这么考虑,但是没有办法,只能这样了,还是打开Keep-Alive开关吧。

     

    当然,不是所有的情况都设置KeepAlive为On,下面的文字总结比较好:

     

    【在使用apache 的过程中,KeepAlive 属性我一直保持为默认值On,其实,该属性设置为On还是Off还是要具体问题具体分析的,在生产环境中的影响还是蛮大的。

    KeepAlive 选项到底有什么用处?如果你用过Mysql ,应该知道Mysql的连接属性中有一个与KeepAlive 类似的Persistent Connection,即:长连接(PConnect)。该属性打开的话,可以使一次TCP连接为同一用户的多次请求服务,提高了响应速度。

    比如很多网页中图片、CSS、JS、Html都在一台Server上,当用户访问其中的Html网页时,网页中的图片、Css、Js都构成了访问请求,打开KeepAlive 属性可以有效地降低TCP握手的次数(当然浏览器对同一域下同时请求的图片数有限制,一般是2),减少httpd进程数,从而降低内存的使用(假定 prefork模式)。MaxKeepAliveRequests 和KeepAliveTimeOut 两个属性在KeepAlive =On时起作用,可以控制持久连接的生存时间和最大服务请求数。

    不过,上面说的只是一种情形,那就是静态网页居多的情况下,并且网页中的其他请求与网页在同一台Server上。当你的应用动态程序(比如:php )居多,用户访问时由动态程序即时生成html内容,html内容中图片素材和Css、Js等比较少或者散列在其他Server上时,KeepAlive =On反而会降低Apache 的性能。为什么呢?

    前面提到过,KeepAlive =On时,每次用户访问,打开一个TCP连接,Apache 都会保持该连接一段时间,以便该连接能连续为同一client服务,在KeepAliveTimeOut还没到期并且 MaxKeepAliveRequests还没到阈值之前,Apache 必然要有一个httpd进程来维持该连接,httpd进程不是廉价的,他要消耗内存和CPU时间片的。假如当前Apache 每秒响应100个用户访问,KeepAliveTimeOut=5,此时httpd进程数就是100*5=500个(prefork 模式),一个httpd进程消耗5M内存的话,就是500*5M=2500M=2.5G,夸张吧?当然,Apache 与Client只进行了100次TCP连接。如果你的内存够大,系统负载不会太高,如果你的内存小于2.5G,就会用到Swap,频繁的Swap切换会加重CPU的Load。

    现在我们关掉KeepAlive ,Apache 仍然每秒响应100个用户访问,因为我们将图片、js、css等分离出去了,每次访问只有1个request,此时httpd的进程数是 100*1=100个,使用内存100*5M=500M,此时Apache 与Client也是进行了100次TCP连接。性能却提升了太多。

    总结:

    1、当你的Server内存充足时,KeepAlive =On还是Off对系统性能影响不大。

    2、当你的Server上静态网页(Html、图片、Css、Js)居多时,建议打开KeepAlive 。

    3、当你的Server多为动态请求(因为连接数据库,对文件系统访问较多),KeepAlive 关掉,会节省一定的内存,节省的内存正好可以作为文件系统的Cache(vmstat命令中cache一列),降低I/O压力。

    PS:当KeepAlive =On时,KeepAliveTimeOut的设置其实也是一个问题,设置的过短,会导致Apache 频繁建立连接,给Cpu造成压力,设置的过长,系统中就会堆积无用的Http连接,消耗掉大量内存,具体设置多少,可以进行不断的调节,因你的网站浏览和服务器配

    展开全文
  • linux维持长连接调优

    千次阅读 2017-02-16 21:49:41
    ip_conntrack 是Linux NAT一个跟踪连接条目的模块记录着允许的跟踪连接条目ip_conntrack 模块会记录 tcp 通讯协议的 established connection 记录, 而且预设 timeout 时间长达五天 (432,000 秒).所以局域网中当有人...
    由于linux内核的限制,files open too many是一个常见的问题
    修改/etc/sysctl.conf文件

    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_tw_reuse = 1

    net.ipv4.tcp_timestamps = 0
    net.ipv4.ip_local_port_range = 1024 65000
    fs.file-max=655360
    net.netfilter.nf_conntrack_max = 798641


    以上参数存在/proc/sys/下的相应目录

    [quote]目前,大多的 ip_conntrack_* 已被 nf_conntrack_* 取代,很多 ip_conntrack_* 仅仅是个 alias,原先的 ip_conntrack 的 /proc/sys/net/ipv4/netfilter/ 依然存在,但是新的 nf_conntrack 在 /proc/sys/net/netfilter/ 中[/quote]
    [quote]file-max是设置 系统所有进程一共可以打开的文件数量
    /proc/sys/fs/file-max
    [/quote]

    [quote]
    ip_conntrack 是Linux NAT一个跟踪连接条目的模块记录着允许的跟踪连接条目ip_conntrack 模块会记录 tcp 通讯协议的 established connection 记录, 而且预设 timeout 时间长达五天 (432,000 秒).所以局域网中当有人使用p2p类的软件就很容易使ip_conntrack达到最大值...也由此造成。
    echo "3600" > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
    [/quote]


    /etc/security/limits.conf
    *    soft    nofile  1000000  
    * hard nofile 1000000

    [quote]ulimit作用:即设置当前shell以及由它启动的进程的资源限制[/quote]


    [quote]
    1.验证某个进程的限制

    # ps -ef |grep nginx

    将得出的PID XXX带入下面

    #cat /proc/XXX/limits

    查看Max open files 那一行

    2.验证系统级别的限制

    # ulimit -n

    3.验证内核级别的限制

    #cat /proc/sys/fs/file-max
    [/quote]
    展开全文
  •  多机器只要把连接map内容维护到缓存里面 集中管理 就可以了。。 Netty   准备说明:引入java-websocket,netty-all-5.0等的jar包。其中内部心跳机制使用userEventTriggered事件方式实现,客户端的心跳实现...

    ps: 以下是单机的处理方案 

         多机器只要把连接map内容维护到缓存里面 集中管理 就可以了。。

    Netty

     

    准备说明:引入java-websocket,netty-all-5.0等的jar包。其中内部心跳机制使用userEventTriggered事件方式实现,客户端的心跳实现客户端的断点重连工作,服务端的心跳实现服务端清除多余链接的功能

     

    。以下为一些实现的代码:1. 

    [java] view plain copy

    package base;  

      

    /** 

     *  

     * 请求类型的消息 

     */  

    public class AskMsg extends BaseMsg {  

        public AskMsg() {  

            super();  

            setType(MsgType.ASK);  

        }  

        private AskParams params;  

      

        public AskParams getParams() {  

            return params;  

        }  

      

        public void setParams(AskParams params) {  

            this.params = params;  

        }  

    }  

    2. 
    [java] view plain copy

    package base;  

      

    import java.io.Serializable;  

      

    /** 

     *   

     */  

    public class AskParams implements Serializable {  

        private static final long serialVersionUID = 1L;  

        private String auth;  

        private String content;  

          

        public String getContent() {  

            return content;  

        }  

      

        public void setContent(String content) {  

            this.content = content;  

        }  

      

        public String getAuth() {  

            return auth;  

        }  

      

        public void setAuth(String auth) {  

            this.auth = auth;  

        }  

    }  

    3. 
    [java] view plain copy

    package base;  

      

    import java.io.Serializable;  

      

    /** 

     *  

     * 必须实现序列,serialVersionUID 一定要有 

     */  

      

    public abstract class BaseMsg  implements Serializable {  

        private static final long serialVersionUID = 1L;  

        private MsgType type;  

        //必须唯一,否者会出现channel调用混乱  

        private String clientId;  

      

        //初始化客户端id  

        public BaseMsg() {  

            this.clientId = Constants.getClientId();  

        }  

      

        public String getClientId() {  

            return clientId;  

        }  

      

        public void setClientId(String clientId) {  

            this.clientId = clientId;  

        }  

      

        public MsgType getType() {  

            return type;  

        }  

      

        public void setType(MsgType type) {  

            this.type = type;  

        }  

    }  

    4. 
    [java] view plain copy

    package base;  

      

      

    /** 

     *   

     */  

    public class Constants {  

        private static String clientId;  

      

        public static String getClientId() {  

            return clientId;  

        }  

      

        public static void setClientId(String clientId) {  

            Constants.clientId = clientId;  

        }  

    }  

    5. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     * 登录验证类型的消息 

     */  

    public class LoginMsg extends BaseMsg {  

        private String userName;  

        private String password;  

        public LoginMsg() {  

            super();  

            setType(MsgType.LOGIN);  

        }  

      

        public String getUserName() {  

            return userName;  

        }  

      

        public void setUserName(String userName) {  

            this.userName = userName;  

        }  

      

        public String getPassword() {  

            return password;  

        }  

      

        public void setPassword(String password) {  

            this.password = password;  

        }  

    }  

    6. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     */  

    public enum  MsgType {  

        PING,ASK,REPLY,LOGIN  

    }  

    7. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     * 心跳检测的消息类型 

     */  

    public class PingMsg extends BaseMsg {  

        public PingMsg() {  

            super();  

            setType(MsgType.PING);  

        }  

    }  

    8. 
    [java] view plain copy

    package base;  

      

    import java.io.Serializable;  

      

    /** 

     *   

     */  

    public class ReplyBody implements Serializable {  

        private static final long serialVersionUID = 1L;  

    }  

    9. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     */  

    public class ReplyClientBody extends ReplyBody {  

        private String clientInfo;  

      

        public ReplyClientBody(String clientInfo) {  

            this.clientInfo = clientInfo;  

        }  

      

        public String getClientInfo() {  

            return clientInfo;  

        }  

      

        public void setClientInfo(String clientInfo) {  

            this.clientInfo = clientInfo;  

        }  

    }  

    10. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     */  

    public class ReplyMsg extends BaseMsg {  

        public ReplyMsg() {  

            super();  

            setType(MsgType.REPLY);  

        }  

        private ReplyBody body;  

      

        public ReplyBody getBody() {  

            return body;  

        }  

      

        public void setBody(ReplyBody body) {  

            this.body = body;  

        }  

    }  

    11. 
    [java] view plain copy

    package base;  

      

    /** 

     *   

     */  

    public class ReplyServerBody extends ReplyBody {  

        private String serverInfo;  

        public ReplyServerBody(String serverInfo) {  

            this.serverInfo = serverInfo;  

        }  

        public String getServerInfo() {  

            return serverInfo;  

        }  

        public void setServerInfo(String serverInfo) {  

            this.serverInfo = serverInfo;  

        }  

    }  

    12.  netty客户端启动类
    [java] view plain copy

    package client;  

      

    import io.netty.bootstrap.Bootstrap;  

    import io.netty.buffer.Unpooled;  

    import io.netty.channel.ChannelFuture;  

    import io.netty.channel.ChannelInitializer;  

    import io.netty.channel.ChannelOption;  

    import io.netty.channel.EventLoopGroup;  

    import io.netty.channel.nio.NioEventLoopGroup;  

    import io.netty.channel.socket.SocketChannel;  

    import io.netty.channel.socket.nio.NioSocketChannel;  

    import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;  

    import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;  

    import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;  

    import io.netty.handler.codec.http.websocketx.WebSocketFrame;  

    import io.netty.handler.codec.serialization.ClassResolvers;  

    import io.netty.handler.codec.serialization.ObjectDecoder;  

    import io.netty.handler.codec.serialization.ObjectEncoder;  

    import io.netty.handler.timeout.IdleStateHandler;  

    import io.netty.util.concurrent.DefaultEventExecutorGroup;  

    import io.netty.util.concurrent.EventExecutorGroup;  

      

    import java.io.BufferedReader;  

    import java.io.IOException;  

    import java.io.InputStreamReader;  

    import java.util.concurrent.TimeUnit;  

      

    import base.AskMsg;  

    import base.AskParams;  

    import base.Constants;  

    import base.LoginMsg;  

      

    /** 

     *  

     */  

    public class NettyClientBootstrap {  

        private int port;  

        private String host;  

        private SocketChannel socketChannel;  

        private static final EventExecutorGroup group = new DefaultEventExecutorGroup(20);  

        public NettyClientBootstrap(int port, String host) throws InterruptedException {  

            this.port = port;  

            this.host = host;  

            start();  

        }  

        private void start() throws InterruptedException {  

            EventLoopGroup eventLoopGroup=new NioEventLoopGroup();  

            Bootstrap bootstrap=new Bootstrap();  

            bootstrap.channel(NioSocketChannel.class);  

            bootstrap.option(ChannelOption.SO_KEEPALIVE,true);  

            bootstrap.group(eventLoopGroup);  

            bootstrap.remoteAddress(host,port);  

            bootstrap.handler(new ChannelInitializer<SocketChannel>() {  

                @Override  

                protected void initChannel(SocketChannel socketChannel) throws Exception {  

                    socketChannel.pipeline().addLast(new IdleStateHandler(20,10,0));  

                    socketChannel.pipeline().addLast(new ObjectEncoder());  

                    socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));  

                    socketChannel.pipeline().addLast(new NettyClientHandler());  

                }  

            });  

            ChannelFuture future =bootstrap.connect(host,port).sync();  

            if (future.isSuccess()) {  

                socketChannel = (SocketChannel)future.channel();  

                System.out.println("connect server  成功---------");  

            }  

        }  

        public static void main(String[]args) throws InterruptedException, IOException {  

            Constants.setClientId("002");  

            NettyClientBootstrap bootstrap=new NettyClientBootstrap(9999,"localhost");  

      

            LoginMsg loginMsg=new LoginMsg();  

            loginMsg.setPassword("yao");  

            loginMsg.setUserName("robin");  

            bootstrap.socketChannel.writeAndFlush(loginMsg);  

    //        while (true){  

    //            TimeUnit.SECONDS.sleep(3);  

    //            AskMsg askMsg=new AskMsg();  

    //            AskParams askParams=new AskParams();  

    //            askParams.setAuth("authToken");  

    //            askMsg.setParams(askParams);  

    //            bootstrap.socketChannel.writeAndFlush(askMsg);  

    //        }  

              

            BufferedReader console = new BufferedReader(new InputStreamReader(System.in));  

            while (true) {  

                String msg = console.readLine();  

                if (msg == null) {  

                    break;  

                } else if ("bye".equals(msg.toLowerCase())) {  

                    break;  

                } else if ("ping".equals(msg.toLowerCase())) {  

                } else {  

                  AskMsg askMsg=new AskMsg();  

                  AskParams askParams=new AskParams();  

                  askParams.setAuth("authToken");  

                  askParams.setContent(msg);  

                  askMsg.setParams(askParams);  

                  bootstrap.socketChannel.writeAndFlush(askMsg);  

                }  

            }  

              

              

        }  

    }  

    13. netty客户端操作实现类
    [java] view plain copy

    package client;  

      

      

      

    import io.netty.channel.ChannelHandlerContext;  

    import io.netty.channel.SimpleChannelInboundHandler;  

    import io.netty.handler.timeout.IdleStateEvent;  

    import io.netty.util.ReferenceCountUtil;  

      

    import java.util.Date;  

      

    import server.NettyChannelMap;  

    import base.AskMsg;  

    import base.BaseMsg;  

    import base.LoginMsg;  

    import base.MsgType;  

    import base.PingMsg;  

    import base.ReplyClientBody;  

    import base.ReplyMsg;  

    import base.ReplyServerBody;  

      

    /** 

     *   

     */  

    public class NettyClientHandler extends SimpleChannelInboundHandler<BaseMsg> {  

      

        private int UNCONNECT_NUM = 0;  

          

        @Override  

        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  

            if (evt instanceof IdleStateEvent) {  

                if(UNCONNECT_NUM >= 4) {  

                    System.err.println("connect status is disconnect.");  

                    ctx.close();  

                    //此处当重启次数达到4次之后,关闭此链接后,并重新请求进行一次登录请求  

                    return;  

                }  

                  

                IdleStateEvent e = (IdleStateEvent) evt;  

                switch (e.state()) {  

                    case WRITER_IDLE:  

                        System.out.println("send ping to server---date=" + new Date());  

                        PingMsg pingMsg=new PingMsg();  

                        ctx.writeAndFlush(pingMsg);  

                        UNCONNECT_NUM++;  

                        System.err.println("writer_idle over. and UNCONNECT_NUM=" + UNCONNECT_NUM);  

                        break;  

                    case READER_IDLE:    

                        System.err.println("reader_idle over.");  

                        UNCONNECT_NUM++;  

                        //读取服务端消息超时时,直接断开该链接,并重新登录请求,建立通道  

                    case ALL_IDLE:  

                        System.err.println("all_idle over.");  

                        UNCONNECT_NUM++;  

                        //读取服务端消息超时时,直接断开该链接,并重新登录请求,建立通道  

                    default:  

                        break;  

                }  

            }  

        }  

          

        @Override  

        protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {  

            MsgType msgType=baseMsg.getType();  

            switch (msgType){  

                case LOGIN:{  

                    //向服务器发起登录  

                    LoginMsg loginMsg=new LoginMsg();  

                    loginMsg.setPassword("alan");  

                    loginMsg.setUserName("lin");  

                    channelHandlerContext.writeAndFlush(loginMsg);  

                }break;  

                case PING:{  

                    System.out.println("receive server ping ---date=" + new Date());  

                    ReplyMsg replyPing=new ReplyMsg();  

                    ReplyClientBody body = new ReplyClientBody("send client msg.");  

                    replyPing.setBody(body);  

                    channelHandlerContext.writeAndFlush(replyPing);  

                }break;  

                case ASK:{  

                    AskMsg askMsg=(AskMsg)baseMsg;  

                    ReplyClientBody replyClientBody=new ReplyClientBody("receive server askmsg:" + askMsg.getParams().getContent());  

                    ReplyMsg replyMsg=new ReplyMsg();  

                    replyMsg.setBody(replyClientBody);  

                    channelHandlerContext.writeAndFlush(replyMsg);  

                }break;  

                case REPLY:{  

                    ReplyMsg replyMsg=(ReplyMsg)baseMsg;  

                    ReplyServerBody replyServerBody=(ReplyServerBody)replyMsg.getBody();  

                    UNCONNECT_NUM = 0;  

                    System.out.println("UNCONNECT_NUM="+ UNCONNECT_NUM + ",receive server replymsg: "+replyServerBody.getServerInfo());  

                }  

                default:break;  

            }  

            ReferenceCountUtil.release(msgType);  

        }  

          

        @Override  

        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  

              

            System.err.println("in client exceptionCaught.");  

            super.exceptionCaught(ctx, cause);  

            //出现异常时,可以发送或者记录相关日志信息,之后,直接断开该链接,并重新登录请求,建立通道  

      

        }  

          

    }  

    14. 
    [java] view plain copy

    package server;  

      

    import io.netty.channel.Channel;  

    import io.netty.channel.socket.SocketChannel;  

      

    import java.util.Map;  

    import java.util.concurrent.ConcurrentHashMap;  

      

    /** 

     *   

     */  

    public class NettyChannelMap {  

        private static Map<String,SocketChannel> map=new ConcurrentHashMap<String, SocketChannel>();  

        public static void add(String clientId,SocketChannel socketChannel){  

            map.put(clientId,socketChannel);  

        }  

        public static Channel get(String clientId){  

           return map.get(clientId);  

        }  

        public static void remove(SocketChannel socketChannel){  

            for (Map.Entry entry:map.entrySet()){  

                if (entry.getValue()==socketChannel){  

                    map.remove(entry.getKey());  

                }  

            }  

        }  

      

    }  

    15.  netty服务端启动类
    [java] view plain copy

    package server;  

      

    import io.netty.bootstrap.ServerBootstrap;  

    import io.netty.channel.ChannelFuture;  

    import io.netty.channel.ChannelInitializer;  

    import io.netty.channel.ChannelOption;  

    import io.netty.channel.ChannelPipeline;  

    import io.netty.channel.EventLoopGroup;  

    import io.netty.channel.nio.NioEventLoopGroup;  

    import io.netty.channel.socket.SocketChannel;  

    import io.netty.channel.socket.nio.NioServerSocketChannel;  

    import io.netty.handler.codec.serialization.ClassResolvers;  

    import io.netty.handler.codec.serialization.ObjectDecoder;  

    import io.netty.handler.codec.serialization.ObjectEncoder;  

    import io.netty.handler.timeout.IdleStateHandler;  

      

    import java.util.concurrent.TimeUnit;  

      

    import base.AskMsg;  

      

    /** 

     *   

     */  

    public class NettyServerBootstrap {  

        private int port;  

        private SocketChannel socketChannel;  

        public NettyServerBootstrap(int port) throws InterruptedException {  

            this.port = port;  

            bind();  

        }  

      

        private void bind() throws InterruptedException {  

            EventLoopGroup boss=new NioEventLoopGroup();  

            EventLoopGroup worker=new NioEventLoopGroup();  

            ServerBootstrap bootstrap=new ServerBootstrap();  

            bootstrap.group(boss,worker);  

            bootstrap.channel(NioServerSocketChannel.class);  

            bootstrap.option(ChannelOption.SO_BACKLOG, 128);  

            bootstrap.option(ChannelOption.TCP_NODELAY, true);  

            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);  

            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {  

                @Override  

                protected void initChannel(SocketChannel socketChannel) throws Exception {  

                    ChannelPipeline p = socketChannel.pipeline();  

                  p.addLast(new IdleStateHandler(10,5,0));  

                    p.addLast(new ObjectEncoder());  

                    p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));  

                    p.addLast(new NettyServerHandler());  

                }  

            });  

            ChannelFuture f= bootstrap.bind(port).sync();  

            if(f.isSuccess()){  

                System.out.println("server start---------------");  

            }  

        }  

        public static void main(String []args) throws InterruptedException {  

            NettyServerBootstrap bootstrap=new NettyServerBootstrap(9999);  

            while (true){  

    //            SocketChannel channel=(SocketChannel)NettyChannelMap.get("001");  

    //            if(channel!=null){  

    //                AskMsg askMsg=new AskMsg();  

    //                channel.writeAndFlush(askMsg);  

    //            }  

                TimeUnit.SECONDS.sleep(10);  

            }  

        }  

    }  

    16. netty服务端操作实现类
    [java] view plain copy

    package server;  

      

    import java.util.Date;  

      

    import io.netty.channel.ChannelHandlerContext;  

    import io.netty.channel.SimpleChannelInboundHandler;  

    import io.netty.channel.socket.SocketChannel;  

    import io.netty.handler.timeout.IdleStateEvent;  

    import io.netty.util.ReferenceCountUtil;  

    import base.AskMsg;  

    import base.BaseMsg;  

    import base.LoginMsg;  

    import base.MsgType;  

    import base.PingMsg;  

    import base.ReplyBody;  

    import base.ReplyClientBody;  

    import base.ReplyMsg;  

    import base.ReplyServerBody;  

      

    /** 

     *   

     */  

    public class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg> {  

        

         private int UNCONNECT_NUM_S = 0;  

          

         @Override  

            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  

                if (evt instanceof IdleStateEvent) {  

                    if(UNCONNECT_NUM_S >= 4) {  

                        System.err.println("client connect status is disconnect.");  

                        ctx.close();  

                        //此处当重启次数达到4次之后,关闭此链接后,清除服务端相关的记录信息  

                        return;  

                    }  

                      

                    IdleStateEvent e = (IdleStateEvent) evt;  

                    switch (e.state()) {  

                        case WRITER_IDLE:  

                            System.out.println("send ping to client---date=" + new Date());  

                            PingMsg pingMsg=new PingMsg();  

                            ctx.writeAndFlush(pingMsg);  

                            UNCONNECT_NUM_S++;  

                            System.err.println("writer_idle over. and UNCONNECT_NUM_S=" + UNCONNECT_NUM_S);  

                            break;  

                        case READER_IDLE:    

                            System.err.println("reader_idle over.");  

                            UNCONNECT_NUM_S++;  

                            //读取服务端消息超时时,直接断开该链接,并重新登录请求,建立通道  

                        case ALL_IDLE:  

                            System.err.println("all_idle over.");  

                            UNCONNECT_NUM_S++;  

                            //读取服务端消息超时时,直接断开该链接,并重新登录请求,建立通道  

                        default:  

                            break;  

                    }  

                }  

            }  

          

          

        @Override  

        public void channelInactive(ChannelHandlerContext ctx) throws Exception {  

            System.err.println("in channelInactive.");  

            NettyChannelMap.remove((SocketChannel)ctx.channel());  

        }  

          

          

        @Override  

        protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {  

      

            if(MsgType.LOGIN.equals(baseMsg.getType())){  

                LoginMsg loginMsg=(LoginMsg)baseMsg;  

                if("lin".equals(loginMsg.getUserName())&&"alan".equals(loginMsg.getPassword())){  

                    //登录成功,把channel存到服务端的map中  

                    NettyChannelMap.add(loginMsg.getClientId(),(SocketChannel)channelHandlerContext.channel());  

                    System.out.println("client"+loginMsg.getClientId()+" 登录成功");  

                }  

            }else{  

                if(NettyChannelMap.get(baseMsg.getClientId())==null){  

                        //说明未登录,或者连接断了,服务器向客户端发起登录请求,让客户端重新登录  

                        LoginMsg loginMsg=new LoginMsg();  

                        channelHandlerContext.channel().writeAndFlush(loginMsg);  

                }  

            }  

            switch (baseMsg.getType()){  

                case PING:{  

                      PingMsg pingMsg=(PingMsg)baseMsg;  

                      ReplyMsg replyPing=new ReplyMsg();  

                      ReplyServerBody body = new ReplyServerBody("send server msg.");  

                      replyPing.setBody(body);  

                      NettyChannelMap.get(pingMsg.getClientId()).writeAndFlush(replyPing);  

                      System.err.println("ping over.");  

                }break;  

                case ASK:{  

                    //收到客户端的请求  

                    AskMsg askMsg=(AskMsg)baseMsg;  

                    if("authToken".equals(askMsg.getParams().getAuth())){  

                        ReplyServerBody replyBody=new ReplyServerBody("receive client askmsg:" + askMsg.getParams().getContent());  

                        ReplyMsg replyMsg=new ReplyMsg();  

                        replyMsg.setBody(replyBody);  

                        NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);  

                    }  

                }break;  

                case REPLY:{  

                    //收到客户端回复  

                    ReplyMsg replyMsg=(ReplyMsg)baseMsg;  

                    ReplyClientBody clientBody=(ReplyClientBody)replyMsg.getBody();  

                    UNCONNECT_NUM_S = 0;  

                    System.out.println("UNCONNECT_NUM_S=" + UNCONNECT_NUM_S +",receive client replymsg: "+clientBody.getClientInfo());  

                }break;  

                default:break;  

            }  

            ReferenceCountUtil.release(baseMsg);  

        }  

          

          

        @Override  

        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  

              

            System.err.println("in here has an error.");  

            NettyChannelMap.remove((SocketChannel)ctx.channel());  

            super.exceptionCaught(ctx, cause);  

            System.err.println("channel is exception over. (SocketChannel)ctx.channel()=" + (SocketChannel)ctx.channel());  

        }  

    展开全文
  •  //该m_pSimpleHttp维持 http长连接  //普通http请求的使用,非长连接  //NetworkCommunicate类中, m_pGetMsgHttp = new SimpleHttp(HTTP_POST,this);    //不管是长连接的http实例,还是非长连接...

    长连接: 指在一个TCP连接上可以连续发送多个数据包,
            在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接;
            一般需要自己做在线维持。




                //http长连接的使用
                //m_pSimpleHttp =  new SimpleHttp(HTTP_KEEPALIVE,this);//长连接类型 的http请求------------------- NetWorkCommunication中创建一个SimpleHttp的实例
                //该m_pSimpleHttp维持 http长连接

                //普通http请求的使用,非长连接
                //NetworkCommunicate类中, m_pGetMsgHttp =  new SimpleHttp(HTTP_POST,this);
                
                //不管是长连接的http实例,还是非长连接的http实例,都是在NetWorkCommunication的析构函数中才会析构掉
                
                
                //长连接和其他链接,没什么区别,长连接是个httpManager对象,该对象和服务器进行链接,
                //服务器每隔15秒就向 该http链接中发送一个数据(心跳包), 客户端如果45s后,还没有收到 服务端发送过来的心跳包,那么客户端就主动关闭该http链接,
                //非长连接,45s后,直接关闭掉该http连接,
                

                enum HTTP_MODE
                {
                    HTTP_GET = 0,
                    HTTP_POST,
                    HTTP_DOWNLOADFILE,
                    HTTP_UPLOADFILE,
                    HTTP_KEEPALIVE
                };//http请求的类型 get post downloadfile uploadfile等
                
                SimpleHttp* HttpRequestManage::addKeepAlivePost(TASK_PARAM * pTask)
                {
                    KeepAliveTask* pKeepAliveTask = dynamic_cast<KeepAliveTask*>(pTask);
                    if(!pKeepAliveTask)
                        return NULL;

                    SimpleHttp* pHttp = new SimpleHttp(HTTP_KEEPALIVE, this);//标识 该请求为长连接请求---------------------
                    pHttp->setOutTimer(pKeepAliveTask->m_OutTimer);
                    pHttp->setPostRequestParam(pKeepAliveTask->m_strParam);
                    pHttp->setRecvMsgFunc(pKeepAliveTask->m_RecvMsgFunc);
                    pHttp->SetAtOnce(pKeepAliveTask->m_bAtOnce);
                    pHttp->httpRequest(pKeepAliveTask->m_strUrl, pKeepAliveTask->m_CompleteFunc);

                    return pHttp;
                }
                
                //开始做任务 执行http请求
                void SimpleHttp::startRequest()
                
                    case HTTP_KEEPALIVE:
                    {
                        connect(m_spHttp.data(), SIGNAL(finished(QNetworkReply*)), this, SLOT(httpFinished(QNetworkReply*)));
                        QNetworkRequest request(m_Url);
                        QByteArray param;
                        if(m_PostParam.isEmpty())
                            param = m_Url.encodedQuery();
                        else
                            param.append(m_PostParam);

                        if(!m_Headers.isEmpty())
                        {
                            for(int i=0; i<m_Headers.size(); ++i)
                            {
                                QPair<QNetworkRequest::KnownHeaders, QVariant> pair = m_Headers[i];
                                request.setHeader(pair.first, pair.second);
                            }
                        }
                        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
                        m_NetworkReply = m_spHttp->post(request, param);
                        connect(m_NetworkReply, SIGNAL(readyRead()), this, SLOT(OnRecvMsg()));//http请求 已经返回数据了------------------ 对获取到的长连接请求的返回数据进行处理
                        connect(m_NetworkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(httpError(QNetworkReply::NetworkError)));
                    }
                    if(m_OutTime < 0 && m_Mode == HTTP_KEEPALIVE )
                    {
                        m_OutTime = HEARTBEAT_TIME;        //这个超时来处理心跳包
                        if(!m_AutoBreakOutTimer)
                        {
                            m_AutoBreakOutTimer = new QTimer(this);
                            connect(m_AutoBreakOutTimer, SIGNAL(timeout ()), this, SLOT(OnAutoBreakOutTimer()));
                        }
                        else
                        {
                            m_AutoBreakOutTimer->stop();
                        }

                        m_AutoBreakOutTimer->start(AUTO_BREAK_TIME);  //长连接使用
                    }

                    m_OutTimer->start(m_OutTime);
                    
                    
                

                //定时器的超时响应函数            
                /*
                服务端每隔15秒发一次心跳包
                //长连接请求发出后,该定时器设定为45秒后触发
                //下面槽的作用,就是为了检测m_bRecvHeartbeat的值,即客户端是否收到了服务端发过来的心跳包
                */
                void SimpleHttp::OnOutTimer()
                {
                    //定时器超时了
                    m_bOutTime = true;
                    if(m_Mode != HTTP_KEEPALIVE)
                    {

                        m_OutTimer->stop();


                        m_NetworkReply->close();    //非长连接 ,手动将该链接关闭,以免占用服务端的资源-------------------------------------长连接和短链接的根本的区别
                    }
                    else
                    {
                        //http是长连接
                        //开始检查心跳包
                        // 因为服务器每隔15s就发送一次心跳包
                        //如果45s还没有收到心跳包,那么说明连接中断了,
                        if(!m_bRecvHeartbeat)  //心跳包停止了
                        {
                            m_OutTimer->stop();
                            m_AutoBreakOutTimer->stop();
                        
                            m_NetworkReply->close();//没有收到心跳包,关闭http连接     //-------------------------------------长连接和短链接的根本的区别
                        }
                        else
                        {
                            //接收到了服务端发过来的心跳包,那么不关闭http连接
                            m_bRecvHeartbeat = false;
                        }
                    }
                }

                
                    
                    

    //第一步
    //网络连接 NetrokCommunicate类,使用的就是http长连接。
    //只使用了这一中连接http连接方式。
                NetworkCommunicate::NetworkCommunicate(QObject *parent)
                    : QObject(parent)
                    , m_pSimpleHttp(NULL)
                    , m_pGetMsgHttp(NULL)
                    , m_Timer(NULL)
                    , m_nRequestNum(0)
                    , m_bPullMsg(true)
                    , m_nRetryTimes(0)
                {
                        m_pSimpleHttp =  new SimpleHttp(HTTP_KEEPALIVE,this);//长连接类型 的http请求-------------
                        
                    

    展开全文
  • nginx跟grpc长连接相关配置,发现在1.15.6版本引入了"grpc_socket_keepalive"跟grpc直接相关长连接配置 Configures the “TCP keepalive” behavior for outgoing connections to a gRPC server. By default, the...
  • 今天,我将手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 1. 长连接 介绍 http的长连接和短连接(史上最通俗!) 2. 长连接断开的原因 从上节可知,在长连接的情况下,双方的所有通信 都建立...
  • 今天,我将手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 目录 示意图 1. 长连接 介绍 1.1 简介 示意图 1.2 作用 通过长时间保持双方连接,从而: 提高通信速度 确保实时性 避免短时间...
  • 今天,我将手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 目录 示意图 1. 长连接 介绍 1.1 简介 示意图 1.2 作用 通过长时间保持双方连接,从而: 提高通信速度 确保实时性 避免短时间...
  • socket长连接维持

    2017-04-28 10:27:00
    长连接维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。如果,长时间未发送维持连接包,服务端程序将断开连接。 客户端:通过持有Client对象,可以随时(使用sendObject方法)发送Object给服务端...
  • socket长连接维持 .

    2017-08-07 13:21:05
    长连接维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。 如果,长时间未发送维持连接包,服务端程序将断开连接。 客户端: 通过持有Client对象,可以随时(使用sendObject方法)发送Object给...
  • socket长连接可以维持多长时间,在客户端和服务器都不主动关闭socket的情况下,普通的中国移动和中国联通sim卡,运营商会多长时间释放掉socket,如果是运营商把socket关掉了,客户端和服务端都能收到通知吗?
  • 问题1:当守护进程运行的时候,因工作任务量大,计算运行耗时,但mysql有最大连接时间,超过这个时间后mysql数据库就自动断连,怎么维持数据库的链接呢? 解决办法:在每一次sql语句执行之前先判定当前数据库连接...
  • python使用paramiko模块对多台服务器进行ssh连接,要用交互式的invoke_shell()执行服务器命令,现在使用的是cgi方式,每次调用都要新建...请问想要初始化python程序后一直维持ssh连接随用随取的话什么方法可以实现?
  • 今天,我将 手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接 目录 1. 长连接 介绍 1.1 简介 1.2 作用 通过 长时间保持双方连接,从而: 提高通信速度 确保实时性 避免短时间内...
  • nginx设置响应连接是长连接或者短连接 ... nginx反向代理时保持长连接 ... ...用nginx做grpc反向代理,nginx到后端server不能维持长连接问题 https://juejin.im/post/6844903809534148622 ...
  • 什么是长连接?其实长连接是相对于通常的短...这就要求长连接在没有数据通信时,定时发送数据包,以维持连接状态,短连接在没有数据传输时直接关闭就行了什么时候用长连接,短连接?长连接主要用于在少数客户端与服...
  • 长连接-心跳保活机制

    千次阅读 2018-03-21 17:24:55
    前言当实现具备实时性需求时,我们一般会选择长连接的通信方式而在实现长连接方式时,存在很多性能问题,如 长连接保活今天,我将 手把手教大家实现自适应的心跳保活机制,从而能高效维持长连接目录1. 长连接 介绍...
  • 在 Java Servlet 中可以通过多种途径来实现会话: like: Cookies HttpSession API URL rewriting etc. Cookies 和 HttpSession API可以单独使用
  • TCP长连接与NAT超时

    2021-02-06 13:07:25
    TCP是有保活定时器的,可以打开保活定时器来维持长连接,设置SO_KEEPALIVE才会开启,时间间隔默认7200s,也就是2h,这个默认是关闭的。 HTTP中的keep-alive和TCP中的keepalive的原理不一样 NAT超时 因为 IP v4 的 ...
  • O、长连接与短链接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个...维持长连接耗资源,所以用户量多了很可能把服务器资源耗尽,所...
  • HTTP的长连接与短连接

    2013-12-04 14:50:21
    其他的Web资源,如JavaScript文件、图像文件、CSS文件等;...   如果浏览器或者服务器在其头信息加入了这行代码...在header中加入 --Connection:keep-alive 在HTTp协议请求和响应中加入这条就能维持长连接。   实现
  • 长连接与短连接含义

    千次阅读 2020-08-27 21:44:21
    所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持。 短连接是指通信双方有数据交互时,就建立一个TCP连接,...
  • 什么是长连接?其实长连接是相对于通常的短...这就要求长连接在没有数据通信时,定时发送数据包,以维持连接状态,短连接在没有数据传输时直接关闭就行了什么时候用长连接,短连接?长连接主要用于在少数客户端与服...
  • 什么是长连接?其实长连接是相对于通常的短...这就要求长连接在没有数据通信时,定时发送数据包,以维持连接状态,短连接在没有数据传输时直接关闭就行了什么时候用长连接,短连接?长连接主要用于在少数客户端与服...
  • 解决peewee的MySQL长连接问题

    千次阅读 2019-09-05 17:26:09
    在peewee中如何维持长连接呢? 解决方法比较晦涩,需要自定义一个支持重试的类,然后自定义一种RetryMySQLDatabase混入类 from peewee import * from peewee import __exception_wrapper__ class ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 807
精华内容 322
关键字:

维持长连接