- 浏览: 337076 次
- 性别:
- 来自: 广州
文章分类
最新评论
在上篇文( 基于html5 WebSocket和WebRTC实现IM和视音频呼叫(一))里我们已经用Jetty-7.5.4.v20111024搭起了一个WebSocket server,现在就可以编写自己的WebSocket Server逻辑完成自己的实现了。
一、编写WebSocket服务端逻辑
MyWebSocketServlet类继承自Jetty开发包中的org.eclipse.jetty.websocket.WebSocketServlet类,用于实现我们的WebSocket 服务端入口。前期没有编写太多的服务端逻辑,只是实现了接受并记录所有连接client端,并广播所有client端消息的功能,代码如下:
package com.webrtcserver;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;
public class MyWebSocketServlet extends WebSocketServlet {
private static final long serialVersionUID = -7289719281366784056L;
public static String newLine = System.getProperty("line.separator");
private final Set<TailorSocket> _members = new CopyOnWriteArraySet<TailorSocket>();
public void init() throws ServletException {
super.init();
}
private void broadcastMessage(String msg) {
for (TailorSocket member : _members) {
logs("Trying to send to Member!");
if (member.isOpen()) {
logs("Sending!");
try {
member.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
getServletContext().getNamedDispatcher("default").forward(request,
response);
logs("doGet");
}
public WebSocket doWebSocketConnect(HttpServletRequest request,
String protocol) {
return new TailorSocket();
}
static private int serialNum = 0;
class TailorSocket implements WebSocket.OnTextMessage {
private Connection _connection;
private String sdp;
private String userName;
public void onClose(int closeCode, String message) {
_members.remove(this);
}
public void sendMessage(String data) throws IOException {
_connection.sendMessage(data);
}
public void onMessage(String data) {
logs("Received: " + data);
broadcastMessage(data);
}
public boolean isOpen() {
return _connection.isOpen();
}
public void onOpen(Connection connection) {
userName = String.format("%5d", serialNum++);
_members.add(this);
_connection = connection;
logs("one memner connected!");
try {
connection
.sendMessage("onOpen:Server received Web Socket upgrade and added it to Receiver List.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void logs(String logMessage) {
System.out.println(logMessage);
}
}
TailorSocket 继承自 WebSocket.OnTextMessage,每当一个client连接时就会调用doWebSocketConnect方法实例化一个client对象。
server端通过TailorSocket的_connection.sendMessage(data)方法向client发送文本消息;通过onMessage接收client发送的文本消息,并调用broadcastMessage方法向所有连接的client广播消息。
二、编写Client逻辑
WebSocket对象在不同的浏览器实现稍有区别,为了代码适应更多的浏览器在调用WebSocket对象前需要判断当前的浏览器,然后实现WebSocket的onopen,onmessage,onclose等方法,即可与WebSocket服务端建立连接,具体代码如下:
var server = {
connect : function() {
var location = get_appropriate_ws_url() + "/servlet/a";
if (BrowserDetect.browser == "Firefox") {
this._ws = new MozWebSocket(location, null);
} else {
this._ws = new WebSocket(location, null);
}
this._ws.onopen = this._onopen;
this._ws.onmessage = this._onmessage;
this._ws.onclose = this._onclose;
showLog("connecting...");
},
_onopen : function() {
showLog("connected to server!");
},
_send : function(message) {
if (this._ws)
this._ws.send(message);
},
send : function(text) {
if (text != null && text.length > 0) {
server._send(text);
}
},
_onmessage : function(m) {
if (m.data) {
showMessage("others", m.data);
}
showLog("onmessage");
},
_onclose : function(m) {
this._ws = null;
showLog("onclose");
}
};
下面的test.html和test.js简单实现了群聊聊天室:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset = "utf-8"/>
<title>WebRTC && Web Sockets Demo</title>
<script type="text/javascript" src="JS/test.js"></script>
<style type='text/css'>
div {
border: 0px solid black;
}
div#messageBox {
clear: both;
width: 40em;
height: 20ex;
overflow: auto;
background-color: #f0f0f0;
padding: 4px;
border: 1px solid black;
}
div#logBox {
clear: both;
width: 40em;
height: 20ex;
overflow: auto;
background-color: #f0f0f0;
padding: 4px;
border: 1px solid black;
}
div#input {
clear: both;
width: 40em;
padding: 4px;
background-color: #e0e0e0;
border: 1px solid black;
border-top: 0px
}
div.hidden {
display: none;
}
span.alert {
font-style: italic;
}
</style>
</head>
<body>
<div>
<input id='connect' class='button' type='submit' name='Connect' value='Connect' />
</div>
<div id='messageBox'></div>
<div id='inputButton'>
<input id="inputBox" type="text"/>
<input id="inputButton" type="button" value="SEND"/>
</div>
<div id='logBox'></div>
<script type='text/javascript'>
$('connect').onclick =function(event) {
server.connect();
return false;
};
$("inputButton").onclick = function(event) {
if($("inputBox").value != "") {
server.send($("inputBox").value);
$("inputBox").value = "";
showMessage("me", text);
}
return false;
}
</script>
</body>
</html>
if (!window.WebSocket)
alert("window.WebSocket unsuport!");
function $() {
return document.getElementById(arguments[0]);
}
function $F() {
return document.getElementById(arguments[0]).value;
}
function getKeyCode(ev) {
if (window.event)
return window.event.keyCode;
return ev.keyCode;
}
function showMessage(from, content) {
var messageBox = $('messageBox');
var spanText = document.createElement('span');
spanText.className = 'text';
spanText.innerHTML = from + ":" + content;
var lineBreak = document.createElement('br');
messageBox.appendChild(spanText);
messageBox.appendChild(lineBreak);
messageBox.scrollTop = messageBox.scrollHeight - messageBox.clientHeight;
}
function showLog(log) {
var logBox = $("logBox");
logBox.innerHTML = log + "<br />" + logBox.innerHTML;
}
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
return pcol + u[0];
}
var server = {
connect : function() {
var location = get_appropriate_ws_url() + "/servlet/a";
if (BrowserDetect.browser == "Firefox") {
this._ws = new MozWebSocket(location,
"dumb-increment-protocol");
} else {
this._ws = new WebSocket(location,
"dumb-increment-protocol");
}
this._ws.onopen = this._onopen;
this._ws.onmessage = this._onmessage;
this._ws.onclose = this._onclose;
showLog("connecting...");
},
_onopen : function() {
showLog("connected to server!");
},
_send : function(message) {
if (this._ws)
this._ws.send(message);
},
send : function(text) {
if (text != null && text.length > 0) {
server._send(text);
}
},
_onmessage : function(m) {
showMessage("others", m.data);
showLog("onmessage");
},
_onclose : function(m) {
this._ws = null;
showLog("onclose");
}
};
/* BrowserDetect came from http://www.quirksmode.org/js/detect.html */
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();
test2.html则用html5的canvas实现了电子白板的功能:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>Minimal Websocket test app</title>
</head>
<body>
<table>
<tr>
<td>Drawing color:
<select id="color" onchange="update_color();">
<option value=#000000>Black</option>
<option value=#0000ff>Blue</option>
<option value=#20ff20>Green</option>
<option value=#802020>Dark Red</option>
</select>
</td>
<td id=wslm_statustd align=center><div id=wslm_status>Not initialized</div></td>
</tr>
<tr>
<td colspan=2 width=500 align=center style="background-color: #e0e0e0;"><div id=wslm_drawing> </div></td>
</tr>
</table>
<script>
/* BrowserDetect came from http://www.quirksmode.org/js/detect.html */
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();
var pos = 0;
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
/*
* We open the websocket encrypted if this page came on an
* https:// url itself, otherwise unencrypted
*/
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
return pcol + u[0];
}
/* lws-mirror protocol */
var down = 0;
var no_last = 1;
var last_x = 0, last_y = 0;
var ctx;
var socket_lm;
var color = "#000000";
if (BrowserDetect.browser == "Firefox") {
socket_lm = new MozWebSocket(get_appropriate_ws_url() + "/servlet/a",
"lws-mirror-protocol");
} else {
socket_lm = new WebSocket(get_appropriate_ws_url() + "/servlet/a",
"lws-mirror-protocol");
}
try {
socket_lm.onopen = function() {
document.getElementById("wslm_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wslm_status").textContent = " websocket connection opened ";
}
socket_lm.onmessage =function got_packet(msg) {
j = msg.data.split(';');
f = 0;
while (f < j.length - 1) {
i = j[f].split(' ');
if (i[0] == 'd') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.moveTo(+(i[2]), +(i[3]));
ctx.lineTo(+(i[4]), +(i[5]));
ctx.stroke();
}
if (i[0] == 'c') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true);
ctx.stroke();
}
f++;
}
}
socket_lm.onclose = function(){
document.getElementById("wslm_statustd").style.backgroundColor = "#ff4040";
document.getElementById("wslm_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
var canvas = document.createElement('canvas');
canvas.height = 300;
canvas.width = 480;
ctx = canvas.getContext("2d");
document.getElementById('wslm_drawing').appendChild(canvas);
canvas.addEventListener('mousemove', ev_mousemove, false);
canvas.addEventListener('mousedown', ev_mousedown, false);
canvas.addEventListener('mouseup', ev_mouseup, false);
offsetX = offsetY = 0;
element = canvas;
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
function update_color() {
color = document.getElementById("color").value;
}
function ev_mousedown (ev) {
down = 1;
}
function ev_mouseup(ev) {
down = 0;
no_last = 1;
}
function ev_mousemove (ev) {
var x, y;
if (ev.offsetX) {
x = ev.offsetX;
y = ev.offsetY;
} else {
x = ev.layerX - offsetX;
y = ev.layerY - offsetY;
}
if (!down)
return;
if (no_last) {
no_last = 0;
last_x = x;
last_y = y;
return;
}
socket_lm.send("d " + color + "" + last_x + "" + last_y + "" + x + ' ' + y + ';');
last_x = x;
last_y = y;
}
</script>
</body>
</html>
相关资料:
http://git.warmcat.com/cgi-bin/cgit/libwebsockets/
http://dev.w3.org/html5/websockets/
发表评论
-
Mina重连
2014-05-26 21:29 2906import com.sun.swing.internal. ... -
面试经典
2014-05-24 09:29 6351.mysql innodb引擎,什么叫聚集索引,与非聚集索 ... -
一拍网网站系统架构图
2014-03-28 21:24 591一拍网网站系统架构图 -
Window下安装配置nginx
2013-08-12 16:53 774安装:http://www.cnblogs.com/wen ... -
使用线程池的好处
2013-07-18 14:41 1227使用线程池有两个好处: 1.可以创建和销毁线程所带来的系统 ... -
Java ThreadLocal使用浅析
2013-07-18 14:36 449ThreadLocal通过在其内部保存变量的副本,并且各个副本 ... -
MyBatis学习之简单增删改查操作、MyBatis存储过程、MyBatis分页、MyBatis一对一、MyBatis一对多
2013-07-05 13:06 1145http://blog.csdn.net/zhangwei ... -
分享一位网友的架构杂谈
2013-05-20 23:16 899不容类型的网站,并发处理不一样,例如针对sns这种类型的网站 ... -
EasyUI和EasyUI桌面App
2013-04-15 11:56 1171http://fxz-2008.iteye.com/blog/ ... -
Jquery进度条
2013-04-12 09:08 837http://www.cnblogs.com/lhb25/ h ... -
11个适合触摸事件开发的JavaScript库
2013-04-10 09:23 799http://www.codecto.com/2012/08/ ... -
JSP页面静态化
2013-04-08 09:20 858http://www.java-zone.org/644.ht ... -
Jquery插件
2013-03-22 18:33 777http://www.cnblogs.com/ywqu/arc ... -
Java compile to C++
2013-03-19 14:53 500http://code.google.com/a/eclips ... -
几个TCP Socket的通信框架
2013-03-19 12:26 986http://www.oschina.net/p/simple ... -
宝贝鱼
2013-03-18 23:54 671http://code.google.com/p/cshbbr ... -
将Java程序注册成系统服务(NT服务)
2013-03-16 16:14 599http://blog.csdn.net/small____f ... -
HTML&JS MVC
2013-03-15 16:27 602http://www.bootcss.com/ http:// ... -
浏览器内核及Js引擎介绍
2013-03-15 16:18 733http://wenku.baidu.com/view/623 ... -
Java内存回收机制
2013-03-13 15:47 807http://www.iteye.com/blogs/tag/ ...
相关推荐
基于Java WebSocket 做信令服务器,使用webrtc浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。从而实现音视频通话。下载启动 输入http://localhost 就可使用
【标题】"基于Chrome、Java、WebSocket、WebRTC实现浏览器视频通话" 描述了现代互联网技术如何让实时通信变得更加便捷。这个项目利用了多种技术,包括Google的Chrome浏览器、Java编程语言、WebSocket协议以及WebRTC...
- 实现信令机制:在呼叫建立阶段,使用WebSocket传递呼叫邀请和响应,包括SDP(会话描述协议)和ICE(交互式连接建立)候选信息。 - 建立WebRTC连接:在双方都同意呼叫后,通过交换SDP和ICE信息,建立P2P(对等网络...
基于WebSocket、WebRTC实现浏览器视频通话, 仅供参考,大家一起讨论学习!
WebSocket 和 WebRTC 结合是现代Web应用程序中实现实时通信的重要技术组合。WebSocket提供双向通信,而WebRTC专注于在浏览器之间直接进行音视频流传输。让我们深入探讨这两种技术以及它们如何协同工作。 WebSocket ...
公司要做一个移动端通讯聊天,考虑到是公司内部使用,没有采用第三方收费通讯接口,刚开始尝试过nginx+rtmp,但是视频延迟太高,后来经过查询测试总结,最终使用websocket+webrtc实现,测试延迟最高为0.3s左右,可以...
本文将深入探讨如何利用SpringBoot、WebSocket和WebRTC技术实现这样的系统。这三个技术的结合为开发者提供了强大的工具,可以创建高效的多人视频通话应用。 首先,SpringBoot是Java开发领域的主流框架,它简化了...
运行结果在这:https://www.bilibili.com/video/BV1wu4y1Z7eW,之前把这个项目发布到公网上的,但是缺少ice服务器的配置,仅仅只能在局域网上才能运行成功哈!用户下载这个压缩包之后,运行这个项目应该还是启动不了...
本项目利用SpringBoot、WebSocket和WebRTC技术构建了一个基本的视频通话系统。以下是关于这些关键技术点的详细说明。 首先,SpringBoot是Spring框架的一个轻量级封装,它简化了Java应用的开发流程,提供了自动配置...