从多个读取器中的TCP连接读取数据

huangapple go评论85阅读模式
英文:

Go - Read data from TCP connection from multiple readers

问题

我正在使用Go编程语言处理云服务器的网络事务。我遇到了一个问题,即如何在不同的Goroutines中同时从相同的TCP连接读取数据。

以下是一个简单的示例:

package main

import (
	"fmt"
	"net"
)

func main() {
	addr, _ := net.ResolveTCPAddr("tcp", ":8888")
	listener, _ := net.ListenTCP("tcp", addr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Println(err)
			return
		}
		go Handle(conn) // 输出总是来自这里
		go Handle(conn)
	}
}

func Handle(conn *net.TCPConn) {
	data := make([]byte, 1024)
	fmt.Println("Ok")
	for {
		len_data, err := conn.Read(data)
		fmt.Println(err)
		fmt.Println(len_data)
	}
}

在这个示例中,控制台输出总是来自第一个Goroutine go Handle(conn)...如何使两个Goroutines同时进行读取操作?

谢谢。

英文:

I'm working on Cloud Server's networking thing using Go programming language.
And I faced a problem with <b>reading same TCPconn at the same time from different Goroutines</b>.

Here is a simple example

package main

import (
	&quot;fmt&quot;
	&quot;net&quot;
)

func main() {
	addr, _ := net.ResolveTCPAddr(&quot;tcp&quot;, &quot;:8888&quot;)
	listener, _ := net.ListenTCP(&quot;tcp&quot;, addr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Println(err)
			return
		}
		go Handle(conn) // output always coming from here
		go Handle(conn)
	}
}

func Handle(conn *net.TCPConn) {
	data := make([]byte, 1024)
	fmt.Println(&quot;Ok&quot;)
	for {
		len_data, err := conn.Read(data)
		fmt.Println(err)
		fmt.Println(len_data)
	}
}

In this example console output always coming from 1st goroutine <code>go Handle(conn)</code> ...
<p>How to make Read functionality from 2 Goroutines at the same time ?</p>

Thanks

答案1

得分: 2

一种方法是使用io.MultiWriterio.Pipe

func main() {
    var wg sync.WaitGroup
    r := strings.NewReader(hello)
    pr1, pw1 := io.Pipe()
    pr2, pw2 := io.Pipe()
    pr3, pw3 := io.Pipe()
    mw := io.MultiWriter(pw1, pw2, pw3)

    wg.Add(4)
    go process(&wg, 0, pr1)
    go process(&wg, 1, pr2)
    go process(&wg, 2, pr3)
    go func() {
        io.Copy(mw, r)
        pw1.Close()
        pw2.Close()
        pw3.Close()
        wg.Done()
    }()

    wg.Wait()
}

playground

英文:

One way to do it is using io.MultiWriter and io.Pipe:

func main() {
	var wg sync.WaitGroup
	r := strings.NewReader(hello)
	pr1, pw1 := io.Pipe()
	pr2, pw2 := io.Pipe()
	pr3, pw3 := io.Pipe()
	mw := io.MultiWriter(pw1, pw2, pw3)

	wg.Add(4)
	go process(&amp;wg, 0, pr1)
	go process(&amp;wg, 1, pr2)
	go process(&amp;wg, 2, pr3)
	go func() {
		io.Copy(mw, r)
		pw1.Close()
		pw2.Close()
		pw3.Close()
		wg.Done()
	}()

	wg.Wait()
}

<kbd>playground</kbd>

答案2

得分: 0

开始一个单独的Go协程来执行conn.Read(data)并将结果放入一个通道中。

然后(并发地,不等待第一个Go协程完成)开始多个Go协程从这个通道中读取。

由于conn不是线程安全的(它只能在单个Go协程中运行,可能是因为MAXGOPROCS == 1),你不希望直接从多个Go协程并发地读取conn

英文:

Start a single go routine to perform conn.Read(data) and put the result into a channel.

Then (concurrently, without waiting for the first go routine to finish) start multiple go routines to read from this channel.

You don't want to directly read from the conn concurrently from multiple go routine since it is not thread-safe (the fact that it runs, and only run only on a single go routine probably because your MAXGOPROCS == 1).

答案3

得分: -1

好的,首先,你做错了,朋友。

你应该创建工作线程(预先创建),创建通道,并将该通道与传入的连接进行聚合。然后,你应该在工作线程内部处理这个连接。这样,你将得到X个并发的工作线程,用于处理你的连接。

我已经为你写了一个很好的示例,展示了如何优雅地处理工作线程,但是没有时间写下如何优雅地处理传入的连接。尽管如此,你会明白我的意思。

希望对你有所帮助。

http://play.golang.org/p/YkQVmBEWly

英文:

Ok so first of all. You're doing it wrong friend.

What you should do is create workers (pre-create), create channel and aggregate that channel with incoming connections. Than you should take that same connection inside of worker and handle it. On this way you'll get X concurrent workers that runs against your connections.

I went ahead and wrote you down one nice example of how to gracefully handle workers but did not had time to write down how to gracefully handle incoming connections. Never the less, you'll see what i mean.

http://play.golang.org/p/YkQVmBEWly

Hope this helps,

huangapple
  • 本文由 发表于 2015年7月18日 23:07:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/31492519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定