我正在尝试通过检查golang
TCPConn.Write返回的错误来检测发送失败,但它为nil。我也尝试使用TCPConn.SetWriteDeadline,但没有成功。
事情就是这样发生的:
问题 :为什么只有第二条消息发送给不存在的客户端会导致错误?案件应如何妥善处理?
代码如下:
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)
}
编辑
:按照JimB的建议,我想出了一个可行的例子。邮件不会再丢失,并且会在新的连接中重新发送。我不确定在不同的go例程之间使用共享变量(connWrap.IsFaulted)有多安全。
package main
import (
"net"
"os"
"bufio"
"fmt"
)
type Connection struct {
IsFaulted bool
Conn net.Conn
}
func StartWritingToNetwork(connWrap * Connection, errChannel chan <- error, msgStack chan string) {
for {
msg := <- msgStack
if connWrap.IsFaulted {
//put it back for another connection
msgStack <- msg
return
}
_, err := connWrap.Conn.Write([]byte(msg))
if err != nil {
fmt.Printf("failed sending a message to network: %v\n", err)
connWrap.IsFaulted = true
msgStack <- msg
errChannel <- err
return
} else {
fmt.Printf("msg sent: %s", msg)
}
}
}
func StartReadingFromNetwork(connWrap * Connection, errChannel chan <- error){
network := bufio.NewReader(connWrap.Conn)
for (!connWrap.IsFaulted) {
line, err := network.ReadString('\n')
if err != nil {
fmt.Printf("failed reading from network: %v\n", err)
connWrap.IsFaulted = true
errChannel <- err
} else {
fmt.Printf("%s", line)
}
}
}
func AcceptConnections(listener net.Listener, console chan string) {
errChannel := make(chan error)
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
fmt.Printf("client connected\n")
connWrap := Connection{false, conn}
go StartReadingFromNetwork(&connWrap, errChannel)
go StartWritingToNetwork(&connWrap, errChannel, console)
//block until an error occurs
<- errChannel
}
}
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)
}
这不是特定于Go的,而是通过底层TCP套接字显示出来的工件。
TCP终止步骤的详细图示在此页面的底部:http
:
//www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm
简单的版本是,当客户端关闭其套接字时,它将发送FIN,并从服务器接收ACK。然后,它等待服务器执行相同的操作。但是,您不是发送FIN,而是发送更多的数据,这些数据将被丢弃,并且客户端套接字现在假定来自您的任何其他数据都是无效的,因此下次发送时会收到RST,这就是气泡进入您看到的错误。
回到您的程序,您需要以某种方式进行处理。一般来说,你能想到的任何人负责发起发送的,还负责启动终止,因此,您的服务器应该假设它可以继续发送,直到 它
关闭连接,或遇到错误。如果需要更可靠地检测到客户端关闭,则需要在协议中具有某种客户端响应。这样,可以在套接字上调用recv并返回0,这将提醒您关闭的连接。
进行中,这将从连接的Read方法(或您的情况下,在Copy中)返回EOF错误。SetWriteDeadline无法正常工作,因为会进行少量写入,然后将其静默删除,否则客户端最终将以RST响应,从而给您带来错误。
我对nodeJS…和编程是新手。但我试图让这段代码工作,我无法理解为什么它似乎不起作用。更糟糕的是,我也不知道如何排除故障。如果我使用控制台。日志语句,我可以看到,一旦我启动网页,它就会连接,但网页从未从nodeJS服务器收到消息,服务器也从未从网页收到消息。我正在使用Chrome浏览器。 服务器.js: 我从命令提示符在树莓pi zero w上启动它: index.html引用interface
我在Spark上使用Python时遇到问题。我的应用程序有一些依赖项,如numpy、pandas、astropy等。我无法使用virtualenv创建具有所有依赖项的环境,因为集群上的节点除了HDFS之外没有任何公共挂载点或文件系统。因此,我一直坚持使用。我将站点包的内容打包在一个ZIP文件中,并使用
这是我第一次涉足AES加密和OpenSSL。我设法得到了一些加密和解密的例子,但它们似乎无法正常工作。例如,在加密函数中: 这将生成一个真正的“加密”文件,它还不错,但并不完全是它应该的样子(或者我认为是这样)。如果我从openssl运行cli命令来加密同一个文件,我会得到一个文本文件,其中写有加密的字符串。我的函数生成的是一个文件,不是文本(实际上它说它是未知格式)。 第二个,解密: 在这个函数
我正在开发新的web,我想使用ArcGIS javascript API4使用WMTS服务 选择空间参考EPSG:25830时,Javascript API 4.11中的WMTSLayer似乎不起作用。 问题是API生成的请求不正确,Tilerow参数错误。 正在发送的请求是这样的。http://www.ign.es/wmts/ign-base?SERVICE=WMTS 而且一定是... http
我不能使用vqmod。当ı单击管理面板中的vqmod时,它会显示 VQMod似乎没有正确生成vqcache文件 我还使用与汽车相关的产品xml。是这件事造成的?我不知道。 还有一些产品页面说 注意:未定义索引:product_info in/home/elmaicom/domains/elmacimarketi。com/public\u html/vqmod/vqcache/vq2-catalog
我刚刚安装了node.js,我还在环境变量中设置了PATH。PATH值为: