一、Socket简介

Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”,作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。

Socket可以使用TCP/IP协议或UDP协议。

TCP/IP协议

TCP/IP协议是目前应用最为广泛的协议,是构成Internet国际互联网协议的最为基础的协议,由TCP和IP协议组成:
TCP协议:面向连接的、可靠的、基于字节流的传输层通信协议,负责数据的可靠性传输的问题。

IP协议:用于报文交换网络的一种面向数据的协议,主要负责给每台网络设备一个网络地址,保证数据传输到正确的目的地。

UDP协议

UDP特点:无连接、不可靠、基于报文的传输层协议,优点是发送后不用管,速度比TCP快。

二、WebSocket简介与消息推送

B/S架构的系统多使用HTTP协议,HTTP协议的特点:

1 无状态协议
2 用于通过 Internet 发送请求消息和响应消息
3 使用端口接收和发送消息,默认为80端口
底层通信还是使用Socket完成。

HTTP协议决定了服务器与客户端之间的连接方式,无法直接实现消息推送(F5已坏),一些变相的解决办法:

双向通信与消息推送

轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。 优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。

长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。 优点:在无消息的情况下不会频繁的请求,耗费资小。 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx,实例:WebQQ、Hi网页版、Facebook IM。

长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。 优点:消息即时到达,不发无用请求;管理起来也相对便。 缺点:服务器维护一个长连接会增加开销。 实例:Gmail聊天

Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。 优点:实现真正的即时通信,而不是伪即时。 缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。 实例:网络互动游戏。

Websocket:
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
特点:
事件驱动
异步
使用ws或者wss协议的客户端socket

能够实现真正意义上的推送功能

缺点:

少部分浏览器不支持,浏览器支持的程度与方式有区别。

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

三、界面如下:

四、实现代码

  1、客户端CSS样式(ChatClient.css):

       #divMessage{
width:750px;
height:550px;
margin:5px;
background-image: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533792134030&di=14e6b1be8d569d7dcb570ed21bbd218d&imgtype=0&src=http%3A%2F%2Ffb.topitme.com%2Fb%2F28%2F64%2F1129884950a4e6428bo.jpg);
background-position: -150px 0px;
float:left;
color:black;
font-size:18px;
font-family:新宋体;
}
#divOperation{
width:400px;
height:450px;
float:right;
}
.green{
color:green;
}
.red{
color:red;
} img{
width:100px;
height:100px;
} span{
font-size:24px;
font-family:华文琥珀;
} #showAllUserName{
width:150px;
height:550px;
background-image: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533792134030&di=14e6b1be8d569d7dcb570ed21bbd218d&imgtype=0&src=http%3A%2F%2Ffb.topitme.com%2Fb%2F28%2F64%2F1129884950a4e6428bo.jpg);
float:left;
font-size:18px;
font-family:新宋体;
margin:5px; } input[type=button]{
width:80px;
height: 30px;
margin:5px;
}

  2、客户端界面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天界面</title>
<link rel="stylesheet" href="css/ChatClient.css">
</head>
<body>
<div style="OVERFLOW-Y: auto; OVERFLOW-X:hidden;" id="showAllUserName">
<p style="color:green;font-family: 华文琥珀;">&emsp;在线用户:</p>
</div>
<div style="OVERFLOW-Y: auto; OVERFLOW-X:hidden;" id="divMessage"> </div> <div id="divOperation">
<p>
昵称:<input style="width:120px;line-height:20px;" type="text" maxlength="5" id="txtUserName" /></p>
<span id="spanUserName" class="red">未连接</span>
</p>
<p>
消息输入(可输入HTML代码):<textarea id="txtMessage" cols="50" rows="4"></textarea>
</p>
<p>
<input type="button" id="btnConnection" value="连接" /><span id="spanMessage"></span>
<input type="button" disabled id="btnSend" value="发送"/>
<input type="button" disabled id="btnClose" value="关闭" />
</p>
</div>
<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script> var socket;
if(typeof(WebSocket)=="undefined"){
alert("您的浏览器不支持WebSocket");
} //连接点击
$("#btnConnection").click(function(){
var name = $("#txtUserName").val(); if(name==null || name==""){
$("#spanUserName").text("用户名格式错误!").prop("class","red");
return;
} //实例化WebSocket,指定要连接的服务器地址与端口
socket = new WebSocket("ws://localhost:8080/ws/"+name); //打开事件
socket.onopen = function () {
console.log("Socket已打开");
$("#spanUserName").text("已连接").prop("class","green");
$("#btnConnection").prop("disabled",true);
$("#btnSend").prop("disabled",false);
$("#btnClose").prop("disabled",false);
$("#txtUserName").prop("disabled",true);
} //获得消息事件
socket.onmessage = function (msg) { var sign = msg.data.substring(0,msg.data.indexOf("&"));
var content = msg.data.substring(msg.data.indexOf("&")+1); if(sign=="userAllName"){ //所有在线用户信息处理
var userNames = content.split(","); //除了第一个p标签,其余清空
$("#showAllUserName p:gt(0)").remove(); for(var i=0;i<userNames.length;i++){
$("#showAllUserName").append($("<p/>").html("&nbsp;"+userNames[i]));
} }
else if(sign=="userMessage"){ //用户发送信息处理
var p = $("<p/>").html("&emsp;&emsp;"+content);
$("#divMessage").append(p);
}
} //关闭事件
socket.onclose = function(){
console.log("socket已关闭");
} //发生错误的事件
socket.onerror = function(){
console.log("发生了错误");
}
}); //发送消息
$("#btnSend").click(function(){
if(document.getElementById("txtMessage").value=="" || document.getElementById("txtMessage").value==null){
alert("消息不能为空!");
return;
} socket.send(document.getElementById("txtMessage").value);
document.getElementById("txtMessage").value = "";
}); //关闭事件
$("#btnClose").click(function(){
socket.close();
$("#btnConnection").prop("disabled",false);
$("#btnClose").prop("disabled",true);
$("#btnSend").prop("disabled",true);
$("#spanUserName").text("已断开").prop("class","red");
$("#txtUserName").prop("disabled",false);
$("#txtUserName").prop("value","");
$("#divMessage p").remove();
$("#showAllUserName p:gt(0)").remove();
}); </script>
</body>
</html>

  3、后台代码(WSServer.java):

package socket;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*; @ServerEndpoint("/ws/{user}")
public class WSServer {
private String currentUser;
private static Set<Session> map = new HashSet<>();
//用户保存
private static Map<String,String> userName = new HashMap<String, String>(); //连接打开时执行
@OnOpen
public void onOpen(@PathParam("user")String user, Session session){
currentUser = user;
map.add(session);
userName.put(session.getId(),user);
//自定义方法,更新客户端的客户在线信息
sendOutMessage();
} //收到消息时执行
@OnMessage
public void onMessage(String message,Session session) throws IOException {
//把信息传到已连接的用户客户端
for(Session sess : map){
//userMessage& 这段是为了客户端判断信息类型,是用户发送的消息,还是所有在线用户的信息
sess.getBasicRemote().sendText("userMessage&"+currentUser + " : " + message);
} } //连接关闭时执行
@OnClose
public void onClose(Session session, CloseReason closeReason){
map.remove(session);//删掉断开连接的用户
userName.remove(session.getId()); //删掉断开连接的用户信息
//更新在线的所有用户
sendOutMessage();
} //连接错误时执行
@OnError
public void OnError(Throwable t){
t.printStackTrace();
} private static void sendOutMessage(){
//将所有在线的用户拼接成字符串 userAllName& 这段是信息类型判断
StringBuffer userAllStr = new StringBuffer("userAllName&");
String str = "";
for(String s : userName.keySet()){
userAllStr.append(str+userName.get(s));
str=",";
}
System.out.println(userAllStr);
//循环所有客户id,向客户端发送信息
for(Session session : map){
try {
session.getBasicRemote().sendText(userAllStr.toString());
} catch (IOException e) {
e.printStackTrace();
}
} } }

初心易得,始终难守。(LC)

介绍一个博客:http://best.cnblogs.com/

Java WebSocket实现简易聊天室的更多相关文章

  1. 基于Node.js + WebSocket 的简易聊天室

    代码地址如下:http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.js ...

  2. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  3. node.js+websocket实现简易聊天室

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) websocket提供了一种全双工客户端服务器的异步通信方法,这种通信方法使用ws或者wss协议,可 ...

  4. node+websocket创建简易聊天室

    关于websocket的介绍太多,在这就不一一介绍了,本文主要实现通过websocket创建一个简易聊天室,就是90年代那种聊天室 服务端 1.安装ws模块,uuid模块,ws是websocket模块 ...

  5. Java WebSocket实现网络聊天室(群聊+私聊)

    1.简单说明 在网上看到一份比较nice的基于webSocket网页聊天项目,准备看看学习学习,如是有了这篇文章!原博主博客:http://blog.csdn.net/Amayadream/artic ...

  6. JAVA WebSocKet ( 简单的聊天室 )

    1, 前端代码 登入页 -> login.html <!DOCTYPE html> <html> <head> <meta charset=" ...

  7. WebSocket实现简易聊天室

    前台页面: <html> <head> <meta http-equiv="Content-Type" content="text/html ...

  8. 使用Html5下WebSocket搭建简易聊天室

    一.Html5WebSocket介绍 WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站 ...

  9. 小案例-WebSocket实现简易聊天室

    前言 在详解 HTTP系列之一讲到HTTP/2.0 突破了传统的"请求-问答模式"这一局限,实现了服务器主动向客户端传送数据.而本章将通过一种在单个TCP连接上进行全双工通信的协议 ...

随机推荐

  1. 巧用函数,使Sql中in的用法更多变

    在Sql中我们经常会用到in 普遍的写法为 where xx in ('1','2','3') 通过函数写法为: IF EXISTS ( SELECT * FROM sys.objects WHERE ...

  2. 2019-2020-1 20199324《Linux内核原理与分析》第九周作业

    第八章 进程的切换和系统的一般执行过程 1.进程调度的时机 硬中断和软中断 中断:在本质上都是软件或者硬件发生了某种情形而通知处理器的行为,处理器进而停止正在运行的指令流(当前进程),对这些通知做出相 ...

  3. org.springframework.web.util.UriComponentsBuilder

    import org.springframework.web.util.UriComponentsBuilder; UriComponentsBuilder.fromHttpUrl("htt ...

  4. Android开发学习1----AndroidStudio的安装、创建第一个Android Studio文件、Android Studio界面介绍和HelloWord!

    移动开发的工具有很多:Android Studio,eclipse,Hbuilder等,其中,现如今最火的开发工具是Android Studio,Android Studio是谷歌自己推出的一款集成开 ...

  5. Hardy-Weinberg laws

    I.3 Diploids with two alleles: Hardy-Weinberg laws 假设子代是Aa,AA,aa的概率分别是PAa,PAA,Paa,A的基因概率是P1,a的基因概率是P ...

  6. maven隐含依赖

    1.有时候,我们在pom.xml依赖了2个jar包,不过在工程lib里看到依赖包多于2个,这是为什么呢?原因是maven引入一个jar时,会连带引入这个jar包依赖的jar包,除非在配置引入这个jar ...

  7. tomcat更新class不生效

    替换线上lib里的class不生效,需要想想是不是前人为了图方便在classes里面扔了一份老版本class

  8. linux系统权限(基本权限)

    linux的系统权限:r--  100 4-w- 010 2--x  001 1 [root@localhost ~]# ll -d dir drwxrwxrwx root root Nov : di ...

  9. hybrid|Conform the norm of|Mollusk|uncanny|canny|Canvas|documentary

    hybrid混合物 Conform the norm of 符合规范 Mollusk贝类 uncanny诡异的 canny精明的 Canvas帆布 documentary纪录片  

  10. IO概念和五种IO模型

    一.什么是IO? 我们都知道unix世界里.一切皆文件.而文件是什么呢?文件就是一串二进制流而已.不管socket.还是FIFO.管道.终端.对我们来说.一切都是文件.一切都是流.在信息交换的过程中. ...