golang TCPConn.Writeによって返されたエラーを検査して送信失敗を検出しようとしていますが、それはゼロです。私はまた、成功なしでTCPConn.SetWriteDeadlineを使ってみました。golang TCPConn.SetWriteDeadlineが期待通りに動作しないようです。
物事が起こる方法は次のとおりです。
- サーバが
- クライアントが
- サーバーがメッセージを送信し、クライアントは、クライアントが
- シャットダウンし、それ
- 受け取りを接続を開始サーバーはもう1つのメッセージを送信します。エラーなし
- サーバーは3番目のメッセージを送信しますGE:今だけのエラーが表示されます。
質問:なぜ唯一のエラーで非既存のクライアント結果の2番目のメッセージ?ケースは適切にどのように扱われるべきですか?
コードは次のとおりです。
package main
import (
"net"
"os"
"bufio"
"fmt"
"time"
)
func AcceptConnections(listener net.Listener, console <- chan string) {
msg := ""
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
fmt.Printf("client connected\n")
for {
if msg == "" {
msg = <- console
fmt.Printf("read from console: %s", msg)
}
err = conn.SetWriteDeadline(time.Now().Add(time.Second))
if err != nil {
fmt.Printf("SetWriteDeadline failed: %v\n", err)
}
_, err = conn.Write([]byte(msg))
if err != nil {
// expecting an error after sending a message
// to a non-existing client endpoint
fmt.Printf("failed sending a message to network: %v\n", err)
break
} else {
fmt.Printf("msg sent: %s", msg)
msg = ""
}
}
}
}
func ReadConsole(network chan <- string) {
console := bufio.NewReader(os.Stdin)
for {
line, err := console.ReadString('\n')
if err != nil {
panic(err)
} else {
network <- line
}
}
}
func main() {
listener, err := net.Listen("tcp", "localhost:6666")
if err != nil {
panic(err)
}
println("listening on " + listener.Addr().String())
consoleToNetwork := make(chan string)
go AcceptConnections(listener, consoleToNetwork)
ReadConsole(consoleToNetwork)
}
サーバーコンソールは、次のようになります。
listening on 127.0.0.1:6666
client connected
hi there!
read from console: hi there!
msg sent: hi there!
this one should fail
read from console: this one should fail
msg sent: this one should fail
this one actually fails
read from console: this one actually fails
failed sending a message to network: write tcp 127.0.0.1:51194: broken pipe
クライアントは、次のようになります。
package main
import (
"net"
"os"
"io"
//"bufio"
//"fmt"
)
func cp(dst io.Writer, src io.Reader, errc chan<- error) {
// -reads from src and writes to dst
// -blocks until EOF
// -EOF is not an error
_, err := io.Copy(dst, src)
// push err to the channel when io.Copy returns
errc <- err
}
func StartCommunication(conn net.Conn) {
//create a channel for errors
errc := make(chan error)
//read connection and print to console
go cp(os.Stdout, conn, errc)
//read user input and write to connection
go cp(conn, os.Stdin, errc)
//wait until nil or an error arrives
err := <- errc
if err != nil {
println("cp error: ", err.Error())
}
}
func main() {
servAddr := "localhost:6666"
tcpAddr, err := net.ResolveTCPAddr("tcp", servAddr)
if err != nil {
println("ResolveTCPAddr failed:", err.Error())
os.Exit(1)
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
println("net.DialTCP failed:", err.Error())
os.Exit(1)
}
defer conn.Close()
StartCommunication(conn)
}
EDIT:JimBの提案Iに続き実際の例を思いついた。メッセージはもはや失われず、新しい接続で再送信されます。私はかなり安全ではありますが、別の実行ルーチン間で共有変数(connWrap.IsFaulted)を使用することはどれほど安全ですか。
答えを含めるように質問を編集するのではなく、あなた自身の質問に回答することをお勧めします。 – Joakim