一、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. lightgbm直方图算法

    https://blog.csdn.net/anshuai_aw1/article/details/83040541

  2. linux上一些常用的命令

    1.时时查看tomcat启动信息,首先切换到tomcat的logs目录下 tail -f catalina.out 2.在tomcat的bin目录下启动无权限,需要赋权 chmod 777 *.sh ...

  3. saltstack的salt-api介绍

    一.salt-api安装 yum install salt-api pyOpenSSL -y #pyOpenSSL 生成自签证书时使用 二.生成自签名证书(ssl使用) [root@master ce ...

  4. GPIO外部中断

    来源:莆田SEO 在STM32中,其每一个外设都可以产生中断. 中断分为分为 ①系统异常,内核 ②外部中断,外设 NVIC(Nested Vector Interrupt Controller ):嵌 ...

  5. 量化投资_MATLAB在时间序列建模预测及程序代码

    1 ARMA时间序列机器特性 下面介绍一种重要的平稳时间序列——ARMA时间序列. ARMA时间序列分为三种: AR模型,auto regressiv model MA模型,moving averag ...

  6. Python2 和 Python3的区别 更新中

    py2和py3的区别 1.默认解释器编码 py2: ascii py3: utf-8 2.输入 输出 输入 py2: name = raw_input('请输入你的姓名:') py3: name = ...

  7. (一)Thread的run() 和 start() 方法

    Java多线程在实际开发中会遇到很多问题,对于这种争抢CPU时间片段的选手,我们或许有很多困惑,捉摸不透.即便如此,它也是可以被我们控制的. 最近在看Java多线程的书籍,里面有好多我曾经不怎么注意的 ...

  8. JDBC常用驱动和语法汇总

    A. Firebird url=jdbc:firebirdsql:[HOST_NAME]/[PORT:][FULL_PATH_TO_DATABASE_FILE] driver=org.firebird ...

  9. String Distance and Transform Process

    http://acm.hdu.edu.cn/showproblem.php?pid=1516 Problem Description String Distance is a non-negative ...

  10. MVP简要示例

      MVP即Model-View-Presenter,是从经典的MVC演变而来的,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理.Model提供数据.View负责显 ...