输入/搜索内容
内置函数
Global
Log
Market
Trade
Account
Futures
Exchange
IO
Network
Storage
Threads
exchange.Go
EventLoop
ctx.subscribe
ctx.poll
ctx.order
ctx.cancel
ctx.orderAsync
ctx.cancelAsync
Subscription
threading
threading.Thread
threading.getThread
threading.mainThread
threading.currentThread
threading.Lock
threading.Condition
threading.Event
threading.Dict
threading.Serve
threading.pending
Thread
ThreadLock
ThreadEvent
ThreadCondition
ThreadDict
Server
TA
Talib
OS
结构体
内置变量与常量
通用约定
交易所

在策略进程内创建Http服务、TCP服务、Websocket服务(基于Http协议),返回Server对象。

Serve(serveURI, handler)
Serve(serveURI, handler, ...args)

示例

  • 启动一个Http服务,并从主线程请求它。

    javascript
    function main() { var server = threading.Serve("http://127.0.0.1:8088", function (ctx) { ctx.write("hello " + ctx.path()) }) Log("serve on", server.addr()) // 输出:serve on 127.0.0.1:8088 Log(HttpQuery("http://127.0.0.1:8088/ping")) // 输出:hello /ping server.close() }
  • 在一个进程内启动Http(含WebSocket)和TCP回显服务,并逐一测试。

    javascript
    function main() { let httpServer = threading.Serve("http://:8088?gzip=true", function (ctx) { Log("http connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) let path = ctx.path() if (path == "/") { ctx.write(JSON.stringify({ path: ctx.path(), method: ctx.method(), headers: ctx.headers(), cookie: ctx.header("Cookie"), remote: ctx.remoteAddr(), query: ctx.rawQuery() })) } else if (path == "/tickers") { let ret = exchange.GetTickers() if (!ret) { ctx.setStatus(500) ctx.write(GetLastError()) } else { ctx.write(JSON.stringify(ret)) } } else if (path == "/wss") { if (ctx.upgrade("websocket")) { // upgrade to websocket while (true) { let r = ctx.read(10) if (r == "") { break } else if (r) { if (r == "ticker") { ctx.write(JSON.stringify(exchange.GetTicker())) } else { ctx.write("not support") } } } Log("websocket closed", ctx.remoteAddr()) } } else { ctx.setStatus(404) } }) let echoServer = threading.Serve("tcp://:8089", function (ctx) { Log("tcp connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) while (true) { let d = ctx.read() if (!d) { break } ctx.write(d) } Log("connect closed") }) Log("http serve on", httpServer.addr(), "tcp serve on", echoServer.addr()) for (var i = 0; i < 5; i++) { if (i == 2) { // test Http var retHttp = HttpQuery("http://127.0.0.1:8088?num=123&limit=100", {"debug": true}) Log("retHttp:", retHttp) } else if (i == 3) { // test TCP var tcpConn = Dial("tcp://127.0.0.1:8089") tcpConn.write("Hello TCP Server") var retTCP = tcpConn.read() Log("retTCP:", retTCP) } else if (i == 4) { // test Websocket var wsConn = Dial("ws://127.0.0.1:8088/wss|compress=gzip") wsConn.write("ticker") var retWS = wsConn.read(1000) Log("retWS:", retWS) // no depth wsConn.write("depth") retWS = wsConn.read(1000) Log("retWS:", retWS) } Sleep(1000) } httpServer.close() echoServer.close() }

返回值

类型描述

Server对象

返回Server对象。用addr()获取实际监听的IP地址、端口,例如:127.0.0.1:8088、0.0.0.0:8089;用close()、stop()关闭服务。

参数

名称类型必填描述

serveURI

string

是

服务的协议、绑定地址、端口和可选设置,例如http://0.0.0.0:8088?gzip=true、tcp://127.0.0.1:6666;写法见备注。

handler

function

是

路由处理函数(Http协议)、消息处理函数(TCP协议)、Stream处理函数(Websocket)。每个TCP连接、每个Http请求都在独立的线程中调用一次该函数。
参数handler传入的回调函数可以定义多个参数,第一个参数为ctx对象(上下文对象)。

arg

string / number / bool / object / array / function / any

否

传给回调函数handler的额外实参,可以有多个,依次对应回调函数中ctx之后的参数。

参考

备注

  • 该函数仅支持JavaScript语言策略。
  • 处理函数与Thread创建的线程一样运行在隔离环境中,不能引用外部变量、闭包或自定义函数,需要的数据通过...args传入;可以调用平台所有的API函数。ThreadDict、ThreadLock等对象也可以作为参数传入,与其它线程共享数据。
  • Http服务每个连接只处理一个请求,处理函数中ctx.write()写入的内容在函数返回后一次性发送。
  • 每个服务同时执行的处理函数最多64个,超出时Http请求返回503,TCP连接直接断开。
  • 策略停止时服务自动关闭;需要提前关闭时调用返回对象的close()或stop()。
  • Websocket服务基于Http协议实现,可以在path中设置一个路由分支,设计Websocket消息订阅/推送的实现代码,可以参考本节范例代码。
  • 旧的全局函数__Serve()仍然可以使用,参数相同,返回值是监听地址字符串,相当于threading.Serve(...).addr();新代码请使用threading.Serve()。

参数handler传入的回调处理函数接收一个ctx参数。ctx参数为一个上下文对象,用于获取数据和写入数据,有以下方法:

  • ctx.proto()
    应用于Http/TCP协议,调用时返回协议名称。例如:HTTP/1.1、tcp。
  • ctx.host()
    应用于Http协议,调用时返回主机信息:IP地址、端口。
  • ctx.path()
    应用于Http协议,调用时返回请求路径。
  • ctx.query(key)
    应用于Http协议,调用时返回请求中query查询中key对应的值。例如发送的请求为:http://127.0.0.1:8088?num=123,参数handler传入的回调处理函数中ctx.query("num")调用时返回"123"。
  • ctx.rawQuery()
    应用于Http协议,调用时返回请求中的原始查询(Http请求的query)。
  • ctx.headers()
    应用于Http协议,调用时返回请求中的请求头信息。
  • ctx.header(key)
    应用于Http协议,调用时返回指定的请求头中的某个key对应的值。例如获取当前请求的headers中的User-Agent:ctx.header("User-Agent")。
  • ctx.method()
    应用于Http协议,调用时返回请求方法,例如GET、POST等。
  • ctx.body()
    应用于Http协议的POST请求,调用时返回请求的正文。
  • ctx.setHeader(key, value)
    应用于Http协议,设置应答报文的请求头信息。
  • ctx.setStatus(code)
    应用于Http协议,设置Http报文状态码,通常在路由分支最后设置Http状态码,默认为200。
  • ctx.remoteAddr()
    应用于Http/TCP协议,调用时返回请求中的远程客户端地址、端口。
  • ctx.localAddr()
    应用于Http/TCP协议,调用时返回服务本地地址、端口。
  • ctx.upgrade("websocket")
    应用于基于Http协议的Websocket协议实现,切换ctx上下文对象为Websocket协议;切换成功返回布尔值(真),失败返回布尔值(假)。
  • ctx.read(timeout_ms)
    应用于基于Http协议的Websocket协议实现/TCP协议,读取Websocket连接的数据,TCP连接的数据,普通Http协议中不支持使用该read方法;可以指定超时时间参数timeout_ms,单位毫秒。超时返回null,对方关闭连接返回空字符串""。
  • ctx.write(s)
    应用于Http/TCP协议,用于写入字符串数据,可以使用JSON.stringify()编码JSON对象为字符串之后写入。对于WebSocket协议,可以使用该方法将编码后的字符串传递给客户端。

serveURI参数的写法:

  • 协议前缀只支持tcp://(TCP服务)和http://(HTTP服务)。WebSocket服务也用http://,在处理函数中调用ctx.upgrade("websocket")切换。
  • IP可以省略,写成http://:8088表示监听所有网卡;端口写0时随机分配空闲端口,实际地址用返回对象的addr()获取。
  • ?后面可以加gzip=true(启用gzip压缩)、tls=true(启用TLS加密:Https、wss、TLS加密的TCP)。启用TLS时必须同时用cert_pem和cert_key_pem传入PEM格式的证书和私钥(内容需要URL编码),例如http://:8443?tls=true&cert_pem=xxxx&cert_key_pem=xxxx;Https服务写成http://加tls=true。

arg参数的用法:下面调用Serve()时传入的1、2、3依次成为回调函数的参数a、b、c。

javascript
threading.Serve("http://:8088", function(ctx, a, b, c) { Log(`ctx.host():`, ctx.host(), ", a=", a, ", b=", b, ", c=", c) }, 1, 2, 3)