SlideShare a Scribd company logo
1 of 87
Download to read offline
Eventmachine
Websocket實戰
慕凡@Ruby Tuesday-28 2014/1/7
講者⾃自介
• Tomlan Workshop(http://tomlan.tw)創辦⼈人	

• RubyConf Taiwan/Ruby Taiwan社群主辦⼈人	

• Rails Girls Taiwan社群主辦⼈人	

• Ruby經驗7年	

• Github/Twitter: ryudoawaru	

• http://ryudo.tw
主題
• 什麼是Websocket	

• Ruby的Websocket解決⽅方案介紹	

• EventMachine::Websocket實戰	

• Deploy平台介紹	

• 多⾏行程伺服器實作
HTTP 1.0
Client
open
close
open
close

Server
HTTP 1.1
Client
open

close

Server
http特性
• 無狀態(stateless)	

• 每次request間無關聯	

• 單向連線	

• 從client端發request, 單向
不適⽤用場合
• 頻率很⾼高, 但每次response都很⼩小	

• 需要由server主動push的場合
以前的解決⽅方案
Client Interval Polling
都2014年了,你不覺得這樣很 ____ 嗎?	

(by 製了2年杖的⼈人)
Long-Polling
•
•
•

最⾼高相容性	

⻑⾧長時間連線容易佔⽤用Server端資源	

衍⽣生物	


•
•

Rails 4 Live Streaming(Server sent Events)	

Comet
Flash Socket們
• 沒有flash不能⽤用→iOS GG	

• SSL相容性問題	

• server端通常需要依賴3rd party元件	

• 地雷機率⾼高	

•

http://juggernaut.rubyforge.org/ →被炸過	


• 可是瑞凡我不會寫flash
Websocket
(RFC6455)
真‧Server Push
W3C規範
(⺫⽬目前版本Draft20發展中)
http://www.w3.org/TR/2012/CR-websockets-20120920/
廣泛的瀏覽器⽀支援
(除了IE, 但是有相容解決⽅方案)
有SSL
(雖然我沒試過)
幾乎所有語⾔言/平台都有⾄至
少Client端實作
EventMachine
⼀一個基於Reactor設計模式的、⽤用於網絡編程和並發
編程的框架
EventMachine
• 事件驅動式	

• 延遲執⾏行	

• 抽象Thread或Fiber	

• 抽象socket處理	

• 通⽤用CRuby/JRuby(我沒試過)
EventMachine::Websocket
Why EventMachine
C10K issue

https://github.com/shokai/sinatra-websocketio/wiki/
C10K
經實測證明,普通的
實體伺服器上單⼀一⾏行
程可負擔超過10k的同
時連線
(請按上⾴頁連結指⽰示服⽤用,請勿在MacOS試)
EM:Websocket實戰
Hello Websocket!
Client
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script>
$(document).ready(function(){
ws = new WebSocket("ws://localhost:28080");
ws.onmessage = function(evt) {
$("#msg").append("<p> NEW message: "+evt.data+"</p>"); };
ws.onclose = function() { console.log("socket closed"); };
ws.onopen = function() {
console.log("connected...");
ws.send("hello server");
};
});
</script>
</head>
<body>
<div id="debug"></div>
<div id="msg"></div>
</body>
</html>

WS URL
Server
require 'em-websocket'
trap(:INT){EM.stop}
EM.run do
connections = []
EM::WebSocket.run(:host => "0.0.0.0", :port => 28080) do |ws|
ws.onopen do |handshake|
puts "New connection"
connections << ws
end
ws.onclose do
connections.delete(ws)
end
ws.onmessage do |msg|
puts "Message coming: #{msg}"
connections.each{|conn| conn.send(msg) }
end
end
end

連線池
特性
• Client/Server端具備相同的事件	

• 原⽣生Javascript物件⽀支援	

• 事件驅動
事件
名稱

作⽤用

C/S端

onopen

連接成功時

共通

onmessage

接收到訊息時

共通

onclose

連線關閉

共通

onerror

發⽣生錯誤時

Server only
methods of WS object
• send(msg)	

• 送訊息	

• ping	

• 測試對⽅方⽣生存狀況	

• close	

• 關閉連線
handshake object on open

• 相當於⼀一般http的request object	

• 有path/host/user-agent/cookie等內容	

• 根據瀏覽器/draft版本不同會有些許差異
連接流程說明
1. 從http端得到html和javascript	

2. Javascript發起WS連線	

3. 連線成功	

4. Client端送訊息給WS端	

5. WS端收到後把訊息送給所有Client端
流程
Server

Client

onopen

start
onopen

onmessage

•invoke to every clients in room	

•iteration

send
onmessage

onclose

close
onclose
這樣就結束了?
案情有這麼單純嗎?
Production issues
• IE issue	

• authentication	

• channel identification	

• non-block message passing
IE問題
• Flash Websocket	

• https://github.com/gimite/web-socket-js	

• 完全相容所有原⽣生Javascript API	

• 需要policy file在port 843, EM已內建	

• Flash版本需>10	

• 連線前置有點慢,⼀一次傳太多資料會卡
authentication issue
•
•

通常無法和http⼀一起掛在port 80(後⾯面說明)	


•
•

WS連線固定為GET,無法POST	


•

唯⼀一能安全地做⽂文章的地⽅方剩下WS連線的URL

即使掛在相同port,有的瀏覽器會視為corss
domain不給cookie	


WS有提供連線時可選的 protocols參數,但不是
所有瀏覽器都⽀支援
典型連線⽅方式
1. 連線http端時已驗證⾝身份	

2. http端在render⾴頁⾯面時,提供特定的WS
URL供連線⽤用,並在此時於後端告知WS
端URL和user⾝身份對應	

3. client端使⽤用這個URL連線	

4. WS端確認⾝身份,接受連線	

5. 將該連線加到「連線池」內
⽰示例-http端
get '/rooms/:room_name.html' do
@ws_url = gen_ws_url
...........
erb "index.html".to_sym
end
def gen_ws_url
hkey = SecureRandom.hex(24) #亂數產⽣生URL後綴
#在REDIS中設定URL對應USER
redis.hsetnx("keys-#{current_room.db_name}".to_sym, hkey, current_member.uid)
sprintf 'ws://%s:%d%s', request.host, params[:ws_port], "/update-service/
#{current_room.db_name}-#{hkey}"
end
#產⽣生:ws://hostanme:port/update-service/group_item_1f938455d50b0228fee500f1a15b8bc2f42974a0e38a1e71c
WS端
#GET /update-service/group_item_1-f938455d50b0228fee500f1a15b8bc2f42974a0e38a1e71c
EventMachine::WebSocket.start(:host => options[:host], :port => 8080) do |ws|
ws.onopen do |request|
if request.path =~ //update-service/(.+)-(.+)/
#$1 為
current_room = Room.where(:db_name => $1).first
rhkey = "keys-#{current_room.db_name}".to_sym
#由之前設好的Redis Hash中由正確的key對應拉出UID, ⾝身份辨認完成
current_member = Discuz::Member.find_by_uid(redis.hget(rhkey,$2))
unless current_member
ws.close
end
redis.hdel rhkey, params[:hkey] #⽴立刻刪key以避免被重複使⽤用
$connections << ws
#將連線加到connections pool內
ws.close
end
end
end
non-block message
passing
由於單⼀一⾏行程要負擔過萬
連線,如何在傳遞訊息時
不阻塞其它處理變成最重
要的事項。
場景:在收到某個client端的訊息後,
將該訊息傳給所有client端
ws.onmessage do |ws_msg|
msg = current_room.messages.create(JSON.parse(ws_msg))
EM.next_tick do
$connections.each do |conn|
conn.send(render_messages([msg]))
end
end
end

EM.next_tick將send排⼊入
背景執⾏行
Reactor程式撰寫原則
事件處理要⼩小不要卡
會卡的事丟到
next_tick或defer
會卡I/O的最好找有EM
包裝的相關實作
Architecture / Framework
Issue
Websocket整合⽅方案分類
Websocket App⾓角⾊色
1. http frontend	

• 負責串接後端與client端的proxy⾓角⾊色	

• 處理「髒連線」等任務	

2. http app server	

• 處理普通的http	

3. websocket app server	

• 主要差別在附屬在http內或是分開
純websocket⾓角⾊色
• EM:Websocket	

• faye-websocket
整合現有http framework
• Sinatra-Websocket	

• Rack-Websocket	

• Goliath	

• Cramp
前後端整合
• 除了web framework外,封裝包括
Javascript	


• Websocket-Rails	

• Rocket-IO
你該選擇哪⼀一種?
考量點
• scalability	

• 套件更新頻率與熱⾨門度	

• 套件和app server的綁定問題
scalability
• http和WS是否住在同⼀一個⾏行程?	

• 是否可依需要分別調整WS或http端的⾏行
程數
套件熱⾨門度
• WS在Ruby圈不是主流	

• 除了EM以外的套件⼤大都更新緩慢或是學
術研究性質產品
app server綁定
• EM:其實⾃自⼰己就是App server	

• 多數會綁定thin	

• ex:sinatra-websocket	

• 有的會⾃自⼰己另外⽤用EM產⽣生WS專⽤用⾏行程	

• ex:Rocket-IO
Production
Environment
Deployment
Http Frontend Proxy
為何需要
• Backend Load Balance	

• app server未必能處理request buffer / dirty
connection等問題
⺫⽬目前主流
• nginx	

• 注意:要1.4版以上	

• haproxy	

• 最早開始⽀支援
nginx
server {
server_name xxx.tw;
listen 443;
location / {
access_log logs/xxx-ws-access.log;
proxy_pass http://localhost:12850;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 30;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
}
haproxy
frontend public	

bind *:443	

timeout client 1800s	

acl is_websocket hdr(Upgrade) -i WebSocket	

use_backend ws if is_websocket	

default_backend www	

!
backend www	

option forwardfor	

timeout server 30s	

server ws1 127.0.0.1	

!
backend ws	

option forwardfor	

timeout server 1800s	

server ws2 127.0.0.1:12850
主要差異
• nginx無法在同⼀一vhost & location內分別
reverse proxy http & WS	


-

其實可以⽤用if辨認header達成,但是會有ifisEvil
問題(http://wiki.nginx.org/IfIsEvil)	


• haproxy無法做為http file server,等於是
多⼀一層
Port issue
• 80 port	

• transparent proxy issue	

• 443 port	

• 最安全,幾乎不會被擋,也不會被
proxy	


• Port > 1000	

• 有機會被client端防⽕火牆檔
結論
• 即使和http在同vhost & port,由於cookie
不⼀一定能被瀏覽器認可,故不需強求	


• nginx / haproxy 的穩定性都很好,視需求
與現有環境狀況決定	


• listen在443也不⼀一定要有SSL,所以443最
安全
同場加映:
Websocket Load
Balancer
如果事業做很⼤大
同時連線達數萬?
解決之道
• Multi-Process	

•
•

fork	

⼀一個⼀一個開	


•
•

Ruby有GIL/GVL,無法使⽤用超過⼀一個核⼼心	


• Multi-Thread	

JRuby OK!
Multi-Process issue
Worker A

Worker B

Worker C

Massive	

Clients
問題
• 每個⾏行程有⾃自⼰己的連線池	

• 每個⾏行程不知道其它⾏行程的連線	

• 當⾏行程A收到訊息,B/C不會知道
Master-Workers
(fork model)

fork
Master

fork

Worker A

Worker B

fork
Worker C
fork model
• for Unix Like OS only	

• 由⽗父⾏行程fork出⼦子⾏行程	

• ⼦子⾏行程有和⽗父⾏行程⼀一樣的記憶體內容	

• ⾏行程間的記憶體不互通	

• ⾏行程間共享fork前已開啟的IO	

• 由Copy on Write⽅方式節省未變更記憶體
使⽤用(Ruby 2.0+ feature)
onmessage流程變更
1. Client傳訊給Woker A,Worker A收到訊息	

2. Worker A通知Master有新訊息	

3. Master通知所有Workers	

4. Workers對各⾃自所屬連線發出訓息
程序說明
Master

3

Worker C

4

Worker B

4

2

Worker A

1

4

Massive Clients

A Client
傳統⾏行程間傳遞訊息的⽅方式
in unix like system

• pipe	

• unix socket	

• shared memory
以上都不是事件驅動
式,撰寫不易
解法1:Websocket on
Websocket
解法2.Redis Pub-Sub
• 頻道 (Channel) 和訂閱者(Subscriber)的概念	

• 和Websocket本質類似,但更⽅方便使⽤用	

• 訂閱單位為頻道	

• ⼀一旦有⼈人向頻道發出訊息(Publish),訂閱者
會收到通知
Example
#Publisher
$redis = Redis.new
data = {"user" => ARGV[1]}
loop do
msg = STDIN.gets
$redis.publish ARGV[0], data.merge('msg' => msg.strip).to_json
end

#Subscriber
$redis = Redis.new(:timeout => 0)
$redis.subscribe('rubyonrails', 'ruby-lang') do |on|
puts "開始subscribe"
on.message do |channel, msg|
data = JSON.parse(msg)
puts "##{channel} - [#{data['user']}]: #{data['msg']}"
end
end
訂閱⽅方式
• Master頻道	

• 訂閱者:Master	

• 由Worker發訊息通知Master	

• Child頻道	

• 訂閱者:Workers	

• Master由Master頻道收到訊息後,從此
處發給Worker們
r2p = Redis.new #Publisher⽤用連線
EventMachine.run do
emredis = EM::Hiredis.connect# Subscriber⽤用
pids = 2.times do |pi|
pid = fork do#############FORK START#####################
EventMachine::WebSocket.start(.....) do |ws|
ws.onopen do |request|
...
ws.onmessage do |ws_msg|
#1. Client傳訊給worker
msg = current_room.messages.create(...)
#2. 向master channel通知有新訊息
r2p.publish 'master', msg.id.to_s
end
emredis.pubsub.subscribe('child') do |mid|/
msg = Message.find(mid)
EM.next_tick do#4. worker們得到master傳來的新訊息,傳給⾃自⼰己的clients
$connections[current_room.db_name.to_sym].each do |s|
s.send(render_messages([msg]))
end
end
end
end
end
end#############FORK END#####################
end
emredis.pubsub.subscribe('master') do |msg|
r2p.publish('child', msg)#3. MASTER得到訊息,通知workers
end
end
要點
• Publisher需要⽤用普通Redis Client	

• Subscriber要⽤用EM::HiRedis Client	

• Master頻道訂閱需在fork之後	

• Child頻道需要在fork內訂閱
End	


http://ryudo.tw

More Related Content

What's hot

凌波微步:wagon + VS Code 的輕功哲學
凌波微步:wagon + VS Code 的輕功哲學凌波微步:wagon + VS Code 的輕功哲學
凌波微步:wagon + VS Code 的輕功哲學Shengyou Fan
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩Wen-Tien Chang
 
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來Shengyou Fan
 
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發LaravelConf Taiwan 2017 單頁面應用與前後端分離開發
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發俊仁 陳
 
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境Shengyou Fan
 
給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由Shengyou Fan
 
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹Shengyou Fan
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎Shengyou Fan
 
選一個框架當好朋友,讓您成為開心攻城獅
選一個框架當好朋友,讓您成為開心攻城獅選一個框架當好朋友,讓您成為開心攻城獅
選一個框架當好朋友,讓您成為開心攻城獅Shengyou Fan
 
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊Shengyou Fan
 
開發環境建置
開發環境建置開發環境建置
開發環境建置Shengyou Fan
 
PHP 語法基礎與物件導向
PHP 語法基礎與物件導向PHP 語法基礎與物件導向
PHP 語法基礎與物件導向Shengyou Fan
 
How to choose web framework
How to choose web frameworkHow to choose web framework
How to choose web frameworkBo-Yi Wu
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 SeedingShengyou Fan
 
Laravel - 簡介與環境設定
Laravel - 簡介與環境設定Laravel - 簡介與環境設定
Laravel - 簡介與環境設定Vincent Chi
 

What's hot (20)

凌波微步:wagon + VS Code 的輕功哲學
凌波微步:wagon + VS Code 的輕功哲學凌波微步:wagon + VS Code 的輕功哲學
凌波微步:wagon + VS Code 的輕功哲學
 
Vagrant教學
Vagrant教學Vagrant教學
Vagrant教學
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
 
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
 
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發LaravelConf Taiwan 2017 單頁面應用與前後端分離開發
LaravelConf Taiwan 2017 單頁面應用與前後端分離開發
 
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境
使用 wagon + VS Code 輕鬆打造 Windows 平台 PHP/Laravel 開發環境
 
給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由
 
工作坊簡介
工作坊簡介工作坊簡介
工作坊簡介
 
課程簡介
課程簡介課程簡介
課程簡介
 
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹
COSCUP 2016 Laravel 部署工作坊 - 生態圈介紹
 
驗證與訊息
驗證與訊息驗證與訊息
驗證與訊息
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎
 
選一個框架當好朋友,讓您成為開心攻城獅
選一個框架當好朋友,讓您成為開心攻城獅選一個框架當好朋友,讓您成為開心攻城獅
選一個框架當好朋友,讓您成為開心攻城獅
 
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊
[Modern Web Conf 2015] 給 PHP 開發者的 Composer 錦囊
 
工作坊簡介
工作坊簡介工作坊簡介
工作坊簡介
 
開發環境建置
開發環境建置開發環境建置
開發環境建置
 
PHP 語法基礎與物件導向
PHP 語法基礎與物件導向PHP 語法基礎與物件導向
PHP 語法基礎與物件導向
 
How to choose web framework
How to choose web frameworkHow to choose web framework
How to choose web framework
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
Laravel - 簡介與環境設定
Laravel - 簡介與環境設定Laravel - 簡介與環境設定
Laravel - 簡介與環境設定
 

Similar to Eventmachine Websocket 實戰

Asp.net core v1.0
Asp.net core v1.0Asp.net core v1.0
Asp.net core v1.0國昭 張
 
Nodejs & NAE
Nodejs & NAENodejs & NAE
Nodejs & NAEq3boy
 
Real time web实时信息流推送
Real time web实时信息流推送Real time web实时信息流推送
Real time web实时信息流推送yongboy
 
Real-Time Web实时信息流推送
Real-Time Web实时信息流推送Real-Time Web实时信息流推送
Real-Time Web实时信息流推送yongboy
 
W3CTech美团react专场-React Native 初探
W3CTech美团react专场-React Native 初探W3CTech美团react专场-React Native 初探
W3CTech美团react专场-React Native 初探美团点评技术团队
 
Knowledge sharing
Knowledge sharingKnowledge sharing
Knowledge sharingPeng Wan
 
lua & ngx_lua 的介绍与应用
lua & ngx_lua 的介绍与应用lua & ngx_lua 的介绍与应用
lua & ngx_lua 的介绍与应用hugo
 
WireMock 起飞手册
WireMock 起飞手册WireMock 起飞手册
WireMock 起飞手册Jiyee Sheng
 
实时Web的前世今生未来
实时Web的前世今生未来实时Web的前世今生未来
实时Web的前世今生未来RolfZhang
 
Rest与面向资源的web开发
Rest与面向资源的web开发Rest与面向资源的web开发
Rest与面向资源的web开发topgeek
 
广告技术部自动化测试介绍.pdf
广告技术部自动化测试介绍.pdf广告技术部自动化测试介绍.pdf
广告技术部自动化测试介绍.pdfbj_qa
 
⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨Wen-Tien Chang
 
How to ASP.NET MVC4
How to ASP.NET MVC4How to ASP.NET MVC4
How to ASP.NET MVC4Daniel Chou
 
讓軟體開發與應用更自由 - 使用 Docker 技術
讓軟體開發與應用更自由 - 使用 Docker 技術讓軟體開發與應用更自由 - 使用 Docker 技術
讓軟體開發與應用更自由 - 使用 Docker 技術Yu Lung Shao
 
DAE 新变化介绍
DAE 新变化介绍DAE 新变化介绍
DAE 新变化介绍Tianwei Liu
 
快!快!快! 互联网第一条军规
快!快!快! 互联网第一条军规快!快!快! 互联网第一条军规
快!快!快! 互联网第一条军规yangdj
 

Similar to Eventmachine Websocket 實戰 (20)

Asp.net core v1.0
Asp.net core v1.0Asp.net core v1.0
Asp.net core v1.0
 
Asp.net core v1.0
Asp.net core v1.0Asp.net core v1.0
Asp.net core v1.0
 
Nodejs & NAE
Nodejs & NAENodejs & NAE
Nodejs & NAE
 
Real time web实时信息流推送
Real time web实时信息流推送Real time web实时信息流推送
Real time web实时信息流推送
 
Real-Time Web实时信息流推送
Real-Time Web实时信息流推送Real-Time Web实时信息流推送
Real-Time Web实时信息流推送
 
W3CTech美团react专场-React Native 初探
W3CTech美团react专场-React Native 初探W3CTech美团react专场-React Native 初探
W3CTech美团react专场-React Native 初探
 
Knowledge sharing
Knowledge sharingKnowledge sharing
Knowledge sharing
 
lua & ngx_lua 的介绍与应用
lua & ngx_lua 的介绍与应用lua & ngx_lua 的介绍与应用
lua & ngx_lua 的介绍与应用
 
WireMock 起飞手册
WireMock 起飞手册WireMock 起飞手册
WireMock 起飞手册
 
实时Web的前世今生未来
实时Web的前世今生未来实时Web的前世今生未来
实时Web的前世今生未来
 
Rest与面向资源的web开发
Rest与面向资源的web开发Rest与面向资源的web开发
Rest与面向资源的web开发
 
广告技术部自动化测试介绍.pdf
广告技术部自动化测试介绍.pdf广告技术部自动化测试介绍.pdf
广告技术部自动化测试介绍.pdf
 
Ali-tomcat
Ali-tomcatAli-tomcat
Ali-tomcat
 
⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨
 
How to ASP.NET MVC4
How to ASP.NET MVC4How to ASP.NET MVC4
How to ASP.NET MVC4
 
讓軟體開發與應用更自由 - 使用 Docker 技術
讓軟體開發與應用更自由 - 使用 Docker 技術讓軟體開發與應用更自由 - 使用 Docker 技術
讓軟體開發與應用更自由 - 使用 Docker 技術
 
Meteor
MeteorMeteor
Meteor
 
DAE 新变化介绍
DAE 新变化介绍DAE 新变化介绍
DAE 新变化介绍
 
快!快!快! 互联网第一条军规
快!快!快! 互联网第一条军规快!快!快! 互联网第一条军规
快!快!快! 互联网第一条军规
 
Html5
Html5Html5
Html5
 

More from Mu-Fan Teng

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMu-Fan Teng
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web RubyistsMu-Fan Teng
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年Mu-Fan Teng
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329Mu-Fan Teng
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroMu-Fan Teng
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Mu-Fan Teng
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Mu-Fan Teng
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Mu-Fan Teng
 

More from Mu-Fan Teng (9)

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in Taiwan
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web Rubyists
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 Intro
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012
 
Ruby on discuz
Ruby on discuzRuby on discuz
Ruby on discuz
 

Eventmachine Websocket 實戰