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,内存压力都很小。

原文地址:https://www.cnblogs.com/bear129/p/7919600.html