青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2016年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910


專注即時通訊及網(wǎng)游服務(wù)端編程
------------------------------------
Openresty 官方模塊
Openresty 標(biāo)準(zhǔn)模塊(Opm)
Openresty 三方模塊
------------------------------------
本博收藏大部分文章為轉(zhuǎn)載,并在文章開頭給出了原文出處,如有再轉(zhuǎn),敬請保留相關(guān)信息,這是大家對原創(chuàng)作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 222040
  • 排名 - 117

最新評論

閱讀排行榜

http://www.tuicool.com/articles/zYfAnea


最近實現(xiàn)一個二維碼掃描登錄的功能,當(dāng)用戶用移動設(shè)備掃描PC端頁面的二維碼之后,移動設(shè)備通過常規(guī)HTTP短連接向服務(wù)器獲取認(rèn)證數(shù)據(jù),認(rèn)證通過后,服務(wù)器向PC瀏覽器主動推送帳號相關(guān)信息以完成PC端頁面的登錄。

服務(wù)器主動向瀏覽器推送數(shù)據(jù),基本上就是ajax輪詢、iframe stream、websocket等等,可以參見 《Comet (web技術(shù))》

推送服務(wù)器有很多種,當(dāng)然用強大穩(wěn)定又順手的nginx了。 nginx相關(guān)的推送插件模塊有nginx-push-stream-module、nginx_http_push_module,但是很遺憾,可配置不可編程。又到我們的主角 OpenResty (OpenResty (aka. ngx_openresty) is a full-fledged web application server by bundling the standard Nginx core, lots of 3rd-party Nginx modules, as well as most of their external dependencies)出馬的時候了。

1、PC瀏覽器向php發(fā)起ajax請求,獲取一個與當(dāng)前session相關(guān)的唯一的二維碼URL,和一個唯一的sub訂閱URL。

2、PC瀏覽器顯示二維碼,并對sub訂閱URL發(fā)起ajax長連接或者websocket連接,這個請求將直接由nginx來hold住,超時時間由配置參數(shù)push_free_timeout決定。

3、手機端掃描并解析二維碼,向php發(fā)起認(rèn)證。

4、php收到移動設(shè)備的請求后,解出sessionid,向nginx的pub接口發(fā)布數(shù)據(jù),該數(shù)據(jù)將被直接投遞到對應(yīng)的sub接口,并回傳到瀏覽器。

5、如果sub接口在push_free_timeout指定的時間內(nèi)一直沒有收到數(shù)據(jù),將主動斷開與瀏覽器端的連接。此時,瀏覽器可以根據(jù)業(yè)務(wù)場景決定是否重新發(fā)起連接。

出于性能考慮,使用ngx.shared共享內(nèi)存存儲消息,只能共享于一個ngx實例內(nèi),對于10k級別的聊天室并發(fā)連接應(yīng)該是夠用了。
使用redis作為外部存儲,也是可以的,如果100k的并發(fā),需要注意ngx對nosql發(fā)起連接時耗盡socket,當(dāng)然這個是可以解決的。
更大規(guī)模的并發(fā),值得自研推送服務(wù)器。

在生產(chǎn)環(huán)境某個LB節(jié)點上試運行過,openresty跑著waf\fastcgi proxy\http proxy\comet。常態(tài)1k并發(fā)連接數(shù),load 0.01,40k并發(fā)時,load只有0.15。

下面是相關(guān)測試代碼,如果有空完善了再托管到github上,考慮寫一個聊天室的完整demo。

resty.push基礎(chǔ)模塊(需要使用到ngx.shared共享內(nèi)存來存儲消息,在nginx.conf的http段配置lua_shared_dict push 10m;)

--[[
-- /usr/local/openresty/lualib/resty/push.lua
-- push.lua ,resty.push 基于nginx_lua的push推送方案
-- 支持多對多頻道 
-- 支持long-pooling, stream, websocket
--
-- Author: chuyinfeng.com <Liujiaxiong@kingsoft.com> 
-- 2014.03.12
--]]

local _M = {_VERSION = '0.01'}

local function debug(msg)
  --ngx.say(msg)
  --ngx.flush(true)
end

-- 配置信息
_M.config = {
  -- 推送間隔,1s
  ['push_interval'] = 1,
  -- 消息隊列最大長度
  ['msglist_len'] = 100,
  -- 消息生存周期
  ['msg_lefttime'] = 3,
  -- 頻道空閑超時
  ['channel_timeout'] = 30,
  -- 推送空閑超時,在改時間段內(nèi)無消息則關(guān)閉當(dāng)前推送連接
  ['push_free_timeout'] = 10,
  -- 共享內(nèi)存名
  ['store_name'] = 'push',
  -- 頻道號
  ['channels'] = {1, 2},
}


-- 頻道數(shù)量
_M.channels_len = 0
-- 當(dāng)前讀位置
_M.idx_read = 0
-- 共享內(nèi)存
_M.store = nil


-- cjson 模塊
local cjson = require "cjson"

--[[ 
-- 設(shè)置
--]]
_M.opt = function(self, k, v)
  local t = type(k)
  if t == 'table' then
    for key, val in pairs(k) do
      self.config[key] = val
    end
  end

  if t == 'string' then
    self.config[k] = v
  end

  self.channels_len = table.maxn(self.config['channels'])
  self.store = ngx.shared[self.config['store_name']]

end


--[[
-- 向頻道寫入消息
--
-- @param ngx.shared.dict, 共享內(nèi)存
-- @param string channel_id,可用ngx.crc32_long生成
-- @param int channel_timeout, 頻道空閑超時時間
-- @param string msg,消息內(nèi)容 必須為字符串
-- @param int msg_lefttime, 消息生存周期
-- @param int msglist_len, 消息隊列長度
-- @return boolean
--]]
local function _write(store, channel_id, channel_timeout, msg, msg_lefttime, msglist_len)
  local idx, ok, err

  -- 消息當(dāng)前讀取位置計數(shù)器+1
  idx, err = store:incr(channel_id, 1)

  -- 如果異常,則新建頻道
  if err then
    ok, err = store:set(channel_id, 1, channel_timeout)
    if err then return 0 end
    idx = 1
  else
    store:replace(channel_id, idx, channel_timeout)
  end


  -- 寫入消息
  debug("write " .. channel_id .. idx .. " , lefttime: " .. msg_lefttime.. " , msg: " .. msg)
  ok, err = store:set('m' .. channel_id .. idx, msg,  msg_lefttime)
  if err then return 0 end

  -- 清除隊列之前的舊消息
  if idx > msglist_len then
    store:delete('m' .. channel_id .. (idx - msglist_len))
  end

  return idx
end

--[[
-- 從頻道讀取消息
--
-- @param int channel_id, 必須為整形,可用ngx.crc32_long生成
-- @param int offset,歷史偏移量,最小為0
-- @return int len, 剩余消息數(shù)量
-- @return string msg, 消息  
--]]
local _read = function (store, channel_id, msglist_len, idx_read)
  local idx_msg, err, msg

   

  -- 獲取最新消息的位置
  idx_msg, _ = store:get(channel_id)
  idx_msg = idx_msg or 0

  if idx_msg == 0 then
    idx_read = 0
  end
  
  if idx_msg - idx_read > msglist_len then
    idx_read = idx_msg - msglist_len
  end
  
  if idx_read < idx_msg then
    idx_read = idx_read + 1
    msg, _ = store:get('m' .. channel_id .. idx_read) 
  end

  -- 返回讀的位置和消息的最大位置,以及消息
  return idx_read, idx_msg, msg
end

--[[
-- 推送消息
-- @param callback wrapper, 消息包裝回調(diào)函數(shù)
--]]
_M.push = function(self, wrapper)
  local flag_work = true
  local flag_read = true
  local idx_read, idx_msg, msg, err
  local time_last_msg = ngx.time()
  
  while flag_work do
     for i = 1, self.channels_len do
      -- 循環(huán)讀取當(dāng)前頻道,直到EOF
      flag_read = true
      while flag_read do
        debug("read from idx_read: " .. self.idx_read)
        self.idx_read, idx_msg, msg = _read(self.store, self.config['channels'][i], self.config['msglist_len'], self.idx_read)
        if msg ~= nil then
          debug("got msg and wrapper  msg: " .. msg)
          time_last_msg = ngx.time()
          wrapper(msg)
        end
        debug("idx_read: " .. self.idx_read .. ", idx_msg: " .. idx_msg)
        
        if self.idx_read == idx_msg then flag_read = false end
      end
      
    end

    debug("push_free: " .. ngx.time() - time_last_msg)
    if ngx.time() - time_last_msg  >= self.config['push_free_timeout'] then
      debug("push_timeout: " .. " last: " .. time_last_msg .. " , now: " .. ngx.time())
      flag_work = false
    end
    

    debug("sleep: " .. self.config['push_interval'])
    ngx.sleep(self.config['push_interval'])
  end

end

--[[
-- 發(fā)送消息到指定頻道
--]]
_M.send = function(self, msg)
  local idx = 0
  for i = 1, self.channels_len do
    idx = _write(self.store, self.config['channels'][i], self.config['channel_timeout'], msg, self.config['msg_lefttime'], self.config['msglist_len'])
  end
  return true
end

--[[
-- jsonp格式化
--]]
_M.jsonp = function(self, data, cb)
    if cb then
        return cb .. "(" .. cjson.encode(data)  .. ");"
    else
        return cjson.encode(data)
    end
end


--[[
-- 公開成員
--]]

_M.new = function(self)
  return setmetatable({}, { __index = _M })
end

return _M

public發(fā)布

local push = require "resty.push"

local function exit(is_ws)
  if is_ws == nil then ngx.eof() end
  ngx.exit(444)
end
local ok, err = ngx.on_abort(exit)
if err then return end

local pub = push:new()

pub:opt({
  ['channels'] = 123,
  ['push_interval'] = 0.1,
  ['push_free_timeout'] = 27,
})

ngx.req.read_body()
local body, err = ngx.req.get_post_args()
if err then exit() end
if pub:send(body['data'] or '') then
  ngx.header['Content-Type'] = 'text/javascript;charset=UTF-8'
  ngx.status = ngx.HTTP_OK
  ngx.say(pub:jsonp({['status'] = 1}, args['callback']))
end

subscribe 訂閱接口

local push = require "resty.push"

local function exit(is_ws)
  if is_ws == nil then ngx.eof() end
  ngx.exit(444)
end
local ok, err = ngx.on_abort(exit)
if err then return end

local args = ngx.req.get_uri_args()

local sub = push:new()

sub:opt({
  ['channels'] = 123,
  ['push_interval'] = 0.1,
  ['push_free_timeout'] = 27,
})

local wrapper = function(msg)
  ngx.header['Content-Type'] = 'text/javascript;charset=UTF-8'
  ngx.status = ngx.HTTP_OK
  ngx.say(sub:jsonp(msg, args['callback']))
  exit()
end

sub:push(wrapper)
wrapper(sub:jsonp({['status'] = 1, ['tips'] = 'timeout'}))
posted on 2016-08-04 08:55 思月行云 閱讀(4394) 評論(0)  編輯 收藏 引用 所屬分類: Nginx\Openresty
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜久久影院| 免费久久精品视频| 你懂的视频一区二区| 亚洲精品免费在线观看| 午夜精品偷拍| 亚洲欧美日韩精品久久| 国产精品女主播| 亚洲午夜一区二区| 最新亚洲一区| 久久久亚洲高清| 久久福利毛片| 国产欧美日韩另类视频免费观看| 亚洲激情第一区| 一区二区三区在线不卡| 亚洲欧美另类国产| 午夜精品成人在线| 欧美视频在线一区| 一个人看的www久久| 99国内精品久久| 欧美激情第三页| 亚洲精品韩国| 中文av字幕一区| 欧美日韩国产bt| 亚洲人成网站精品片在线观看| 亚洲黄色成人网| 免费日韩视频| 亚洲国产欧美日韩精品| 亚洲激情网站| 欧美日韩成人在线| 一本色道久久综合一区| 亚洲一区二区视频在线观看| 欧美肉体xxxx裸体137大胆| 亚洲剧情一区二区| 亚洲一区二区不卡免费| 国产精品高清在线| 亚洲女人小视频在线观看| 午夜久久久久久| 国产视频一区在线观看| 久久久www免费人成黑人精品| 久久天天躁狠狠躁夜夜爽蜜月| 狠狠色伊人亚洲综合成人| 久久久一区二区| 亚洲国产成人精品女人久久久| 亚洲精品国产视频| 欧美日韩三级| 亚洲一区视频在线观看视频| 久久九九精品99国产精品| 亚洲第一精品福利| 欧美激情在线| 午夜精品久久久久久久99樱桃| 久久人人超碰| 亚洲开发第一视频在线播放| 国产精品国产三级国产aⅴ入口 | 亚洲精品人人| 欧美新色视频| 久久久国产精品一区| 亚洲国产精品一区二区www| 亚洲一区在线免费| 国产午夜精品美女视频明星a级 | 欧美极品aⅴ影院| 亚洲一区二区三区久久| 美女精品在线| 亚洲专区免费| 亚洲黄色有码视频| 欧美少妇一区二区| 久久嫩草精品久久久久| 99日韩精品| 女人香蕉久久**毛片精品| 亚洲综合色激情五月| 伊人久久大香线| 欧美午夜电影网| 裸体素人女欧美日韩| 午夜精品福利电影| 亚洲三级电影全部在线观看高清| 久久精品人人做人人爽| 一区二区三区蜜桃网| 黄色成人av网站| 国产精品伦子伦免费视频| 另类综合日韩欧美亚洲| 午夜精品久久久久久久久久久久久 | 亚洲——在线| 亚洲电影成人| 久久久久久九九九九| 亚洲一区二区三区乱码aⅴ| 亚洲国产免费看| 国产一级揄自揄精品视频| 欧美日韩福利视频| 久久综合狠狠| 欧美在线播放视频| 亚洲一区激情| 在线亚洲欧美| 一区二区免费在线观看| 亚洲国产精品女人久久久| 久久视频在线看| 欧美一二三区精品| 亚洲一区二区在线看| 在线亚洲欧美专区二区| 亚洲人成免费| 亚洲精品资源美女情侣酒店| 亚洲大胆人体视频| 伊人久久噜噜噜躁狠狠躁| 狠狠色丁香久久婷婷综合丁香| 国产精品理论片| 国产精品久久久一区二区| 欧美日韩综合不卡| 欧美日韩三级视频| 欧美日韩免费观看一区| 欧美日韩国产三级| 欧美日韩中国免费专区在线看| 欧美日韩a区| 国产精品v欧美精品v日本精品动漫 | 亚洲大片精品永久免费| 欧美国产日韩视频| 欧美激情精品| 亚洲国产精品久久久久秋霞影院| 欧美电影免费网站| 亚洲国产第一| 亚洲美女中文字幕| 亚洲午夜久久久| 亚洲一区二区三区四区中文| 亚洲一区三区视频在线观看| 午夜影院日韩| 久久综合网络一区二区| 欧美精品导航| 国产精品自拍网站| 好吊日精品视频| 亚洲日韩成人| 亚洲欧美综合v| 久久蜜桃精品| 欧美激情亚洲| 亚洲视频精选| 久久免费99精品久久久久久| 美腿丝袜亚洲色图| 欧美午夜精品| 国色天香一区二区| 亚洲精品欧美一区二区三区| 亚洲欧美日韩另类精品一区二区三区| 欧美一级日韩一级| 欧美18av| 亚洲视频综合在线| 久久综合久久综合久久| 欧美区视频在线观看| 国产麻豆成人精品| 最近中文字幕日韩精品 | 欧美一区二区三区免费大片| 久久人人爽人人| 欧美日韩日韩| 在线观看欧美成人| 亚洲直播在线一区| 欧美xxx成人| 亚洲欧美在线高清| 欧美福利视频在线| 国产一区二区高清| 一本色道久久综合| 免费成人高清| 午夜激情综合网| 欧美日韩综合久久| 亚洲欧洲精品一区二区精品久久久| 这里只有视频精品| 欧美69wwwcom| 篠田优中文在线播放第一区| 免费成人在线视频网站| 国产区精品在线观看| 99国产精品自拍| 欧美激情bt| 久久gogo国模裸体人体| 国产精品啊啊啊| 夜夜嗨av一区二区三区网页| 久久婷婷一区| 亚洲嫩草精品久久| 欧美日韩在线免费视频| 最新日韩欧美| 老司机成人网| 久久国产精品第一页| 国产精品一区一区| 亚洲在线播放电影| 亚洲精品美女在线观看| 免费在线成人av| 亚洲成色777777在线观看影院| 久久精品99国产精品| 亚洲中午字幕| 国产精品社区| 亚欧成人在线| 亚洲欧美精品中文字幕在线| 欧美丝袜一区二区三区| 中文亚洲视频在线| 99综合精品| 欧美色播在线播放| 亚洲天堂av图片| 99视频一区| 欧美午夜国产| 翔田千里一区二区| 亚洲欧美日韩第一区| 国产乱人伦精品一区二区| 午夜精品亚洲一区二区三区嫩草| 一区二区三区回区在观看免费视频| 欧美日韩国产精品自在自线| 99re66热这里只有精品3直播| 亚洲成人在线视频播放| 久久精品一区二区国产|