diff --git a/g/net/ghttp/ghttp_request.go b/g/net/ghttp/ghttp_request.go index 739925c77..0d301da9c 100644 --- a/g/net/ghttp/ghttp_request.go +++ b/g/net/ghttp/ghttp_request.go @@ -58,7 +58,6 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { return request } - // 初始化GET请求参数 func (r *Request) initGet() { if !r.parsedGet.Val() { @@ -82,6 +81,17 @@ func (r *Request) initPost() { } } +// 获取Web Socket连接对象 +func (r *Request) WebSocket() (*WebSocket, error) { + if conn, err := wsUpgrader.Upgrade(r.Response.ResponseWriter.ResponseWriter, &r.Request, nil); err == nil { + return &WebSocket { + conn, + }, nil + } else { + return nil, err + } +} + // 获得指定名称的参数字符串(GET/POST),同 GetRequestString // 这是常用方法的简化别名 func (r *Request) Get(k string) string { diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 9aaf931b2..ee2cdf69b 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -24,6 +24,7 @@ import ( "gitee.com/johng/gf/g/os/gspath" "gitee.com/johng/gf/g/os/gfile" "gitee.com/johng/gf/g/os/genv" + "github.com/gorilla/websocket" ) const ( @@ -48,7 +49,6 @@ type Server struct { methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充) servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象) - signalQueue chan os.Signal // 终端命令行监听队列 // 服务注册相关 hmmu sync.RWMutex // handler互斥锁 hmcmu sync.RWMutex // handlerCache互斥锁 @@ -98,7 +98,7 @@ type HandlerItem struct { router *Router // 注册时绑定的路由对象 } -// http注册函数 +// HTTP注册函数 type HandlerFunc func(r *Request) // 文件描述符map @@ -107,13 +107,11 @@ type listenerFdMap map[string]string // Server表,用以存储和检索名称与Server对象之间的关联关系 var serverMapping = gmap.NewStringInterfaceMap() -// Web Server多进程管理器 -var procManager = gproc.NewManager() +// Web Socket默认配置 +var wsUpgrader = websocket.Upgrader{} -// Web Server开始执行事件通道,由于同一个进程支持多Server,因此该通道为非阻塞 -var readyChan = make(chan struct{}, 100000) // Web Server已完成服务事件通道,当有事件时表示服务完成,当前进程退出 -var doneChan = make(chan struct{}, 100000) +var doneChan = make(chan struct{}, 1000) // Web Server进程初始化 func init() { @@ -159,7 +157,6 @@ func GetServer(name...interface{}) (*Server) { sessionIdName : gtype.NewString(gDEFAULT_SESSION_ID_NAME), servedCount : gtype.NewInt(), closeQueue : gqueue.New(), - signalQueue : make(chan os.Signal), logPath : gtype.NewString(), accessLogEnabled : gtype.NewBool(), errorLogEnabled : gtype.NewBool(true), diff --git a/g/net/ghttp/ghttp_server_admin.go b/g/net/ghttp/ghttp_server_admin.go index 37c1202a3..95610013d 100644 --- a/g/net/ghttp/ghttp_server_admin.go +++ b/g/net/ghttp/ghttp_server_admin.go @@ -156,7 +156,7 @@ func forkReloadProcess(newExeFilePath...string) { if len(newExeFilePath) > 0 { path = newExeFilePath[0] } - p := procManager.NewProcess(path, os.Args, os.Environ()) + p := gproc.NewProcess(path, os.Args, os.Environ()) // 创建新的服务进程,子进程自动从父进程复制文件描述来监听同样的端口 sfm := getServerFdMap() // 将sfm中的fd按照子进程创建时的文件描述符顺序进行整理,以便子进程获取到正确的fd @@ -195,7 +195,7 @@ func forkRestartProcess(newExeFilePath...string) { os.Unsetenv(gADMIN_ACTION_RELOAD_ENVKEY) env := os.Environ() env = append(env, gADMIN_ACTION_RESTART_ENVKEY + "=1") - p := procManager.NewProcess(path, os.Args, env) + p := gproc.NewProcess(path, os.Args, env) if _, err := p.Start(); err != nil { glog.Errorfln("%d: fork process failed, error:%s", gproc.Pid(), err.Error()) } diff --git a/g/net/ghttp/ghttp_server_handler.go b/g/net/ghttp/ghttp_server_handler.go index e23cd4585..4e5b86bef 100644 --- a/g/net/ghttp/ghttp_server_handler.go +++ b/g/net/ghttp/ghttp_server_handler.go @@ -117,17 +117,20 @@ func (s *Server)serveFile(r *Request, path string) { } info, _ := f.Stat() if info.IsDir() { - // 处理访问目录 + // 处理index files if len(s.config.IndexFiles) > 0 { for _, file := range s.config.IndexFiles { - fpath := path + gfile.Separator + file - if gfile.Exists(fpath) { + // 这里使用s.paths来检索,而不是直接使用path,避免多目录检索情况 + // 例如:/tmp目录及源码目录都存在的情况按照优先级会返回/tmp,但是index files只在源码目录中存在 + fpath := s.paths.Search(r.URL.Path + gfile.Separator + file) + if fpath != "" { f.Close() s.serveFile(r, fpath) return } } } + // 处理访问目录 if s.config.IndexFolder { s.listDir(r, f) } else { diff --git a/g/net/ghttp/ghttp_server_websocket.go b/g/net/ghttp/ghttp_server_websocket.go new file mode 100644 index 000000000..b40096aa9 --- /dev/null +++ b/g/net/ghttp/ghttp_server_websocket.go @@ -0,0 +1,14 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + + +package ghttp + +import "github.com/gorilla/websocket" + +type WebSocket struct { + *websocket.Conn +} \ No newline at end of file diff --git a/geg/net/ghttp/websocket/echo/index.html b/geg/net/ghttp/websocket/echo/index.html new file mode 100644 index 000000000..1accbfdfb --- /dev/null +++ b/geg/net/ghttp/websocket/echo/index.html @@ -0,0 +1,93 @@ + + + + gf websocket echo server + + + + +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/geg/net/ghttp/websocket/echo/main.go b/geg/net/ghttp/websocket/echo/main.go new file mode 100644 index 000000000..3f88e5beb --- /dev/null +++ b/geg/net/ghttp/websocket/echo/main.go @@ -0,0 +1,25 @@ +package echo + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/net/ghttp" +) + +func main() { + s := g.Server() + s.BindHandler("/ws", func(r *ghttp.Request) { + conn, _ := r.WebSocket() + for { + msgType, msg, err := conn.ReadMessage() + if err != nil { + return + } + if err = conn.WriteMessage(msgType, msg); err != nil { + return + } + } + }) + s.SetPort(8199) + s.Run() +} +