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();//阻止默认行为
    }
}
相关推荐
今天也想MK代码1 天前
基于WebRTC的实时语音对话系统:从语音识别到AI回复
人工智能·webrtc·语音识别
红米饭配南瓜汤4 天前
WebRTC中的几个Channel
网络协议·音视频·webrtc·媒体
腾讯云音视频4 天前
AI实时对话的通信基础,WebRTC技术综合指南
人工智能·webrtc
achene_ql8 天前
WebRTC:去中心化网络P2P框架解析
网络·去中心化·webrtc·p2p
唯独失去了从容8 天前
WebRTC通信原理与流程
webrtc
拧螺丝专业户9 天前
外网访问内网海康威视监控视频的方案:WebRTC + Coturn 搭建
音视频·webrtc·监控视频
唯独失去了从容10 天前
WebRTC 源码原生端Demo入门-1
webrtc
eguid_110 天前
WebRTC流媒体传输协议RTP点到点传输协议介绍,WebRTC为什么使用RTP协议传输音视频流?
java·网络协议·音视频·webrtc·实时音视频
eguid_111 天前
WebRTC工作原理详细介绍、WebRTC信令交互过程和WebRTC流媒体传输协议介绍
java·音视频·webrtc·实时音视频
程序猿阿伟11 天前
《探索React Native社交应用中WebRTC实现低延迟音视频通话的奥秘》
react native·音视频·webrtc