一、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. ZJNU 1531 - 丢手绢--中级

    可以将相同的人数分块存在数组gp中先 例如RRGGGRBBBBRR 则gp[1~5]={2,3,1,4,2} 首先可以知道,如果要让没有相邻的相同,只需要每个gp[i]/2向下取整即可得出最少需要改变 ...

  2. NOIP复赛文件路径怎么写

    以2018年NOIP普及组复赛为例,四道题对应着四个文件夹:   随便选一道题,比如第一道题,进入title目录,可以看到title1.in, title1.ans, title2.in, title ...

  3. JQuery查找标签

    JQuery查找标签 一.基本标签 1 id选择器: $("#id(名称)") $("#cent") 2 标签选择器: $("tabName(便签名称 ...

  4. HDU - 4578 线段树+三重操作

    这道题自己写了很久,还是没写出来,也看了很多题解,感觉多数还是看的迷迷糊糊,最后面看到一篇大佬的才感觉恍然大悟. 先上一篇大佬的题解:https://blog.csdn.net/aqa20372995 ...

  5. Java实现卖票程序(两种线程实现)

    /** * 2019年8月8日16:05:05 * 目的:实现火车站卖票系统(第一种创建线程的方式) * @author 张涛 * */ //第一种方式直接继承Thread来创建线程 class T1 ...

  6. string.Format字符串格式化说明(转)

    string.Format字符串格式化说明 www.111cn.net 编辑:Crese 来源:转载   先举几个简单的应用案例: 1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统 ...

  7. sin之舞---蓝桥杯练习

    问题描述 最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功.所以他准备和奶牛们做一个“Sine之舞”的游戏,寓教于乐,提高奶牛们的计算能力. 不妨设 An=s ...

  8. 关于css中hover下拉框的一个bug

    写hover下拉框的时候会遇到一个奇怪的bug,就是下拉框下来的时候会被所在位置的div遮挡,哪怕下拉框使用的absolute,也会被遮挡. 如图: 这个语言选择的下拉框会被下面的div挡住(截图是已 ...

  9. UUID与时间戳

    /** * 32位去除'-'的UUID */ public static String getUUID() { String uuid = java.util.UUID.randomUUID().to ...

  10. [LC] 285. Inorder Successor in BST

    Given a binary search tree and a node in it, find the in-order successor of that node in the BST. Th ...