Golang 中国

想在一台机器上部署多个网站,使用nginx作为域名分发以及静态文件的访问比较方便。

在处理动态请求使用proxy_pass 转发给go处理。

这里的问题是net/http貌似只能监听tcp的端口,我这里想使用unix socket file的方式来做数据交换,

这样就不用在去tcp/ip这个协议里跑一回了,(当然对普通应用开销可以忽略,我暂时也是这样做的)。

只是想等高手赐教,能否使用socket file的方式?


Roy 于 2013-12-12 16:41 修改
6 回复
rn2dy
#1 rn2dy • 2013-12-13 04:09

不确定你这样做的目的是什么,不过我觉得可以实现。你学要用 unix domain socket 和 Go 的 net.UnixConn.

在你的 nginx 配置文件里:

http {
  server {
    listen 8080;
    server_name localhost;
    location /static {
      proxy_pass http://unix:/tmp/fileserver.socket;
    }
  }
}

Go 代码

package main

import (
  "fmt"
  "net"
)

func createUnixDomainSocketFileServer(){
  addr, err := net.ResolveUnixAddr("unix", "/tmp/fileserver.socket")
  if err != nil {
    panic("Cannot resolve unix addr: " + err.Error())
  }
  listener, err := net.ListenUnix("unix", addr)
  if err != nil {
    panic("Cannot listen to unix domain socket: " + err.Error())
  }
  fmt.Println("Listening on", listener.Addr())
  for {
    c, err := listener.Accept()
    if err != nil {
      panic("Accept: " + err.Error())
    }
    defer c.Close()
    buf := make([]byte, 10480)
    nr, err := c.Read(buf)
    if err != nil {
      panic("Read: " + err.Error())
    }
    var responseData []byte
    // 这里,你需要 parse buf 里的数据来决定返回什么给客户端
    // 假设 respnoseData 是你想返回的文件内容     
    _, err = c.Write(responseData)
    if err != nil {
      panic("Writes failed.")
    }
  }
}

func main() {
  // 启动服务器
  createUnixDomainSocketFileServer()
}

注意, 必须保证 go 程序启动 under root user! 否则 nginx 将无法对 fileserver.socket 进行写操作.

Roy
#2 Roy • 2013-12-13 10:32

多谢2楼。

因为我的go应用是使用net/http来做的,我想知道对于http这个包来说能让他直接去监听unix socket吗,如果要自己去用net包写一套监听方法,那就确实没必要了。

我测试过,http包貌似只能去监听tcp的端口,不支持读取unix socket的方式。不过我还是来这里问下,因为我对go也是新手

gihnius
#3 gihnius • 2013-12-13 12:33

net/http 没有支持 socket 的方法:

1608 l, e := net.Listen("tcp", addr) 使用的是 tcp

或者你改写一下 net/http

 1603   func (srv *Server) ListenAndServe() error {
 1604       addr := srv.Addr
 1605       if addr == "" {
 1606           addr = ":http"
 1607       }
 1608       l, e := net.Listen("tcp", addr)
 1609       if e != nil {
 1610           return e
 1611       }
 1612       return srv.Serve(l)
 1613   }
gihnius
#4 gihnius • 2013-12-13 12:34

但是 net 包是支持 socket 的

Roy
#5 Roy • 2013-12-13 12:46

哈哈,就是刚才又重新浏览下net/http包的api, 终于找到了这个东西 http://golang.org/pkg/net/http/#Server.Serve

os.Remove(SockFile)
listener, e := net.Listen("unix", SockFile)
if e != nil {
    L.Fatal("failed to start listening", e)
}
defer listener.Close()

S = &http.Server{Handler: R}
L.Println(S.Serve(listener))

然后nginx 使用 proxy_pass http://unix:/run/potato.socket;

看来go的设计还是很不错滴

真是开心

lazycat
#6 lazycat • 2017-09-11 16:37

5楼好,看了你说的试了几把,我的电脑上回报502的错误(自己电脑装了nginx),网上搜了下,按照下面两个链接给的描述改过了,仍是502

https://gist.github.com/teknoraver/5ffacb8757330715bcbcc90e6d46ac74

https://github.com/golang/go/issues/11822

请问,你有碰到过吗

需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。