1. 程式人生 > >tcp並發服務器(c20w)

tcp並發服務器(c20w)

sock proc () 進程 ipv4 sync cli aso truct

** 原創文章,請勿轉載 **

並發服務器是一個老生常談的話題,今天這裏也寫一個。

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,內存壓力都很小。

tcp並發服務器(c20w)