1. 程式人生 > 其它 >從gin的啟動開始看socket是如何在go伺服器中建立的

從gin的啟動開始看socket是如何在go伺服器中建立的


從gin的啟動開始看socket是如何在伺服器中建立的:
gin -> net/http -> net -> internal/syscall -> syscall -> runtime
通過上面的呼叫流程,可以看出,http是對net的封裝,方便開發者呼叫,實際建立Socket的還是net庫,底層已經是到了go的syscall和runtime庫了。
最終呼叫的還是作業系統提供的socket介面。這就是socket建立的流程。

具體流程涉及的檔案以及程式碼:
router.go

r := gin.New()
r.Run(address) // host:port

  

github.com\gin-gonic\[email protected]\gin.go

err = http.ListenAndServe(address, engine)

  

Go\src\net\http\server.go

// Go net/http包
return server.ListenAndServe()
ln, err := net.Listen("tcp", addr) // http也是對net的封裝
if err != nil {
return err
}

  

Go\src\net\dial.go

return lc.Listen(context.Background(), network, address)
l, err = sl.listenTCP(ctx, la)

  

Go\src\net\tcpsock_posix.go

fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", sl.ListenConfig.Control)

  

Go\src\net\ipsock_posix.go

return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn) // 出現socket函數了

  

Go\src\net\sock_posix.go

// socket returns a network file descriptor that is ready for
// asynchronous I/O using the network poller.

s, err := sysSocket(family, sotype, proto)

  

Go\src\net\sock_windows.go

s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto),nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT)

  


Go\src\net\hook_windows.go

wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket // windows.WSASocket就是返回的socket

  

Go\src\internal\syscall\windows\zsyscall_windows.go

// 可以看到檔案已經跳轉到internal資料夾下的系統相關呼叫目錄
func WSASocket(af int32, typ int32, protocol int32, protoInfo *WSAProtocolInfo, group uint32, flags uint32) (handle Handle, err error) {
  r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protoInfo)), uintptr(group), uintptr(flags))
  handle = Handle(r0)
  if handle == InvalidHandle {
    err = errnoErr(e1)
  }
  return
}

  

=== r0 start ===
C:\Program Files\Go\src\syscall\dll_windows.go

// 可以看到檔案已經跳轉到syscall系統呼叫目錄,dll_windows名稱也可看出該檔案底層呼叫的是windos系統提供的介面。
// Implemented in ../runtime/syscall_windows.go.
// 註釋中是說繼承於../runtime/syscall_windows.go檔案中的Syscall6,這個寫法比較特殊,是go1.14剛出的,go:linkname,有興趣的可以繼續深入這個寫法,這裡不做贅述。
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)

  


C:\Program Files\Go\src\runtime\syscall_windows.go

//go:linkname syscall_Syscall6 syscall.Syscall6
//go:nosplit
//go:cgo_unsafe_args
func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
  lockOSThread()
  defer unlockOSThread()
  c := &getg().m.syscall
  c.fn = fn
  c.n = nargs
  c.args = uintptr(noescape(unsafe.Pointer(&a1)))
  cgocall(asmstdcallAddr, unsafe.Pointer(c))
  return c.r1, c.r2, c.err
}

  

=== r0 end ===