WebRtc08:WebRtc信令服务器实现

如何使用socket.io发送消息

发送消息

js 复制代码
// 给本次连接发送消息
socket.emit()

// 给某个房间内所有人发送消息
io.in(room).emit()

// 除了自己以外,给某个房间的所有人发消息
socket.to(room).emit();

// 除本连接外,给所有人发消息
socket.broadcast.emit();

客户端处理消息

js 复制代码
// 发送action命令:服务端发送消息,客户端监听并执行对应的func
S: socket.emit('action');
C: socket.on('action', function(){...});

// 发送一个action命令,并携带data数据
S: socket.emit('action', data);
C: socket.on('action', function(data){...});

// 发送一个action命令,并携带两个数据
S: socket.emit('action', arg1, arg2);
C: socket.on('action', function(arg1, arg2){...});

// 发送一个action命令,在emit方法中包含回调函数
S: socket.emit('action', data, function(arg1, arg2){...});
C: socket.on('action', function(data, fn){fn('a', 'b');});

WebRtc信令服务器原理

信令服务器的作用

具体看第九章

为什么要使用socket.io

  • socket.io是websocket的超集
  • socket.io有房间的概念,不需要做额外的操作
  • socket.io跨平台,跨终端,跨语言

socket.io工作原理

实战

改造服务端

安装socket.io和log4js

shell 复制代码
npm install socket.io log4js

最新版本的socket.io是4.8.1,需要考虑和2版本的兼容性,很多API都变了

引入socket.io

处理connection消息

js 复制代码
'use strict'
var http = require('http');
var https = require('https');
var fs = require('fs');

var express = require('express');
var serveIndex = require('serve-index');
var app = express();
app.use(serveIndex('./public'));
app.use(express.static('./public'));

// 引入socket.io
const { Server } = require('socket.io');

// 引入log4js日志
var log4js = require('log4js');
log4js.configure({
    appenders: {
        file: {
            type: 'file',
            filename: 'app.log',
            layout: {
                type: 'pattern',
                pattern: '%r %p - %m',
            }
        }
    },
    categories: {
        default: {
            appenders: ['file'],
            level: 'debug'
        }
    }
});
var logger = log4js.getLogger();

// http server
var http_server = http.createServer(app);
http_server.listen(8080, '0.0.0.0');

var options = {
    key :   fs.readFileSync('/ssl/cert.key'),
    cert :  fs.readFileSync('/ssl/cert.pem')
}

var https_server = https.createServer(options, app);
// 绑定socket.io
var io = new Server(https_server);

io.sockets.on('connection', (socket)=>{
    console.log('客户端已连接', socket.id);
    socket.on('message', (room, data)=>{
		socket.to(room).emit('message', room, socket.id, data)//房间内所有人,除自己外
	});

	//该函数应该加锁
	socket.on('join', (room)=> {

		socket.join(room);

		// var myRoom = io.sockets.adapter.rooms[room]; 旧版api
		// var users = Object.keys(myRoom.SocketId).length;

        const socketIds = io.sockets.adapter.rooms.get(room); // 使用 Map 的 get 方法
        const users = socketIds ? socketIds.size : 0; // 处理空房间或不存在的情况

		logger.log('the number of user in room is: ' + users);

		//在这里可以控制进入房间的人数,现在一个房间最多 2个人
		//为了便于客户端控制,如果是多人的话,应该将目前房间里
		//人的个数当做数据下发下去。
		if(users < 3) {
			socket.emit('joined', room, socket.id);	
			if (users > 1) {
				socket.to(room).emit('otherjoin', room);//除自己之外
			}
		}else {
			socket.leave(room);
			socket.emit('full', room, socket.id);	
		}
	 	//socket.to(room).emit('joined', room, socket.id);//除自己之外
		//io.in(room).emit('joined', room, socket.id)//房间内所有人
	 	//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点	
	});

	socket.on('leave', (room)=> {
        const socketIds = io.sockets.adapter.rooms.get(room); // 使用 Map 的 get 方法
        const users = socketIds ? socketIds.size : 0; // 处理空房间或不存在的情况

		//users - 1;

		logger.log('the number of user in room is: ' + (users-1));

		socket.leave(room);
		socket.to(room).emit('bye', room, socket.id)//房间内所有人,除自己外
	 	socket.emit('leaved', room, socket.id);	
	 	//socket.to(room).emit('joined', room, socket.id);//除自己之外
		//io.in(room).emit('joined', room, socket.id)//房间内所有人
	 	//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点	
	});
});

//connection
io.sockets.on('connection', (socket)=>{

	socket.on('message', (room, data)=>{
		socket.to(room).emit('message', room, socket.id, data)//房间内所有人
	});

	socket.on('join', (room)=> {
		socket.join(room);
		const socketIds = io.sockets.adapter.rooms.get(room); // 使用 Map 的 get 方法
        const users = socketIds ? socketIds.size : 0; // 处理空房间或不存在的情况

		logger.log('the number of user in room is: ' + users);
	 	socket.emit('joined', room, socket.id);	
	 	//socket.to(room).emit('joined', room, socket.id);//除自己之外
		//io.in(room).emit('joined', room, socket.id)//房间内所有人
	 	//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点	
	});

	socket.on('leave', (room)=> {
		const socketIds = io.sockets.adapter.rooms.get(room); // 使用 Map 的 get 方法
        const users = socketIds ? socketIds.size : 0; // 处理空房间或不存在的情况

		//users - 1;

		logger.log('the number of user in room is: ' + (users-1));

		socket.leave(room);
	 	socket.emit('leaved', room, socket.id);	
	 	//socket.to(room).emit('joined', room, socket.id);//除自己之外
		//io.in(room).emit('joined', room, socket.id)//房间内所有人
	 	//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点	
	});
});

https_server.listen(443, '0.0.0.0', (err) => {
    if (err) {
        console.error('HTTPS server error: ', err);
    } else {
        console.log('HTTPS server is running on port 443');
    }
});

客户端实现简单的聊天室

index.html

html 复制代码
<html>
	<head>
		<title>Chat Room</title>
		<link rel="stylesheet" href="./css/main.css"></link>
	</head>
	<body>
		<table align="center">
			<tr>
				<td>
					<label>UserName: </label>
					<input type=text id="username"></input>
				</td>
			</tr>
			<tr>
				<td>
					<label>room: </label>
					<input type=text id="room"></input>
					<button id="connect">Conect</button>
					<button id="leave" disabled>Leave</button>
				</td>
			</tr>
			<tr>
				<td>
					<label>Content: </label><br>
					<textarea disabled style="line-height: 1.5;" id="output" rows="10" cols="100"></textarea>
				</td>
			</tr>
			<tr>
				<td>
					<label>Input: </label><br>
					<textarea disabled id="input" rows="3" cols="100"></textarea>
				</td>
			</tr>
			<tr>
				<td>
					<button id="send">Send</button>
				</td>
			</tr>
		</table>

		<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.8.1/socket.io.js"></script>
		<script src="./js/client.js"></script>
	</body>

</html>

client.js

js 复制代码
'use strict'

//
var userName = document.querySelector('input#username');
var inputRoom = document.querySelector('input#room');
var btnConnect = document.querySelector('button#connect');
var btnLeave = document.querySelector('button#leave');
var outputArea = document.querySelector('textarea#output');
var inputArea = document.querySelector('textarea#input');
var btnSend = document.querySelector('button#send');

var socket;
var room;

btnConnect.onclick = ()=>{

	//connect
	socket = io.connect(); 
	
	//recieve message
	socket.on('joined', (room, id) => {
		btnConnect.disabled = true;
		btnLeave.disabled = false;
		inputArea.disabled = false;
		btnSend.disabled = false;
	});	
	
	socket.on('leaved', (room, id) => {
		btnConnect.disabled = false;
		btnLeave.disabled = true;
		inputArea.disabled = true;
		btnSend.disabled = true;

		socket.disconnect();
	});	

	socket.on('message', (room, id, data) => {
		outputArea.scrollTop = outputArea.scrollHeight;//窗口总是显示最后的内容
		outputArea.value = outputArea.value + data + '\r';
	});	

	socket.on('disconnect', (socket)=>{
		btnConnect.disabled = false;
		btnLeave.disabled = true;
		inputArea.disabled = true;
		btnSend.disabled = true;
	});

	//send message
	room = inputRoom.value;
	socket.emit('join', room);
}

btnSend.onclick = ()=>{
	var data = inputArea.value;
	data = userName.value + ':' + data;
	socket.emit('message', room, data);
	inputArea.value = '';
}

btnLeave.onclick = ()=>{
	room = inputRoom.value;
	socket.emit('leave', room);
}

inputArea.onkeypress = (event)=> {
    //event = event || window.event;
    if (event.keyCode == 13) { //回车发送消息
	var data = inputArea.value;
	data = userName.value + ':' + data;
	socket.emit('message', room, data);
	inputArea.value = '';
	event.preventDefault();//阻止默认行为
    }
}
相关推荐
桃花岛主701 天前
如何使用WebRTC
webrtc
唯独失去了从容2 天前
WebRTC服务器Coturn服务器的管理平台功能
运维·服务器·webrtc
唯独失去了从容3 天前
WebRTC服务器Coturn服务器中的通信协议
运维·服务器·webrtc
唯独失去了从容4 天前
WebRTC服务器Coturn服务器部署
webrtc
Stupid小池5 天前
webrtc建立连接的过程
webrtc
Paraverse平行云8 天前
如何使用UE Cesium插件实现网页端无算力负担访问?
云原生·webrtc
NodeMedia12 天前
如何用WHIP协议WebRTC推流到NodeMediaServer
webrtc·音视频开发
TSINGSEE12 天前
跨平台嵌入式音视频开发指南:EasyRTC音视频通话的多场景适配与AI扩展能力
人工智能·音视频·webrtc·智能家居
唯独失去了从容13 天前
MacOS下下载和编译webrtc步骤
webrtc