最大连接数“65535”的误解

编程模型

让我们先看一下socket的编程模型:

以上图片来自此文

和C语言不同的是,go语言在底层帮我们封装了socket,ListenTCP的时候创建,绑定,并监听;DialTCP的时候,创建并连接 。具体可以看此文,或者用调试模式跟踪一下。下面让我们用代码来看清服务器只能有65536个最大链接的谬论吧。

服务端代码

server.go

package main

import (
    "fmt"
    "net"
    "os"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Printf("Usage: %s host:port\n", os.Args[0])
        return
    }

    //创建TCP协议
    tcpAddr, err := net.ResolveTCPAddr("tcp4", os.Args[1]) //tcp4 是协议版本,还有tcp6 如果只有端口的话默认绑定127.0.0.1
    checkError(err)

    //创建、绑定、监听socket
    listener, err := net.ListenTCP("tcp4", tcpAddr)
    checkError(err)
    for {
        //等待连接
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        //处理连接
        go handleClient(conn)
    }
}

func handleClient(conn net.Conn) {
    defer conn.Close()
    fmt.Printf("client address %s\n",conn.RemoteAddr().String())
    conn.Write([]byte(`hello`))
}

func checkError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s\n", err.Error())
        os.Exit(1)
    }
}

客户端代码

package main

import (
    "fmt"
    "net"
    "os"
    "time"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Print( "Usage: %s host:port \n", os.Args[0])
        return
    }

    tcpAddr, err := net.ResolveTCPAddr("tcp4", os.Args[1])
    checkError(err)
    //创建socket并连接服务器
    conn, err := net.DialTCP("tcp4", nil, tcpAddr)
    checkError(err)
    fmt.Printf("client address %s\n",conn.LocalAddr().String())

    defer conn.Close()
    var buf [512]byte
    for {
        //从服务器读取数据
        n, err := conn.Read(buf[0:])
        if n == 0 {
            time.Sleep(time.Second)  //如果没读到就继续等待
            continue
        }
        checkError(err)
        fmt.Printf("receive %s from server\n",string(buf[0:n]))

    }


}
func checkError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s\n", err.Error())
        os.Exit(1)
    }
}

测试链接

需要两台电脑测试,这里使用虚拟机

启动服务端

go run server.go 0.0.0.0:7777 ,这里在虚拟机上运行服务端
这里0.0.0.0 的意思是允许来自外部的链接

启动客户端

go run client.go 服务端ip地址:7777,这里在本地运行客户端,并启动了四个

查看端口

服务端

客户端

从上图我们可以看到:

  • 客户端连接到服务端后,服务端随机分配了一个端口给客户端,客户端会绑定分配自己的端口。
  • 对客户端来说7777这个端口,并没有绑定,否则我们也不能启动多个客户端了。7777这个端口对客户端来说,就是连接服务端的坐标。
  • 再看服务端,分配给客户端后建立连接后,也没有绑定分配的那个端口,比如上图的43718。

误解从何而来

看一下socket的编程模型,我估计在与服务端的accept这个环节。其实这个环节并没有另外去绑定一个端口来和客户端通信。
扩展一下,其实对于服务端来说,端口数并不能限制(因为只绑定一个端口),那么连接客户端的总数限制就在于内存、CPU和网络带宽了。
对于客户端呢,连接同一个服务端时,都要占用一个端口,对同一台电脑,限制可以运行的客户端总数就在于端口数、内存、CPU和网络带宽。
另外65535这个数目实际上是可以更改的。

推荐工具

这里的虚拟机使用的vagrant,一个方便的虚拟机管理软件,

猜你喜欢

转载自www.cnblogs.com/xdao/p/server_max_65535.html