最大连接数“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,一个方便的虚拟机管理软件,

posted @ 2018-04-30 12:55  半山th  阅读(2343)  评论(0编辑  收藏  举报