编程模型
让我们先看一下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,一个方便的虚拟机管理软件,