英文:
How do I call TCPConn.SetLinger()?
问题
我正在使用Go 1.2,并尝试在我的服务器关闭由于输入中的致命错误而关闭的套接字上调用TCPConn.SetLinger(0)。然而,我无法弄清楚如何做到这一点。net.Listener.Accept()和TCPListener.Accept()都返回net.Conn,而不是net.TCPConn。net.Conn没有实现SetLinger。我尝试进行类型切换,但编译器抱怨"不可能的类型切换情况:conn(类型为net.Conn)不能具有动态类型net.TCPConn(缺少Close方法)"。net.TCPConn怎么会缺少Close方法呢?我还没有检查过源代码,但文档中列出了一个close方法(反正你无论如何都可以关闭连接)。
看起来你不能将net.Conn转换为net.TCPConn(因为没有Close方法),而且你无法从服务器获取TCPConn,因为所有的Accept()都返回net.Conn。那么我该如何调用SetLinger呢?(或者说,SetKeepAlive、SetNoDelay呢?)
仔细查看后,似乎有一个net.TCPListener.AcceptTCP()方法,它返回一个TCPListener,我真的需要这样做吗?为什么我不能从Accept()中获取TCPConn呢?我开始使用net.Listen("tcp", ":4321"),所以我知道它必须是一个TCPConn...
英文:
I'm using Go 1.2 and trying to call TCPConn.SetLinger(0) on a socket that my server is closing due to fatal errors in the input. However, I can't figure out how I would do this. Both net.Listener.Accept() and TCPListener.Accept() return net.Conn, not net.TCPConn. net.Conn does not implement SetLinger. I tried doing a type switch, but then the compiler complains of an "impossible type switch case: conn (type net.Conn) cannot have dynamic type net.TCPConn (missing Close method)". How can net.TCPConn be missing a Close method?? I haven't checked the source, but the documentation lists a close method (and what kind of connection can you not close, anyway?).
It seems like you cannot cast net.Conn to net.TCPConn (because of no Close method), and you can't get a TCPConn on a server, because all the Accept()s return a net.Conn. So how do I actually call SetLinger? (Or for that matter, SetKeepAlive, SetNoDelay?)
After looking more closely, it looks like there is a net.TCPListener.AcceptTCP() which returns a TCPListener, is that really what I have to do? Why can't I get a TCPConn from Accept()? I started it off with net.Listen("tcp", ":4321"), so I know it has to be a TCPConn underneath...
答案1
得分: 3
你可以使用TCPListener.AcceptTCP()
方法,Accept
方法只是调用AcceptTCP
方法并将*TCPConn
作为接口返回。
从http://golang.org/src/pkg/net/tcpsock_posix.go?s=7727:7771#L233
func (l *TCPListener) Accept() (Conn, error) {
c, err := l.AcceptTCP() //注意这部分
if err != nil {
return nil, err
}
return c, nil
}
或者像James在评论中提到的那样,你可以简单地将其转换为tcpcon := conn.(*net.TCPConn)
。
英文:
You could use TCPListener.AcceptTCP()
, Accept
just calls AcceptTCP
and returns *TCPConn
as an interface.
From http://golang.org/src/pkg/net/tcpsock_posix.go?s=7727:7771#L233
func (l *TCPListener) Accept() (Conn, error) {
c, err := l.AcceptTCP() //notice this part
if err != nil {
return nil, err
}
return c, nil
}
Or like James mentioned in the comments, you could simply cast it to tcpcon := conn.(*net.TCPConn)
.
答案2
得分: 0
根据如何设置Go net/http的Socket选项 - setsockopt()示例,我们可以通过net.Dialer
的Control
来设置SO_LINGER
。
另一种解决方案是通过http.Transport
的DialContext
来完成。
以上是要翻译的内容。
英文:
Per How to Set Go net/http Socket Options - setsockopt() example
We could set SO_LINGER
through Control
of net.Dialer
dialer := &net.Dialer{
Control: func(network, address string, conn syscall.RawConn) error {
var operr error
if err := conn.Control(func(fd uintptr) {
operr = syscall.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_LINGER, 1)
}); err != nil {
return err
}
return operr
},
}
client := http.Client{Transport: &http.Transport{DialContext: dialer.DialContext}}
Another solution could be done through DialContext
of http.Transport
type connDialer struct {
c net.Conn
}
func (cd connDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
tcpConn, ok := cd.c.(*net.TCPConn)
if ok {
tcpConn.SetLinger(0)
return tcpConn, nil
}
return cd.c, nil
}
dialer := net.Dialer{}
conn, _ := dialer.DialContext(ctx, network, addr)
client := http.Client{Transport: &http.Transport{DialContext: connDialer{c: conn}.DialContext}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论