websocket服务端开发
基于http请求以拉的方式去做服务器的推送,无论是实时性和有效字节都是差强人意的效果。
公司的im系统在与客户端的交互上实际上借助了websocket来实现服务器与客户端的事实消息推送,今天就来简单了解下这个协议,并且自己实现对websocket的响应。

可以看到在理解了tcp和http之后,websocket的设计其实并不复杂,再最开始建立链接的时候客户端实际上会进行一次http请求,只不过请求头的内容有些特别,这里我们来看下:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protool: chat,superchat
Sec-WebSocket-Version:13
可以看到这个报文里包含了一些附加头信息。其中附加头信息"Upgrade: WebSocket" ,表明这是一个申请协议升级的http请求。"Sec-WebSocket-Key"是随机的,服务端会用这些数据构造出
一个SHA-1的信息摘要,把"Sec-WebSocket-Key"加上一个魔幻字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"。使用SHA-1加密,然后进行BASE-64编码,将结果作为"Sec-WebSocket-Accept"头的值,返回给客户端:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protool: chat
实现对websocket请求的响应:
public class WebsocketServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(8080);
Socket socket= serverSocket.accept();
new Thread(new Handle(socket)).start();
}
}
public class Handle implements Runnable{
private Socket socket;
Handle(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try {
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStreamWriter streamWriter=new OutputStreamWriter(socket.getOutputStream());
BufferedWriter bufferedWriter=new BufferedWriter(streamWriter);
String key=null;
//读报文
while (true){
String s= reader.readLine();
System.out.println(s);
if (s.equals("")){
break;
}else{
if (s.contains("Sec-WebSocket-Key")){
String keyValue[]=s.split(":");
key=keyValue[1].trim()+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
}
}
}
//写报文
MessageDigest messageDigest=DigestUtils.getSha1Digest();
byte[] digest=messageDigest.digest(key.getBytes());
Base64 base64 = new Base64();
String finalKey=base64.encodeToString(digest);
bufferedWriter.write("HTTP/1.1 101 Switching Protocols\r\n");
bufferedWriter.write("Upgrade: websocket\r\n");
bufferedWriter.write("Connection: Upgrade\r\n");
bufferedWriter.write("Sec-WebSocket-Accept: "+finalKey+"\r\n");
bufferedWriter.write("Sec-WebSocket-Protool: chat\r\n");
bufferedWriter.write("\r\n");
bufferedWriter.write("test");
bufferedWriter.write("\r\n");
bufferedWriter.flush();
//接收数据
System.out.println("响应报文已经发送");
while (true){
String s=reader.readLine();
System.out.println(s==null);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
建立连接的时候要注意 Sec-WebSocket-Key在做sha-1哈希时,取得时摘要 然后拿着摘要去做base64遍嘛得到Sec-WebSocket-Accept,上面代码还有问题就是连接建立之后 BufferedReader的readLine()方法在遇到\r,\r\n,\n之前会等到填满缓冲区才会被唤醒,找的很多测试用的客户端都会把换行符去掉导致线程在填满缓冲区8KB之前一直阻塞,另一个问题就是字符流的编码问题。这里更多的关注连接建立过程,连接建立之后其实就是直接用tcp传输数据了,这里不多做赘述
websocket服务端开发的更多相关文章
- 用nodejs快速实现websocket服务端(带SSL证书生成)
有不少公司将nodejs的socket.io作为websocket的解决方案,很遗憾的是socket.io是对websocket的封装,并不支持html5原始的websocket协议,微信小程序使用的 ...
- Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...
- 在线教学、视频会议 Webus Fox(2) 服务端开发手册
上次在<在线教学.视频会议软件 Webus Fox(1)文本.语音.视频聊天及电子白板基本用法>里介绍了软件的基本用法.本文主要介绍服务器端如何配置.开发. 1. 配置 1.1 IIS配置 ...
- C# WebSocket 服务端示例代码 + HTML5客户端示例代码
WebSocket服务端 C#示例代码 using System; using System.Collections.Generic; using System.Linq; using System. ...
- Android 服务端开发之开发环境配置
Android 服务端开发之开发环境配置 这里是在Eclipse的基础上安装PhpEclipse插件方法,PHPEclipse是Eclipse的 一个用于开发PHP的插件.当然也可以采用Java开发a ...
- nodejs服务端开发学习笔记
正在学习中,不断改错... 学习了一段时间nodejs,对其中的很多东西还不是很理解,在网上看过很多的例子,希望通过自己的一些总结让自己了解的更全面些,同时也作为学习笔记留存备忘. 准备工作 node ...
- Swift3.0服务端开发(三) Mustache页面模板与日志记录
本篇博客主要介绍如果在Perfect工程中引入和使用Mustache页面模板与日志记录系统.Mustache页面模板类似于PHP中的smarty模板引擎或者Java中的JSTL标签.当然Mustach ...
- Swift3.0服务端开发(五) 记事本的开发(iOS端+服务端)
前边以及陆陆续续的介绍了使用Swift3.0开发的服务端应用程序的Perfect框架.本篇博客就做一个阶段性的总结,做一个完整的实例,其实这个实例在<Swift3.0服务端开发(一)>这篇 ...
- 如何有效快速提高Java服务端开发人员的技术水平?
我相信很多工作了3-5年的开发人员都会经常问自己几个问题: 1.为什么总是感觉技术没有质的提高? 2.如何能够有效和快速的提高自身的技术水平? 3.如何进入到一个牛逼的大公司,认识牛逼的人? 这篇文章 ...
随机推荐
- java 文件和byte 互转
/** * 获得指定文件的byte数组 */ private byte[] getBytes(String filePath){ byte[] buffer = null; try { File fi ...
- 由Menu小项目所引发的对软件工程的思考
学习了孟老师的这几节课程,我学习了如何搭建一个简单的命令行menu小程序,从最简单的程序开始,一步步的根据软件工程的一般规律,进行逐步开发.完善,最终实现了一个比较通用的menu程序,可以让别的开发者 ...
- vue父组件促发子组件中的方法
实现在父组件中促发子组件里面的方法 子组件: <template> <div> 我是子组件 </div> </template> <script& ...
- Spring AOP实现注解式的Mybatis多数据源切换
一.为什么要使用多数据源切换? 多数据源切换是为了满足什么业务场景?正常情况下,一个微服务或者说一个WEB项目,在使用Mybatis作为数据库链接和操作框架的情况下通常只需要构建一个系统库,在该系统库 ...
- XJOI 夏令营501-511NOIP训练17 蛇形数阵
话说小X在孩提时,都会做标准的蛇形矩阵了,发现很好玩.现在的小X很想对其进行改版,变为如下类型的一个无限大蛇形数阵:令S(x)表示以1为左上角,x为右下角的矩形内所有数之和.例如S(12)就是具有深色 ...
- 17flask分页
一,flask_sqlachemy的使用 如果想要展示出来的页面是分页显示,则首先需要知道每页应该分多少个条目,然后通过数据库去查找对应的条数,同时也需要和分页所需的"paginate&qu ...
- [tmp]__URL
常用排序算法稳定性.时间复杂度分析(转,有改动) http://www.cnblogs.com/nannanITeye/archive/2013/04/11/3013737.html http://w ...
- [MIT6.006] 7. Counting Sort, Radix Sort, Lower Bounds for Sorting 基数排序,基数排序,排序下界
在前6节课讲的排序方法(冒泡排序,归并排序,选择排序,插入排序,快速排序,堆排序,二分搜索树排序和AVL排序)都是属于对比模型(Comparison Model).对比模型的特点如下: 所有输入ite ...
- 402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k.num 不会包含任何前导零.示例 1 : 输入: num ...
- ubuntu12.10安装sun java jdk
add-apt-repository ppa:webupd8team/java apt-get update apt-get install oracle-java6-installer root@k ...