Socket.IO是一個基于WebSocket的實時通信庫债查,在主流平臺都有很好的支持蜕琴,此文主要是通過一個小例子來演示Socket.IO的使用娱颊。
基礎(chǔ)環(huán)境搭建
新建一個文件夾(JS工程)拦耐,創(chuàng)建一個package.json弯蚜,復(fù)制以下內(nèi)容并保存十籍。
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"dependencies": {}
}
然后執(zhí)行npm命令蛆封,安裝我們需要的依賴(Express和Socket.IO), 請確保你電腦已經(jīng)有node環(huán)境
在項目根目錄也就是package.json所在的目錄在終端執(zhí)行以下命令
npm install --save express@4.10.2
npm install --save socket.io
進(jìn)度條讀完后會多這么一個文件夾勾栗,此時Express和Socket.IO就已經(jīng)安裝好了惨篱,這和iOS的Cocopods差不多,以模塊化進(jìn)行加載围俘。
然后新建一個index.js作為服務(wù)端砸讳,再建一個index.html作為客戶端。(為了方便演示界牡,我這里有兩個客戶端簿寂,一個是iOS端,一個是瀏覽器端)
index.html
這也是官方Demo的演示界面宿亡,UI上沒做修改
代碼如下
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/',function(req,res){
res.sendfile(__dirname + '/index.html');
});
http.listen(3000,function () {
console.log('listien 3000');
});
開啟了一個Server常遂,監(jiān)聽3000端口,然后回到項目根目錄挽荠,在終端輸入
node index.js
如果出現(xiàn)listen 3000則表明服務(wù)開啟成功了烈钞,此時在瀏覽器訪問
http://localhost:3000
就能看到index.html頁面了
iOS客戶端的集成
新建一個iOS工程,在終端cd到項目根目錄創(chuàng)建一個Podfile文件
vim Podfile
復(fù)制以下內(nèi)容
use_frameworks!
target 'SocketIO_Chat_Example' do #項目名
pod 'Socket.IO-Client-Swift', '~> 8.2.0'
end
保存退出坤按,執(zhí)行命令安裝依賴
pod install
or pod install --verbose --no-repo-update
請確保已經(jīng)有cocopods環(huán)境
iOS端的UI
使用Socket.IO
此時我們的客戶端和服務(wù)端都已經(jīng)有了Socket.IO的環(huán)境了毯欣,接下來就是使用它進(jìn)行聊天了。
Socket.IO中事件的處理主要通過這兩個方法來實現(xiàn)的
on(_ event: String, callback: NormalCallback)
emit(_ event: String, _ items: AnyObject...)
on方法為接收事件的方法臭脓,emit為發(fā)送事件的方法
我們的需求是讓瀏覽器和iOS客戶端進(jìn)行單聊
服務(wù)端的處理
要想發(fā)送到指定的客戶端酗钞,需要知道當(dāng)前客戶端的id(Socket.IO的id,例:3t60BArlK47a2fA-AAAd),但是客戶端并不清楚砚作,客戶端只知道我們自己定義的id,所以我們要將Socket.IO的Id和我們自己定義的id綁定并存儲起來窘奏。
var socketArray = new Array();
io.on('connection', function(socket){
var islogin = false;
console.log('**********新加入了一個用戶*********',socket.id);
socket.on('login',function (userId) {
if(islogin) return;
socket.userId = userId;
socketArray.push(socket);
islogin = true;
});
socket.on('privateMessage',function (data) {
console.log(data);
})
socket.on('chat message', function(data){
var to = data.toUser;
var message = data.message;
for(var i = 0;i<socketArray.length;i++){
var receiveData = socketArray[i];
if (receiveData.userId == to){
io.to([receiveData.id]).emit('privateMessage',''+receiveData.userId+':'+message);
}
}
});
socket.on('disconnect',function () {
console.log('***********用戶退出登陸************,'+socket.id);
})
});
客戶端的處理
瀏覽器的處理
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
socket.emit('login','30621');
$('form').submit(function(){
socket.emit('chat message',{'toUser':'30342','message':$('#m').val()} );
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
socket.on('privateMessage',function (msg) {
$('#messages').append($('<li>').text(msg));
});
</script>
iOS端的處理
iOS在初始化的時候需要一個config字典,config可以配置諸如log日志輸出等設(shè)置
- (SocketIOClient *)client{
if (!_client) {
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:3000"];
_client = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @YES, @"forcePolling": @YES}];
}
return _client;
}
- (void)connection{
[self.client on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
NSLog(@"*************\n\niOS客戶端上線\n\n*************");
[self.client emit:@"login" with:@[@"30342"]];
}];
[self.client on:@"chat message" callback:^(NSArray * _Nonnull event, SocketAckEmitter * _Nonnull ack) {
if (event[0] && ![event[0] isEqualToString:@""]) {
[self.messageArray insertObject:event[0] atIndex:0];
[self.messageTableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
}
}];
[self.client on:@"privateMessage" callback:^(NSArray * _Nonnull event, SocketAckEmitter * _Nonnull ack) {
if (event[0] && ![event[0] isEqualToString:@""]) {
[self.messageArray insertObject:event[0] atIndex:0];
[self.messageTableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
}
}];
[self.client on:@"disconnect" callback:^(NSArray * _Nonnull event, SocketAckEmitter * _Nonnull ack) {
NSLog(@"*************\n\niOS客戶端下線\n\n*************%@",event?event[0]:@"");
}];
[self.client on:@"error" callback:^(NSArray * _Nonnull event, SocketAckEmitter * _Nonnull ack) {
NSLog(@"*************\n\n%@\n\n*************",event?event[0]:@"");
}];
[self.client connect];
}
//按鈕點擊事件
- (IBAction)sendMessage:(id)sender {
if (self.inputView.text.length>0) {
[self.client emit:@"chat message" with:@[@{@"toUser":@"30621",@"message":self.inputView.text}]];
[self.messageArray insertObject:self.inputView.text atIndex:0];
[self.messageTableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
self.inputView.text = @"";
}
}