What is the proper way to detect a dropped connection in Go?

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

What is the proper way to detect a dropped connection in Go?

问题

我正在使用一个Go HTTP服务器实现,该服务器从移动客户端读取上传的内容。然而,我遇到了一个问题,由于长时间的keep-alive,如果移动客户端离线(经常发生),服务器将在读取请求缓冲区时挂起很长时间。

检测到连接断开并关闭输入缓冲区的正确方法是什么?

英文:

I am working with a Go HTTP server implementation that reads an upload from a mobile client. However, I'm experiencing problems where because of a long keep-alive, the server will hang reading the request buffer for quite a long time if the mobile client goes offline (as often happens).

What is the proper way to detect a dropped connection and close the input buffer?

答案1

得分: 2

在服务器上设置一个合理的超时时间,例如:

  1. srv := &http.Server{
  2. Addr: ":443",
  3. ReadTimeout: time.Minute * 2,
  4. WriteTimeout: time.Minute * 2,
  5. }
  6. log.Fatal(srv.ListenAndServeTLS(certFile, keyFile))
英文:

Set a reasonable timeout on the server, for example:

  1. srv := &http.Server{
  2. Addr: ":443",
  3. ReadTimeout: time.Minute * 2,
  4. WriteTimeout: time.Minute * 2,
  5. }
  6. log.Fatal(srv.ListenAndServeTLS(certFile, keyFile))

答案2

得分: 1

因为我只想在写入停止时断开连接(并且快速断开,以便我可以记录到目前为止接收到的数据并允许客户端恢复),所以ReadTimeout对我来说不是正确的解决方案。

我在这个gist中找到了答案。你需要在连接本身上设置读取超时。

  1. package nettimeout
  2. import (
  3. "net"
  4. "time"
  5. )
  6. // Listener wraps a net.Listener, and gives a place to store the timeout
  7. // parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
  8. type Listener struct {
  9. net.Listener
  10. ReadTimeout time.Duration
  11. WriteTimeout time.Duration
  12. }
  13. func (l *Listener) Accept() (net.Conn, error) {
  14. c, err := l.Listener.Accept()
  15. if err != nil {
  16. return nil, err
  17. }
  18. tc := &Conn{
  19. Conn: c,
  20. ReadTimeout: l.ReadTimeout,
  21. WriteTimeout: l.WriteTimeout,
  22. }
  23. return tc, nil
  24. }
  25. // Conn wraps a net.Conn, and sets a deadline for every read
  26. // and write operation.
  27. type Conn struct {
  28. net.Conn
  29. ReadTimeout time.Duration
  30. WriteTimeout time.Duration
  31. }
  32. func (c *Conn) Read(b []byte) (int, error) {
  33. err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
  34. if err != nil {
  35. return 0, err
  36. }
  37. return c.Conn.Read(b)
  38. }
  39. func (c *Conn) Write(b []byte) (int, error) {
  40. err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
  41. if err != nil {
  42. return 0, err
  43. }
  44. return c.Conn.Write(b)
  45. }
  46. func NewListener(addr string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
  47. l, err := net.Listen("tcp", addr)
  48. if err != nil {
  49. return nil, err
  50. }
  51. tl := &Listener{
  52. Listener: l,
  53. ReadTimeout: readTimeout,
  54. WriteTimeout: writeTimeout,
  55. }
  56. return tl, nil
  57. }
英文:

Because I wanted to drop the connection only when writes stop (and quickly, so that I can record the data received so far and allow the client to resume), the ReadTimeout isn't the right solution for me.

I found the answer in this gist. You need to set a read on the connection itself.

package nettimeout

  1. import (
  2. "net"
  3. "time"
  4. )
  5. // Listener wraps a net.Listener, and gives a place to store the timeout
  6. // parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
  7. type Listener struct {
  8. net.Listener
  9. ReadTimeout time.Duration
  10. WriteTimeout time.Duration
  11. }
  12. func (l *Listener) Accept() (net.Conn, error) {
  13. c, err := l.Listener.Accept()
  14. if err != nil {
  15. return nil, err
  16. }
  17. tc := &Conn{
  18. Conn: c,
  19. ReadTimeout: l.ReadTimeout,
  20. WriteTimeout: l.WriteTimeout,
  21. }
  22. return tc, nil
  23. }
  24. // Conn wraps a net.Conn, and sets a deadline for every read
  25. // and write operation.
  26. type Conn struct {
  27. net.Conn
  28. ReadTimeout time.Duration
  29. WriteTimeout time.Duration
  30. }
  31. func (c *Conn) Read(b []byte) (int, error) {
  32. err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
  33. if err != nil {
  34. return 0, err
  35. }
  36. return c.Conn.Read(b)
  37. }
  38. func (c *Conn) Write(b []byte) (int, error) {
  39. err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
  40. if err != nil {
  41. return 0, err
  42. }
  43. return c.Conn.Write(b)
  44. }
  45. func NewListener(addr string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
  46. l, err := net.Listen("tcp", addr)
  47. if err != nil {
  48. return nil, err
  49. }
  50. tl := &Listener{
  51. Listener: l,
  52. ReadTimeout: readTimeout,
  53. WriteTimeout: writeTimeout,
  54. }
  55. return tl, nil
  56. }

huangapple
  • 本文由 发表于 2016年4月22日 06:44:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/36781707.html
匿名

发表评论

匿名网友

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

确定