Python网络套接字(许多对等连接)



文件:websocket_server.py

import asyncio
import websockets
import json
import ssl
peers = ()

async def on_open(websocket,path):
async for message in websocket:
message = json.loads(message)
if(message["type"]=="register"):
await register(websocket,message["username"])
elif(message["type"]=="offer"):
await send_offer(websocket,message)
elif(message["type"]=="answer"):
await send_answer(websocket,message)
elif(message["type"]=="candidate"):
await send_candidate(websocket,message)
await unregister(websocket)

async def register(websocket,username):
global peers
print(username+" logged in.")
peers = peers + ((websocket,username),)
for peer in peers:
if peer[0] is not websocket:
await websocket.send(json.dumps({"type": "create_peer","username":peer[1]}))
async def send_offer(websocket,message):
global peers
offer_creator = message["from"]
offer_receiver = message["to"]
offer = message["offer"]
print(offer_creator+" creates and sends offer to "+offer_receiver)
for peer in peers:
if(peer[1]==offer_receiver):
await peer[0].send(json.dumps({"type": "offer","username":offer_creator,"offer":offer}))

async def send_answer(websocket,message):
global peers
answer_creator = message["from"]
answer_receiver = message["to"]
answer = message["answer"]
print(answer_creator+" creates and sends answer to "+answer_receiver)
for peer in peers:
if(peer[1]==answer_receiver):
await peer[0].send(json.dumps({"type": "answer","username":answer_creator,"answer":answer}))

async def send_candidate(websocket,message):
global peers
candidate_creator = message["from"]
candidate_receiver = message["to"]
candidate = message["candidate"]
print(candidate_creator+" send candidate packet to "+candidate_receiver)
for peer in peers:
if(peer[1]==candidate_receiver):
await peer[0].send(json.dumps({"type": "candidate","username":candidate_creator,"candidate":candidate}))

async def unregister(websocket):
global peers
for peer_1 in peers:
if(peer_1[0]==websocket):
username = peer_1[1]
print(username+" logged out.")
for peer_2 in peers:
if(peer_2[0] is not websocket):
await peer_2[0].send(json.dumps({"type": "unregister","username":username}))

peers_list = list(peers)
peers_list.remove((websocket,username))
peers = tuple(peers_list)


ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context = None
start_server = websockets.serve(on_open, "127.0.0.1", 8080)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

文件index.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Audio Calls</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="main.js"></script>
<style type="text/css">
.video{
border:2px solid black;
position:relative;
}

video{

}

.username{
border-top:2px solid black;
text-align:center;
font-weight:bold;
}
</style>
</head>
<body>

</body>
</html>

文件main.js

var ws_url = "ws://127.0.0.1:8080"
var ws = new WebSocket(ws_url);
var pcs = [];
var peer_connections = 0;
var constraints = {audio: true,video: true};
function makeid(length) {
var result           = '';
var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
var local_username;
$(document).ready(function(){
local_username = makeid(5);
ws.onopen = () => ws.send(JSON.stringify({"type":"register","username":local_username}));
})
var signal_in_progress;
ws.onmessage = async function (event) {
var signal = JSON.parse(event.data);
if(signal.type=="create_peer"){
username = signal.username;
create_peer(username);
//console.log("Creating peer for: "+username);
}else if(signal.type=="offer"){
receive_offer(signal);
}else if(signal.type=="answer"){
receive_answer(signal);
//console.log("Receiving answer from peer: "+signal.username)
}else if(signal.type=="candidate"){
receive_candidate(signal);
}else if(signal.type=="unregister"){
unregister(signal);
}
}
async function create_peer(username){
pc = new RTCPeerConnection();
stream = await navigator.mediaDevices.getUserMedia(constraints);
pc.addStream(stream);

pc.onaddstream = function(event) {
make_video_element(event.stream,username)
};

pc.createOffer(function(offer) {
pc.setLocalDescription(offer, function() {
data = {"type":"offer","from":local_username,"to":username,"offer":offer}
ws.send(JSON.stringify(data));
}, fail);
}, fail);

pc.onicecandidate = function(event) {
if (event.candidate) {
data = {"type":"candidate","from":local_username,"to":username,"candidate":event.candidate}
ws.send(JSON.stringify(data));
}
};

pcs[peer_connections] = [username,pc];
peer_connections = peer_connections+1;
}
async function receive_offer(signal){
username = signal.username;
offer = signal.offer;

pc = new RTCPeerConnection();
stream = await navigator.mediaDevices.getUserMedia(constraints);
pc.addStream(stream);

pc.onaddstream = function(event) {
make_video_element(event.stream,username)
};

pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
data = {"type":"answer","from":local_username,"to":username,"answer":answer}
ws.send(JSON.stringify(data));
}, fail);
}, fail);
}, fail);

pc.onicecandidate = function(event) {
if (event.candidate) {
data = {"type":"candidate","from":local_username,"to":username,"candidate":event.candidate}
ws.send(JSON.stringify(data));
}
};

pcs[peer_connections] = [username,pc];
peer_connections = peer_connections+1;

}
async function receive_answer(signal){
username = signal.username;
answer = signal.answer;
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
pcs[i][1].setRemoteDescription(new RTCSessionDescription(answer));
}
}
}
async function receive_candidate(signal){
username = signal.username;
candidate = signal.candidate;
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
pcs[i][1].addIceCandidate(new RTCIceCandidate(candidate));
}
}
}
async function unregister(signal){
username = signal.username;
index = 0
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
pcs[i][1].close();
document.getElementById(username).style.display = "none";
document.getElementById(username).getElementsByTagName("video")[0].pause();
index = i;
break;
}
}

pcs.splice(index, 1);
peer_connections = peer_connections-1;

}

function make_video_element(stream,username){
var video_container = document.createElement("div");
video_container.id = username;
video_container.classList.add("video");

var video = document.createElement("video");
video.srcObject = stream;
video_container.appendChild(video);

var username_element = document.createElement("div");
username_element.classList.add("username");
username_element.innerHTML = username;
video_container.appendChild(username_element);

document.body.appendChild(video_container);
video.play();
}
function fail(error){
console.log(error);
}

以上代码适用于一个连接(发送-接收(。但如果我打开三个标签,就会出现问题。我不知道问题集中在哪里。你能帮我吗?

我发现错误:

main.js

var ws_url = "ws://127.0.0.1:8080"
var ws = new WebSocket(ws_url);
var pcs = [];
var peer_connections = 0;
var constraints = {audio: true,video: true};
function makeid(length) {
var result           = '';
var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
var local_username;
$(document).ready(function(){
local_username = makeid(5);
ws.onopen = () => ws.send(JSON.stringify({"type":"register","username":local_username}));
})
var signal_in_progress;
ws.onmessage = async function (event) {
var signal = JSON.parse(event.data);
if(signal.type=="create_peer"){
username = signal.username;
create_peer(username);
}else if(signal.type=="offer"){
receive_offer(signal);
}else if(signal.type=="answer"){
receive_answer(signal);
}else if(signal.type=="candidate"){
receive_candidate(signal);
}else if(signal.type=="unregister"){
unregister(signal);
}
}
async function create_peer(username){
pc = new RTCPeerConnection();
var pc_index = peer_connections;
pcs[pc_index] = [username,pc];

peer_connections = peer_connections+1;
stream = await navigator.mediaDevices.getUserMedia(constraints);
pcs[pc_index][1].addStream(stream);

pcs[pc_index][1].onaddstream = function(event) {
make_video_element(event.stream,username)
};

console.log(pc_index);
pcs[pc_index][1].createOffer(function(offer) {
pcs[pc_index][1].setLocalDescription(offer, function() {
data = {"type":"offer","from":local_username,"to":username,"offer":offer}
console.log("Offer to: "+username);
ws.send(JSON.stringify(data));
}, fail);
}, fail);

pcs[pc_index][1].onicecandidate = function(event) {
if (event.candidate) {
data = {"type":"candidate","from":local_username,"to":username,"candidate":event.candidate}
ws.send(JSON.stringify(data));
}
};


}
async function receive_offer(signal){
username = signal.username;
offer = signal.offer;

pc = new RTCPeerConnection();
pc_index = peer_connections;
pcs[pc_index] = [username,pc];
peer_connections = peer_connections+1;
stream = await navigator.mediaDevices.getUserMedia(constraints);
pcs[pc_index][1].addStream(stream);

pcs[pc_index][1].onaddstream = function(event) {
make_video_element(event.stream,username)
};

pcs[pc_index][1].setRemoteDescription(new RTCSessionDescription(offer), function() {
pcs[pc_index][1].createAnswer(function(answer) {
pcs[pc_index][1].setLocalDescription(answer, function() {
data = {"type":"answer","from":local_username,"to":username,"answer":answer}
ws.send(JSON.stringify(data));
}, fail);
}, fail);
}, fail);

pcs[pc_index][1].onicecandidate = function(event) {
if (event.candidate) {
data = {"type":"candidate","from":local_username,"to":username,"candidate":event.candidate}
ws.send(JSON.stringify(data));
}
};



}
async function receive_answer(signal){
username = signal.username;
answer = signal.answer;
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
console.log("Accept answer");
console.log(username);
console.log(i)
pcs[i][1].setRemoteDescription(new RTCSessionDescription(answer));
}
}
}
async function receive_candidate(signal){
username = signal.username;
candidate = signal.candidate;
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
pcs[i][1].addIceCandidate(new RTCIceCandidate(candidate));
}
}
}
async function unregister(signal){
username = signal.username;
index = 0
for(var i=0;i<peer_connections;i++){
if(pcs[i][0]==username){
pcs[i][1].close();
document.getElementById(username).style.display = "none";
document.getElementById(username).getElementsByTagName("video")[0].pause();
index = i;
break;
}
}

pcs.splice(index, 1);
peer_connections = peer_connections-1;

}

function make_video_element(stream,username){
var video_container = document.createElement("div");
video_container.id = username;
video_container.classList.add("video");

var video = document.createElement("video");
video.srcObject = stream;
video_container.appendChild(video);

var username_element = document.createElement("div");
username_element.classList.add("username");
username_element.innerHTML = username;
video_container.appendChild(username_element);

document.body.appendChild(video_container);
video.play();
}
function fail(error){
console.log(error);
}

可能是由于以下原因造成的错误:peer_connections变量在创建offer之前发生了更改,因为正在尝试创建另一个offer。

编辑:对于想要在本地网络中实现上述代码的人,还请注意,必须在每个对等端关闭windows defender防火墙。

最新更新