編程模型
讓我們先看一下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,一個方便的虛擬機管理軟件,