Netty implementation of TCP long connection and heartbeat detection

Source: Internet
Author: User
Tags auth object serialization serialization

The Netty realizes long connection communication between server and client, and heartbeat detection.

Basic idea: The Netty server saves all connected client Socketchannel through a map, and the ID of the client is the key of the map. Every time the server side to send a message to a client, just according to ClientID out the corresponding Socketchannel, to write messages inside. Heartbeat detection through the Idleevent event, timed to the service side of the ping message, detection socketchannel whether the end of the break.

Environmental JDK1.8 and Netty5

The following is a detailed code implementation and introduction:

1 The Public share section (mainly contains the definition of the Message protocol type)

Design Message Type:

Public enum  Msgtype {
    ping,ask,reply,login
}

Message base class:

Must implement sequence, serialversionuid must have, no person in the Netty message serialization deserialization will be problematic, receive no message ... Public
abstract class Basemsg  implements Serializable {
    private static final long Serialversionuid = 1l;
  
   private msgtype type;
    Must be unique, no one will appear channel call Chaos
    private String clientId;
 
    Initialize Client 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;
    }
}
  

Constant settings:

public class Constants {
    private static String clientId;
    public static String Getclientid () {return
        clientId;
    }
    public static void Setclientid (String clientId) {
        constants.clientid = clientId;
    }
}

Logon Type message:

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;
    }
}

Heartbeat detection Ping Type message:

public class Pingmsg extends Basemsg {public
    pingmsg () {
        super ();
        SetType (msgtype.ping);
    }

Request Type message:

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;
    }
}
Request type parameter
//must implement serialization interface public
class Askparams implements Serializable {
    private static final long Serialversionuid = 1L;
    Private String auth;
 
    Public String GetAuth () {return
        auth;
    }
 
    public void Setauth (String auth) {
        this.auth = auth;
    }
}

Response type message:

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; }///corresponding type body pair like public class Replybody implements Serializable {private static final long serialversionuid = 1L;} p
 
    Ublic 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;
    } public class Replyserverbody extends Replybody {private String serverinfo;
    Public Replyserverbody (String serverinfo) {this.serverinfo = ServerInfo;
    Public String Getserverinfo () {return serverinfo; } publicvoid SetServerInfo (String serverinfo) {this.serverinfo = ServerInfo; }
}

2 server-side: primarily contains map,channelhandler implementations and bootstrap for Socketchannel references.

MAP:

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 ());}}}
 

Handler

public class Nettyserverhandler extends simplechannelinboundhandler<basemsg> {@Override public void Channel Inactive (Channelhandlercontext ctx) throws Exception {//channel invalid, remove Nettychannelmap.remove from map (socketc
    Hannel) Ctx.channel ()); @Override protected void messagereceived (Channelhandlercontext channelhandlercontext, basemsg basemsg) throws Ex
            ception {if (MsgType.LOGIN.equals (Basemsg.gettype ())) {loginmsg loginmsg= (loginmsg) basemsg; if ("Robin". Equals (Loginmsg.getusername ()) && "Yao". Equals (Loginmsg.getpassword ()) {//Login succeeded, put Cha 
                Nnel is saved to the server's map Nettychannelmap.add (Loginmsg.getclientid (), (Socketchannel) Channelhandlercontext.channel ());
            SYSTEM.OUT.PRINTLN ("Client" +loginmsg.getclientid () + "login Successful"); }else{if (Nettychannelmap.get (Basemsg.getclientid ()) ==null) {//description is not logged in, or the connection is broken, the server
           Client initiates login request, lets client log in again         Loginmsg loginmsg=new loginmsg ();
            Channelhandlercontext.channel (). Writeandflush (LOGINMSG);
                } switch (Basemsg.gettype ()) {case ping:{pingmsg pingmsg= (pingmsg) basemsg;
                Pingmsg replyping=new pingmsg ();
            Nettychannelmap.get (Pingmsg.getclientid ()). Writeandflush (replyping);
            }break;
                Case ask:{//request received from client askmsg askmsg= (askmsg) basemsg; if ("AuthToken". Equals (Askmsg.getparams (). GetAuth ())) {Replyserverbody replybody=new replyserverbody ("s
                    ERVER Info $ $!!! ");
                    Replymsg replymsg=new replymsg ();
                    Replymsg.setbody (Replybody);
                Nettychannelmap.get (Askmsg.getclientid ()). Writeandflush (REPLYMSG);
            }}break;
  Case reply:{//Receive client reply Replymsg replymsg= (replymsg) basemsg;              Replyclientbody clientbody= (Replyclientbody) replymsg.getbody ();
            SYSTEM.OUT.PRINTLN ("Receive client msg:" +clientbody.getclientinfo ());
            }break;
        Default:break;
    } referencecountutil.release (BASEMSG); }
}

 serverbootstrap:

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);
        Disable Nagle through Nodelay, so that the message is sent immediately, do not wait for a certain amount of data to send out to Bootstrap.option (Channeloption.tcp_nodelay, true);
        Maintain long connection state bootstrap.childoption (channeloption.so_keepalive, true); Bootstrap.childhandler (New channelinitializer<socketchannel> () {@Override protected void in Itchannel (Socketchannel socketchannel) throws Exception {ChannelpipEline p = socketchannel.pipeline ();
                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=ne
        W Nettyserverbootstrap (9999);
            while (true) {Socketchannel channel= (socketchannel) nettychannelmap.get ("001");
                if (channel!=null) {askmsg askmsg=new askmsg ();
            Channel.writeandflush (ASKMSG);
        } TimeUnit.SECONDS.sleep (5); }
    }
}

3 Client side: Includes initiating login, sending heartbeat, and corresponding message processing

Handler

public class Nettyclienthandler extends simplechannelinboundhandler<basemsg> {//Use write idle to send heartbeat detection messages @Override public void usereventtriggered (Channelhandlercontext ctx, Object evt) throws Exception {if (evt instanceof idles
            tateevent) {idlestateevent e = (idlestateevent) evt;
                    Switch (e.state ()) {case writer_idle:pingmsg pingmsg=new pingmsg ();
                    Ctx.writeandflush (PINGMSG);
                    System.out.println ("Send ping to Server----------");
                Break
            Default:break; }} @Override protected void messagereceived (Channelhandlercontext channelhandlercontext, basemsg Ba
        Semsg) throws Exception {Msgtype msgtype=basemsg.gettype ();
                Switch (msgtype) {case login:{//Login to server loginmsg loginmsg=new loginmsg (); Loginmsg.setpassword ("Yao");
                Loginmsg.setusername ("Robin");
            Channelhandlercontext.writeandflush (LOGINMSG);
            }break;
            Case ping:{System.out.println ("Receive PING from server----------");
            }break;
                Case ask:{replyclientbody replyclientbody=new replyclientbody ("Client Info * * * * *!!!");
                Replymsg replymsg=new replymsg ();
                Replymsg.setbody (Replyclientbody);
            Channelhandlercontext.writeandflush (REPLYMSG);
            }break;
                Case reply:{replymsg replymsg= (replymsg) basemsg;
                Replyserverbody replyserverbody= (Replyserverbody) replymsg.getbody ();
            SYSTEM.OUT.PRINTLN ("Receive client msg:" +replyserverbody.getserverinfo ());
        } Default:break;
    } referencecountutil.release (Msgtype); }
}

 bootstrap

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 Initcha Nnel (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 successful---------");
        } public static void Main (String[]args) throws Interruptedexception {Constants.setclientid ("001");
 
        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); }
    }
}

Specific examples and corresponding pom.xml see https://github.com/WangErXiao/ServerClient

Forwarding please indicate the source: http://my.oschina.net/robinyao/blog/399060

Summarize:

When Java implements TCP serialization and deserialization, it is best to use a JSON string to pass data. This ensures that the client deserialization succeeds. If both the client and the server are using Java implementations, it is possible to use object serialization and deserialization. If the client is implemented using a non-Java language, the Java object serialization and deserialization cannot be used. It is best to use strings to pass data. It is recommended that you use a JSON string.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.