• 最大连接数“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
    ", 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
    ",conn.RemoteAddr().String())
    	conn.Write([]byte(`hello`))
    }
    
    func checkError(err error) {
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Fatal error: %s
    ", 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 
    ", 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
    ",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
    ",string(buf[0:n]))
    
    	}
    
    
    }
    func checkError(err error) {
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "Fatal error: %s
    ", 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,一个方便的虚拟机管理软件,

  • 相关阅读:
    python使用zipfile递归压缩和解压缩文件
    文件上传控件bootstrap-fileinput中文设置没有效果的情况
    vue keep-alive 不生效和多级(三级以上)缓存失败
    Entityframework批量删除
    EasyUI ComboGrid 集成分页、按键示例
    在Entity Framework中使用事务
    MVC实用构架设计(三)——EF-Code First(6):数据更新最佳实践
    Entityframework更新数据和插入数据
    esayui-datagrid的使用
    javascript:;与javascript:void(0)使用介绍
  • 原文地址:https://www.cnblogs.com/xdao/p/server_max_65535.html
Copyright © 2020-2023  润新知