我必须编写一个客户端代码,该代码从服务器接收字符串形式的消息,并从控制台接收输入,以将消息结束到服务器。这两个操作应彼此同时运行。我已经编写了执行这些操作的代码,但是没有顺序执行。
这是我当前的代码:
func SocketClient() {
conn, err := net.Dial("tcp", ":9000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
server_reader := bufio.NewReader(conn)
input_reader := bufio.NewReader(os.Stdin)
for {
// for sending messages
buff, err := input_reader.ReadString('\n')
if err != nil {
log.Fatalln(err)
}
conn.Write([]byte(buff))
// for receiving messages but this won't run until the above has taken input from console
buff2, err := server_reader.ReadString('\n')
if err != nil {
log.Fatalln(err)
}
fmt.Println("Received: %s", buff2)
}
}
buff从服务器接收传入消息,然后buff2从控制台接收传出消息输入,但是为了再次接收传入消息,buff2需要一些输入。我知道可以使用通道,互斥锁等来完成此操作,但是由于我对基本原理缺乏了解,因此在使用它们时遇到了问题。
我想实际的代码应该像这样:
func SocketClient() {
conn, err := net.Dial("tcp", ":9000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
go func() {
// for sending messages
} ()
go func() {
// for receiving messages
} ()
}
如何使输入和输出成为两个独立的goroutine?
答案 0 :(得分:1)
直接在SocketClient
中运行循环之一。在以SocketClient
开头的新goroutine中运行另一个循环。
func SocketClient() error {
conn, err := net.Dial("tcp", ":9000")
if err != nil {
return err
}
defer conn.Close()
server_reader := bufio.NewReader(conn)
input_reader := bufio.NewReader(os.Stdin)
go func() {
defer conn.Close()
// This loop will break and the goroutine will exit when the
// SocketClient function executes conn.Close().
for {
buff, err := server_reader.ReadBytes('\n')
if err != nil {
// optional: log.Fatal(err) to cause program to exit without waiting for new input from stdin.
return
}
fmt.Printf("Received: %s", buff)
}
}()
for {
// for sending messages
buff, err := input_reader.ReadBytes('\n')
if err != nil {
return err
}
if _, err := conn.Write(buff); err != nil {
return err
}
}
}
使用bufio.Reader ReadBytes
方法代替ReadString
,以避免在[]byte
和string
之间进行不必要的转换。
答案 1 :(得分:0)
您可以创建一个像这样的函数,该函数返回一个通道。它还会启动一个新的go例程,该例程将写入返回的通道。
这允许使用者调用此方法,并期望值返回到返回的通道上。
我还更新了方法签名以使用<form method="post" enctype="multipart/form-data">
<input type="hidden" id="formUpload" name="formUpload">
<input type="file" name="formUploadFile" required>
<label for="ds" >Hiermit willige ich ein, dass die eingegebenen Daten zur Bearbeitung meines Anliegens gespeichert und verarbeitet werden. Folgende Daten werden an die EK Frachtenservice übermittelt: Alle Daten welche im Formular angegeben sind.
<input type="checkbox" id="ds" name="ds" required>
<span class="checkmark"></span>
</label>
<input type="submit" value="Antragsformulare hochladen" name="submit" id="send">
</form>
,因为它是在换行符上分割的更有效方法。
*bufio.Scanner
现在我们可以在func ReadFully(scanner *bufio.Scanner) <-chan string {
out := make(chan string)
go func() {
// once all the values have been read, close the channel
// this tells the consumers that there will not be anymore
// values and they don't need to keep listening to this channel.
defer close(out)
for scanner.Scan() {
out <- scanner.Text()
}
if err := scanner.Err(); err!= nil {
log.Fatal(err)
}
}()
return out
}
中使用此ReadFully
方法
SocketClient
注意,此示例完全省略了取消等操作。通常,如果没有停止它的方法,切勿启动go例程。
查看有关管道的出色文章。 https://blog.golang.org/pipelines
答案 2 :(得分:0)
我写了一篇关于Go并发的博客文章。 https://marcofranssen.nl/concurrency-in-go/
还使用了此博客文章中的一些概念。
https://marcofranssen.nl/go-webserver-with-gracefull-shutdown/
这还使我能够拦截命令行输入(例如信号)以安全地关闭服务器。
您可以使用类似的方法来获取您的命令输入并进行使用。
主要思想是使用通道在go例程之间进行通信。