zoukankan      html  css  js  c++  java
  • tcp并发服务器(c20w)

    ** 原创文章,请勿转载 **

    并发服务器是一个老生常谈的话题,今天这里也写一个。

    1. 目标

        同时在线连接20万(c20w)。  

        开发语言:重要的事情说三遍,GOLANG, GOLANG, GOLANG!

        那为什么是20W,不是30W或其它? 这个数字随意。   :)


    2. 环境

        虚拟机(xenserver),    虚出6台机器(OS: CentOS 6.6 64bit) :
           . 一台服务器8核CPU,2G内存
           . 五台客户端2核CPU,2G内存
          

    3.  改centos几个参数, 6台机器一样:
      
    # ulimit -a   

          看 open files
          改成300000(大于20W就行) :
       #  ulimit -n 300000

       改端口范围
      
    # echo 1025 65000 > /proc/sys/net/ipv4/ip_local_port_range

    4. golang代码

        服务端: server.go

    package main
    
    import (
        "log"
        "net"
        "sync"
        "time"
    )
    
    func main() {
        tcpAddr, err := net.ResolveTCPAddr("tcp", ":5000")
    
        if err != nil {
            log.Fatalln("net.ResolveTCPAddr fail", err)
        }
    
        listener, err := net.ListenTCP("tcp4", tcpAddr)
        if err != nil {
            log.Println("server failed to start...")
            return
        }
    
        defer listener.Close()
        go print()
        log.Println("begin listening, addr : ", tcpAddr)
    
        for {
            conn, err := listener.Accept()
            if err != nil {
                log.Println("socket accept failed. reason: ", err)
                continue
            }
    
            go handleConnection(conn)
        }
    
    }
    
    func print() {
        ticker := time.NewTicker(5 * time.Second)
    
        for {
            <-ticker.C
            log.Println(len(clients.Map))
        }
    }
    
    var num = 0
    var num2 = 0
    var clients = Clients{Map: make(map[string]int, 0)}
    
    type Clients struct {
        sync.RWMutex
        Map map[string]int
    }
    
    func (c *Clients) Add(ip string) {
        c.Lock()
        c.Map[ip] = 1
        c.Unlock()
    }
    
    func (c *Clients) Del(ip string) {
        c.Lock()
        delete(c.Map, ip)
        c.Unlock()
    }
    func handleConnection(conn net.Conn) {
        ip := conn.RemoteAddr().String()
        clients.Add(ip)
    
        buf := make([]byte, 64)
        for {
            _, err := conn.Read(buf)
            //log.Println("n=", n)
            if err != nil {
                //log.Println(err)
                conn.Close()
                clients.Del(ip)
            }
        }
    }

        客户端: client.go

    package main
    
    import (
        "log"
        "net"
    )
    
    func main() {
        for i := 0; i < 40000; i++ {
            conn, err := net.Dial("tcp", "x.x.x.x:5000")
            if err != nil {
                log.Println(err)
                return
            }
        
            go Read(conn)
        }
    
        log.Println("ok")
        select {}
    }
    
    func Read(conn net.Conn) {
        buf := make([]byte, 64)
        for {
            _, err := conn.Read(buf)
            if err != nil {
                log.Println(err)
                return
            }
        }    
    }

    结论:

          开始时,服务器是2核,2G内存, 达到8W连接左右,接受新连接的速度就慢了。后来改成8核,20W连接无压力。

          最终5个客户端,每个客户端发起40000个连接, 共20W连接。
          服务器单进程, 接受20W个连接。CPU,内存压力都很小。

  • 相关阅读:
    九.Spring Boot JPAHibernateSpring Data
    JIRA安装过程中链接mysql的问题!
    五、案例-指令参考-freemarker指令、表达式
    四、模版指令操作
    三、freemarker数据、模版指令
    二、freemarker.controller半自动静态化+Tomcat虚拟资源映射
    一、springMVC、freemarker页面半自动静态化
    window窗口-button(按钮)-dialog(对话框,带按钮)
    panel面板
    python 给定年份、月份,返回当月对应天数
  • 原文地址:https://www.cnblogs.com/bear129/p/7919600.html
Copyright © 2011-2022 走看看