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

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


最近實(shí)現(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)然用強(qiá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、手機(jī)端掃描并解析二維碼,向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實(shí)例內(nèi),對于10k級別的聊天室并發(fā)連接應(yīng)該是夠用了。
使用redis作為外部存儲,也是可以的,如果100k的并發(fā),需要注意ngx對nosql發(fā)起連接時耗盡socket,當(dāng)然這個是可以解決的。
更大規(guī)模的并發(fā),值得自研推送服務(wù)器。

在生產(chǎn)環(huán)境某個LB節(jié)點(diǎn)上試運(yùn)行過,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>
            欧美一级在线播放| 久久综合九色综合久99| 欧美日韩免费视频| 亚洲第一精品影视| 在线观看一区视频| 美女脱光内衣内裤视频久久网站| 久久久免费av| 亚洲欧洲偷拍精品| 欧美日韩一卡二卡| 午夜视频在线观看一区| 久久亚洲色图| 亚洲精品乱码久久久久久按摩观| 欧美大片18| 亚洲麻豆一区| 久久精品中文字幕免费mv| 亚洲国产精品一区二区www在线| 免费观看一级特黄欧美大片| 亚洲毛片一区二区| 久久久噜噜噜| 夜夜嗨av色综合久久久综合网| 欧美日韩国产综合在线| 欧美一激情一区二区三区| 免费亚洲电影在线观看| 一区二区三区高清在线观看| 国产欧美丝祙| 美女久久一区| 亚洲一区二区视频| 欧美www视频| 亚洲综合99| 亚洲区一区二区三区| 国产美女精品在线| 欧美激情第3页| 欧美中文字幕在线视频| 亚洲精品资源美女情侣酒店| 久久国产福利| 亚洲色图综合久久| 一区二区在线不卡| 欧美日韩一区二区三区在线视频| 亚洲综合第一| 亚洲国产一区视频| 久久久午夜精品| 亚洲视频在线观看一区| 亚洲二区免费| 国产一区二区视频在线观看| 欧美成人嫩草网站| 久久精品国产999大香线蕉| 在线亚洲一区观看| 亚洲国产二区| 欧美 日韩 国产 一区| 欧美一二三区精品| 亚洲视频你懂的| 亚洲精品四区| 亚洲黄一区二区| 激情久久一区| 韩国av一区二区三区在线观看| 欧美日韩视频在线一区二区 | 欧美夫妇交换俱乐部在线观看| 亚洲在线观看视频网站| 免费在线欧美视频| 久久久蜜桃精品| 夜夜爽99久久国产综合精品女不卡| 韩国成人福利片在线播放| 国产精品一区二区三区四区五区| 欧美日韩ab| 欧美日韩精品免费观看视频| 每日更新成人在线视频| 久久精品国产一区二区电影 | 欧美高清视频www夜色资源网| 欧美一区二区三区日韩| 欧美亚洲系列| 久久精品国产99国产精品澳门| 午夜在线播放视频欧美| 亚洲欧美一区二区激情| 亚洲欧美日韩区| 亚洲欧美日韩在线综合| 亚洲午夜女主播在线直播| 亚洲午夜电影| 午夜精品久久久久久久蜜桃app| 在线视频日韩精品| 亚洲午夜精品久久久久久app| 一区二区三区视频在线观看| 欧美成人一区二区| 欧美高清hd18日本| 91久久在线播放| 艳女tv在线观看国产一区| 妖精成人www高清在线观看| 亚洲国产日韩欧美在线图片| 亚洲精品国产精品国产自| 99在线热播精品免费| 亚洲自拍偷拍色片视频| 亚洲欧美国产精品桃花| 亚洲曰本av电影| 亚洲欧美在线观看| 久久嫩草精品久久久久| 噜噜噜噜噜久久久久久91| 欧美久久在线| 国产精品久久一卡二卡| 韩日精品视频一区| 在线免费观看成人网| 亚洲成色精品| 一本久久a久久精品亚洲| 午夜精品一区二区三区在线播放| 欧美综合激情网| 久久久91精品国产一区二区三区 | 国产欧美日韩不卡免费| 国产一区二区精品丝袜| 在线看日韩av| 亚洲性人人天天夜夜摸| 久久久久成人网| 久久精品国产亚洲aⅴ| 久久这里有精品视频| 亚洲精品看片| 午夜精品福利视频| 欧美99在线视频观看| 国产精品国产三级国产aⅴ浪潮 | 99精品视频免费全部在线| 翔田千里一区二区| 欧美久久九九| 精品福利电影| 亚洲一区欧美二区| 欧美成人小视频| 99视频一区| 久久久国产精品一区二区中文 | 欧美日韩精品免费看| 黄色亚洲网站| 亚洲自拍啪啪| 久久精品中文字幕免费mv| 亚洲精品极品| 亚洲欧美日韩精品在线| 欧美成人免费网站| 欧美日韩视频在线一区二区观看视频 | 久久这里有精品视频| 国产精品久久999| 亚洲精品免费在线| 亚洲免费在线看| 欧美高清hd18日本| 亚洲综合国产激情另类一区| 欧美大胆a视频| 国内精品美女av在线播放| 亚洲一区二区网站| 亚洲大胆美女视频| 午夜精品福利一区二区三区av| 欧美激情综合色| 尤物99国产成人精品视频| 欧美在线黄色| 亚洲图片欧美日产| 欧美调教视频| 亚洲精品欧美极品| 免费看av成人| 久久久久久电影| 国产精品亚洲аv天堂网| 一本色道久久综合狠狠躁篇的优点 | 亚洲精品免费在线| 欧美1区2区3区| 最近中文字幕日韩精品| 久久久av水蜜桃| 欧美一区二视频在线免费观看| 欧美激情精品| 亚洲韩国青草视频| 欧美激情精品久久久久久黑人| 亚洲欧美成aⅴ人在线观看| 欧美精品久久99久久在免费线| 在线观看成人网| 六十路精品视频| 久久久久久久高潮| 红桃视频欧美| 免费成人高清| 欧美xxx成人| 亚洲精品久久久久| 欧美福利专区| 欧美日韩1080p| 亚洲一区二区三区色| 99精品视频一区| 欧美视频中文字幕在线| 亚洲性感激情| 亚洲你懂的在线视频| 国产精品ⅴa在线观看h| 亚洲午夜久久久| 一区二区三区 在线观看视| 国产精品日韩欧美一区二区三区 | 亚洲国产精品第一区二区三区| 欧美二区在线观看| 中文在线一区| 亚洲欧美日韩中文视频| 国产精品成人一区二区网站软件 | 欧美一区二区播放| 午夜欧美大片免费观看| 狠狠狠色丁香婷婷综合激情| 欧美暴力喷水在线| 欧美刺激性大交免费视频 | 亚洲午夜久久久久久久久电影院 | 亚洲精品中文字| 国产精品国产三级国产aⅴ无密码| 亚洲综合国产| 欧美在线综合| 日韩一二三区视频| 日韩一区二区免费看| 国产精品综合不卡av| 久久久久www| 欧美风情在线观看|