背景:
客户端主动连接服务端,连接成功后,服务端负责发送数据,客户端负责接收数据(打印当前时间)。每当多产生一个新的客户端连接,服务端都会新开启一个协程用来处理这条新的连接请求。
服务端代码:
package main
import (
"fmt"
"io"
"net"
"runtime"
"time"
)
func handleConn(c net.Conn, limitCh chan struct{}) {
limitCh <- struct{}{}
defer func() {
<- limitCh
}()
for {
_, err := io.WriteString(c, time.Now().Format(time.RFC3339) + "\n")
if err != nil {
c.Close()
<- limitCh
fmt.Println("io.WriteString() error: ", err)
return
}
fmt.Println("当前协程数:", len(limitCh), runtime.NumGoroutine())
time.Sleep(time.Second)
}
}
func main() {
limitChan := make(chan struct{}, 100)
listener, err := net.Listen("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println("net.Listen() error: ", err)
return
}
for {
conn, err := listener.Accept() // 循环监听
if err != nil {
fmt.Println("lisener.Accept() error: ", err)
return
}
go handleConn(conn, limitChan)
}
}
客户端代码:
package main
import (
"io"
"log"
"net"
"os"
"time"
)
func ConnectServer() {
conn, err := net.Dial("tcp", "localhost:8888")
if err != nil {
log.Fatal("net.Dial() error: ", err)
return
}
defer conn.Close()
_, err = io.Copy(os.Stdout, conn)
if err != nil {
log.Fatal("io.Copy() error: ", err)
return
}
}
func main() {
// 开启100个客户端连接服务:
for i := 0; i < 100; i++ {
go ConnectServer()
}
time.Sleep(1 * time.Hour) // 延时
}
/*
bind: An operation on a socket could not be performed because the system lacked sufficient buffer sp
https://blog.csdn.net/xia_xing/article/details/53352658
*/
补充:
若尝试将客户端的协程数开到1w,客户端开启的协程数过多,即会占用较多的端口,最终导致系统端口耗尽,如下图:
报错原因:由于系统端口已耗尽,无法再建立新的Socket链接(报错原因跳转链接):
如此时服务端也会收到客户端断开连接的通知,如下图: