Go 利用goroutine实现本地 客户端-服务端 tcp通信(读/写数据):

 

背景:
  客户端主动连接服务端,连接成功后,服务端负责发送数据,客户端负责接收数据(打印当前时间)。每当多产生一个新的客户端连接,服务端都会新开启一个协程用来处理这条新的连接请求。

服务端代码:

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链接(报错原因跳转链接):
 

如此时服务端也会收到客户端断开连接的通知,如下图: 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值