利用利用Golang实现实现TCP连接的双向拷贝详解连接的双向拷贝详解
公司中遇到了一个使用golang编写的agent程序,所以这篇文章主要给大家介绍了关于利用Go如何实现TCP连接
的双向拷贝的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考,下面随着小编来一起看看
吧。
前言前言
本文主要给大家介绍了关于Golang实现TCP连接的双向拷贝的相关内容,分享出来供大家参考学习,下面话不多说了,来一
起看看详细的介绍吧。
最简单的实现最简单的实现
每次来一个Server的连接,就新开一个Client的连接。用一个goroutine从server拷贝到client,再用另外一个goroutine从client
拷贝到server。任何一方断开连接,双向都断开连接。
func main() {
runtime.GOMAXPROCS(1)
listener, err := net.Listen("tcp", "127.0.0.1:8848")
if err != nil {
panic(err)
}
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
go handle(conn.(*net.TCPConn))
}
}
func handle(server *net.TCPConn) {
defer server.Close()
client, err := net.Dial("tcp", "127.0.0.1:8849")
if err != nil {
fmt.Print(err)
return
}
defer client.Close()
go func() {
defer server.Close()
defer client.Close()
buf := make([]byte, 2048)
io.CopyBuffer(server, client, buf)
}()
buf := make([]byte, 2048)
io.CopyBuffer(client, server, buf)
}
一个值得注意的地方是io.Copy的默认buffer比较大,给一个小的buffer可以支持更多的并发连接。
这两个goroutine并序在一个退出之后,另外一个也退出。这个的实现是通过关闭server或者client的socket来实现的。因为
socket被关闭了,io.CopyBuffer 就会退出。
Client端实现连接池端实现连接池
一个显而易见的问题是,每次Server的连接进来之后都需要临时去建立一个新的Client的端的连接。这样在代理的总耗时里就
包括了一个tcp连接的握手时间。如果能够让Client端实现连接池复用已有连接的话,可以缩短端到端的延迟。
var pool = make(chan net.Conn, 100)
func borrow() (net.Conn, error) {
select {
case conn := <- pool:
return conn, nil
default:
return net.Dial("tcp", "127.0.0.1:8849")
}
}
func release(conn net.Conn) error {
select {
case pool <- conn:
// returned to pool
return nil
default: