Netty为基础的Socket长连接高并发服务器微家开发之路(2)--第一版简略服务器编码

  • 作者
  • KING

事隔上一篇《前言》发表在微家上已经有了近一周了,看来本人还是惰性太大,这么久了,才来开始写第二篇。其实这篇代码是在22号左右就已经提交到GIT上面去了。(所有源码都可以在GIT上看到),当然其中,也有很大部分时间,是在构思应该怎么来写本文章乃到怎么写本系列的文章。因为,代码太少了,好像文章也不用怎么写,看代码基本就可以,但如果不写,等到下次一起写,好像又跨度太大了。想来想去,还是把一些重点代码贴过来,然后做以简单的说明。我相信这样,对我代码的演变过程,是一个更好的总结与思考。

此类文章本人将会按一个系列的形式进行书写。该系列文章,主要记录从零开始,利用Netty搭建一个TCP的Socket长连接服务器项目的过程。本系列文章原始出处微家(www.wejias.com),转载请注明出处。

  • POM引用NETTY

       本人在开发时NETTY5仍然只有两个alpha版本,为了安全起见,本人决定用4.0的最新版本4.0.56

       <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.0.56.Final</version>
      </dependency>
  • 引入slf4j和logback

      <dependency>        
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
      </dependency>
            
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.7</version>
      </dependency>
            
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
      </dependency>

做初用maven的来说,做下面两点入门级的备注事项:

备注1:maven原始远程中央库(即下载JAR包的地址),是在国外,所以我朝程序猿并不友好,所以需要对其修改,指向国内的镜像,如下:

        以指向阿里镜向为例,
        1.找到本地库(存JAR的目录)或者全局(MAVEN安装目录/conf/)的setting.xml
        在mirrors节点下,添加如下内容:
        <mirror>
            <id>nexus-aliyun</id>
            <mirrorOf>central</mirrorOf>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
	    </mirror>

备注2:对于初用maven的人来说,有一个困惑,我这些maven地址,上哪里去找呢?有些jar官方地址还特别不好找.

          所以分享一个查询网址:http://mvnrepository.com/


重点代码部分:

NettyServer
public class NettyServer {
        private EventLoopGroup      bossGroup   = null;
        private EventLoopGroup      workerGroup = null;
        private ServerBootstrap      bootStrap   = null;
        
        public void  launch(int serverPort){
            String osName = System.getProperty("os.name");
            this.initThreadGroup(osName);
            
            bootStrap = new ServerBootstrap();
            bootStrap.group(bossGroup, workerGroup);
            this.initServerChannel(osName);
            
            bootStrap.childOption(ChannelOption.TCP_NODELAY, true);
            bootStrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            bootStrap.childOption(ChannelOption.SO_REUSEADDR, true);
            
            bootStrap.childHandler(new ServerChannel());
            ChannelFuture future = bootStrap.bind(serverPort);
        }
        
         private void initThreadGroup(String osName){
                    if(osName.trim().equals("Linux")){
                        this.bossGroup = new EpollEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_CORE_THREAD_NUM);
                        this.workerGroup = new EpollEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_WORK_THREAD_NUM);
                    }else{
                        this.bossGroup = new NioEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_CORE_THREAD_NUM);
                        this.workerGroup = new NioEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_WORK_THREAD_NUM);
                    }
                }
    
                private void initServerChannel(String osName){
                    if(osName.trim().equals("Linux")){
                        this.bootStrap.channel(EpollServerSocketChannel.class);
                    }else{
                        this.bootStrap.channel(NioServerSocketChannel.class);
                    }
                }
}

以上Server启动的需要调用的初始化方向的接口.其中几个线程组,可以根据系统选不同的IO方式进行构造,以确保其中当前系统最优的方案.其中可以大部分朋友可能对这个String osName = System.getProperty("os.name")取出值比较担心,不知道是些什么值.此处贴一下百度出来的,较为清晰的答案:

os.nameos.versionos.archComments
Linux2.0.31x86IBM Java 1.3
Linux(*)i386Sun Java 1.3.1, 1.4 or Blackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)x86_64Blackdown Java; note x86_64 might change to amd64; (*) os.version depends on Linux Kernel version
Linux(*)sparcBlackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)ppcBlackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)armv41Blackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)i686GNU Java Compiler (GCJ); (*) os.version depends on Linux Kernel version
Linux(*)ppc64IBM Java 1.3; (*) os.version depends on Linux Kernel version
Mac OS7.5.1PowerPC
Mac OS8.1PowerPC
Mac OS9.0, 9.2.2PowerPCMacOS 9.0: java.version=1.1.8, mrj.version=2.2.5; MacOS 9.2.2: java.version=1.1.8 mrj.version=2.2.5
Mac OS X10.1.3ppc
Mac OS X10.2.6ppcJava(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-39)
Java HotSpot(TM) Client VM (build 1.4.1_01-14, mixed mode)
Mac OS X10.2.8ppcusing 1.3 JVM: java.vm.version=1.3.1_03-74, mrj.version=3.3.2; using 1.4 JVM: java.vm.version=1.4.1_01-24, mrj.version=69.1
Mac OS X10.3.1, 10.3.2, 10.3.3, 10.3.4ppcJDK 1.4.x
Mac OS X10.3.8ppcMac OS X 10.3.8 Server; using 1.3 JVM: java.vm.version=1.3.1_03-76, mrj.version=3.3.3; using 1.4 JVM: java.vm.version=1.4.2-38; mrj.version=141.3
Windows 954.0x86
Windows 984.10x86Note, that if you run Sun JDK 1.2.1 or 1.2.2 Windows 98 identifies itself as Windows 95.
Windows Me4.90x86
Windows NT4.0x86
Windows 20005.0x86
Windows XP5.1x86Note, that if you run older Java runtimes Windows XP identifies itself as Windows 2000.
Windows 20035.2x86java.vm.version=1.4.2_06-b03; Note, that Windows Server 2003 identifies itself only as Windows 2003.
Windows CE3.0 build 11171armCompaq iPAQ 3950 (PocketPC 2002)
OS/220.40x86
Solaris2.xsparc
SunOS5.7sparcSun Ultra 5 running Solaris 2.7
SunOS5.8sparcSun Ultra 2 running Solaris 8
SunOS5.9sparcJava(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
MPE/iXC.55.00PA-RISC
HP-UXB.10.20PA-RISCJDK 1.1.x
HP-UXB.11.00PA-RISCJDK 1.1.x
HP-UXB.11.11PA-RISCJDK 1.1.x
HP-UXB.11.11PA_RISCJDK 1.2.x/1.3.x; note Java 2 returns PA_RISC and Java 1 returns PA-RISC
HP-UXB.11.00PA_RISCJDK 1.2.x/1.3.x
HP-UXB.11.23IA64NJDK 1.4.x
HP-UXB.11.11PA_RISC2.0JDK 1.3.x or JDK 1.4.x, when run on a PA-RISC 2.0 system
HP-UXB.11.11PA_RISCJDK 1.2.x, even when run on a PA-RISC 2.0 system
HP-UXB.11.11PA-RISCJDK 1.1.x, even when run on a PA-RISC 2.0 system
AIX5.2ppc64sun.arch.data.model=64
AIX4.3Power
AIX4.1POWER_RS
OS/39039002.10.00J2RE 1.3.1 IBM OS/390 Persistent Reusable VM
FreeBSD2.2.2-RELEASEx86
Irix6.3mips
Digital Unix4.0alpha
NetWare 4.114.11x86
OSF1V5.1alphaJava 1.3.1 on Compaq (now HP) Tru64 Unix V5.1
OpenVMSV7.2-1alphaJava 1.3.1_1 on OpenVMS 7.2

其它代码主要是ServerChannel和ServerIoHandler类,但是本版本这两个类的代码都比较简单,以上代码片段主要是本人认为,需要特别说明的地方。更全的代码可在Github上查看。

本项目,主要采用以上开源框架技术。另外再从设置上或者代码上,进行优化。最终期望,本项目成为一个高负载,高并发的TCP服务器。本系列文章主要记录本项目开发的过程,以及过程中遇到的问题。记录其的主要目的,是想让自己能够在开发之后,更系统,全面且静下心来梳理相关知识点。与此同时,提高自己,也希望对其它准备相关项目的小伙伴,起到抛砖引玉的作用。当然,只要是代码就会BUG,如果看过文章,你发现有什么不对或者不合理地方,非常欢迎和谢谢指正。

当然最好最直接的方式,是通过页面底的众多联系方式找到我,和我直接开聊讨论。

具体的联系有QQ号:2091263530,QQ群:688543468

或者关注我们公众号”微家频道“,或者微博”微家频道“。

Netty为基础的Socket长连接高并发服务器微家开发之路(2)--第一版简略服务器编码

事隔上一篇《前言》发表在微家上已经有了近一周了,看来本人还是惰性太大,这么久了,才来开始写第二篇。其实这篇代码是在22号左右就已经提交到GIT上面去了。(所有源码都可以在GIT上看到),当然其中,也有很大部分时间,是在构思应该怎么来写本文章乃到怎么写本系列的文章。因为,代码太少了,好像文章也不用怎么写,看代码基本就可以,但如果不写,等到下次一起写,好像又跨度太大了。想来想去,还是把一些重点代码贴过来,然后做以简单的说明。我相信这样,对我代码的演变过程,是一个更好的总结与思考。

此类文章本人将会按一个系列的形式进行书写。该系列文章,主要记录从零开始,利用Netty搭建一个TCP的Socket长连接服务器项目的过程。本系列文章原始出处微家(www.wejias.com),转载请注明出处。

  • POM引用NETTY

       本人在开发时NETTY5仍然只有两个alpha版本,为了安全起见,本人决定用4.0的最新版本4.0.56

       <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.0.56.Final</version>
      </dependency>
  • 引入slf4j和logback

      <dependency>        
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
      </dependency>
            
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.7</version>
      </dependency>
            
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
      </dependency>

做初用maven的来说,做下面两点入门级的备注事项:

备注1:maven原始远程中央库(即下载JAR包的地址),是在国外,所以我朝程序猿并不友好,所以需要对其修改,指向国内的镜像,如下:

        以指向阿里镜向为例,
        1.找到本地库(存JAR的目录)或者全局(MAVEN安装目录/conf/)的setting.xml
        在mirrors节点下,添加如下内容:
        <mirror>
            <id>nexus-aliyun</id>
            <mirrorOf>central</mirrorOf>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
	    </mirror>

备注2:对于初用maven的人来说,有一个困惑,我这些maven地址,上哪里去找呢?有些jar官方地址还特别不好找.

          所以分享一个查询网址:http://mvnrepository.com/


重点代码部分:

NettyServer
public class NettyServer {
        private EventLoopGroup      bossGroup   = null;
        private EventLoopGroup      workerGroup = null;
        private ServerBootstrap      bootStrap   = null;
        
        public void  launch(int serverPort){
            String osName = System.getProperty("os.name");
            this.initThreadGroup(osName);
            
            bootStrap = new ServerBootstrap();
            bootStrap.group(bossGroup, workerGroup);
            this.initServerChannel(osName);
            
            bootStrap.childOption(ChannelOption.TCP_NODELAY, true);
            bootStrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            bootStrap.childOption(ChannelOption.SO_REUSEADDR, true);
            
            bootStrap.childHandler(new ServerChannel());
            ChannelFuture future = bootStrap.bind(serverPort);
        }
        
         private void initThreadGroup(String osName){
                    if(osName.trim().equals("Linux")){
                        this.bossGroup = new EpollEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_CORE_THREAD_NUM);
                        this.workerGroup = new EpollEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_WORK_THREAD_NUM);
                    }else{
                        this.bossGroup = new NioEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_CORE_THREAD_NUM);
                        this.workerGroup = new NioEventLoopGroup(ServerCoreInfo.DEFAULT_NETTY_WORK_THREAD_NUM);
                    }
                }
    
                private void initServerChannel(String osName){
                    if(osName.trim().equals("Linux")){
                        this.bootStrap.channel(EpollServerSocketChannel.class);
                    }else{
                        this.bootStrap.channel(NioServerSocketChannel.class);
                    }
                }
}

以上Server启动的需要调用的初始化方向的接口.其中几个线程组,可以根据系统选不同的IO方式进行构造,以确保其中当前系统最优的方案.其中可以大部分朋友可能对这个String osName = System.getProperty("os.name")取出值比较担心,不知道是些什么值.此处贴一下百度出来的,较为清晰的答案:

os.nameos.versionos.archComments
Linux2.0.31x86IBM Java 1.3
Linux(*)i386Sun Java 1.3.1, 1.4 or Blackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)x86_64Blackdown Java; note x86_64 might change to amd64; (*) os.version depends on Linux Kernel version
Linux(*)sparcBlackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)ppcBlackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)armv41Blackdown Java; (*) os.version depends on Linux Kernel version
Linux(*)i686GNU Java Compiler (GCJ); (*) os.version depends on Linux Kernel version
Linux(*)ppc64IBM Java 1.3; (*) os.version depends on Linux Kernel version
Mac OS7.5.1PowerPC
Mac OS8.1PowerPC
Mac OS9.0, 9.2.2PowerPCMacOS 9.0: java.version=1.1.8, mrj.version=2.2.5; MacOS 9.2.2: java.version=1.1.8 mrj.version=2.2.5
Mac OS X10.1.3ppc
Mac OS X10.2.6ppcJava(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-39)
Java HotSpot(TM) Client VM (build 1.4.1_01-14, mixed mode)
Mac OS X10.2.8ppcusing 1.3 JVM: java.vm.version=1.3.1_03-74, mrj.version=3.3.2; using 1.4 JVM: java.vm.version=1.4.1_01-24, mrj.version=69.1
Mac OS X10.3.1, 10.3.2, 10.3.3, 10.3.4ppcJDK 1.4.x
Mac OS X10.3.8ppcMac OS X 10.3.8 Server; using 1.3 JVM: java.vm.version=1.3.1_03-76, mrj.version=3.3.3; using 1.4 JVM: java.vm.version=1.4.2-38; mrj.version=141.3
Windows 954.0x86
Windows 984.10x86Note, that if you run Sun JDK 1.2.1 or 1.2.2 Windows 98 identifies itself as Windows 95.
Windows Me4.90x86
Windows NT4.0x86
Windows 20005.0x86
Windows XP5.1x86Note, that if you run older Java runtimes Windows XP identifies itself as Windows 2000.
Windows 20035.2x86java.vm.version=1.4.2_06-b03; Note, that Windows Server 2003 identifies itself only as Windows 2003.
Windows CE3.0 build 11171armCompaq iPAQ 3950 (PocketPC 2002)
OS/220.40x86
Solaris2.xsparc
SunOS5.7sparcSun Ultra 5 running Solaris 2.7
SunOS5.8sparcSun Ultra 2 running Solaris 8
SunOS5.9sparcJava(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
MPE/iXC.55.00PA-RISC
HP-UXB.10.20PA-RISCJDK 1.1.x
HP-UXB.11.00PA-RISCJDK 1.1.x
HP-UXB.11.11PA-RISCJDK 1.1.x
HP-UXB.11.11PA_RISCJDK 1.2.x/1.3.x; note Java 2 returns PA_RISC and Java 1 returns PA-RISC
HP-UXB.11.00PA_RISCJDK 1.2.x/1.3.x
HP-UXB.11.23IA64NJDK 1.4.x
HP-UXB.11.11PA_RISC2.0JDK 1.3.x or JDK 1.4.x, when run on a PA-RISC 2.0 system
HP-UXB.11.11PA_RISCJDK 1.2.x, even when run on a PA-RISC 2.0 system
HP-UXB.11.11PA-RISCJDK 1.1.x, even when run on a PA-RISC 2.0 system
AIX5.2ppc64sun.arch.data.model=64
AIX4.3Power
AIX4.1POWER_RS
OS/39039002.10.00J2RE 1.3.1 IBM OS/390 Persistent Reusable VM
FreeBSD2.2.2-RELEASEx86
Irix6.3mips
Digital Unix4.0alpha
NetWare 4.114.11x86
OSF1V5.1alphaJava 1.3.1 on Compaq (now HP) Tru64 Unix V5.1
OpenVMSV7.2-1alphaJava 1.3.1_1 on OpenVMS 7.2

其它代码主要是ServerChannel和ServerIoHandler类,但是本版本这两个类的代码都比较简单,以上代码片段主要是本人认为,需要特别说明的地方。更全的代码可在Github上查看。

本项目,主要采用以上开源框架技术。另外再从设置上或者代码上,进行优化。最终期望,本项目成为一个高负载,高并发的TCP服务器。本系列文章主要记录本项目开发的过程,以及过程中遇到的问题。记录其的主要目的,是想让自己能够在开发之后,更系统,全面且静下心来梳理相关知识点。与此同时,提高自己,也希望对其它准备相关项目的小伙伴,起到抛砖引玉的作用。当然,只要是代码就会BUG,如果看过文章,你发现有什么不对或者不合理地方,非常欢迎和谢谢指正。

当然最好最直接的方式,是通过页面底的众多联系方式找到我,和我直接开聊讨论。

具体的联系有QQ号:2091263530,QQ群:688543468

或者关注我们公众号”微家频道“,或者微博”微家频道“。