WebSocket入门介绍及编程实战

前言:最近看了几天的WebSocket,从以前的只闻其名,到现在也算是有一点点的了解了。所以就准备用博客记录一下自己的学习过程,希望也能帮助其它学习的人,因为我本人学习的过程中也是参考了很多其它人的博文。 这里主要是想了解一下WebSocket传输的协议帧,并使用java来模拟一个WebSocket客户端向服务端发送、接收数据。

注:对于网络协议的学习,通过自己编程实现一些简单的功能是一种很有效的方式。例如使用Socket去下载网络图片或者访问接口等,你会遇到很多问题,解决它们之后,也会收获很多东西!

WebSocket入门介绍

在介绍WebSocket之前先来简单说一下HTTP吧,因为WebSocket本身就是为了补充或者取代一部分HTTP的功能。在这之前的几天,我对WebSocket的理解也只是浮于表面,只是听过名字,知道它是全双工的工作特点。但是经过这几天的了解以及实际的编程操作,我对于它的协议有了一定的认识了,对于为什么是全双工有了一个较为深入的理解。所以,如果你对WebSocket不是很了解的话,推荐直接拉到文章最后,先阅读参考资料,然后了解一波内容之后,再过来阅读我的这篇博客,相信你会收获很多的!


HTTP的限制

全双工和半双工:
全双工:全双工(Full Duplex)是允许数据在两个方向上同时传输。
半双工:半双工(Half Duplex)是允许数据在两个方向上传输,但是同一个时间段内只允许一个方向上传输。

这里半双工我们可以类比我们熟知的HTTP协议,它的工作方式就是类似于半双工(但是,我们也应该明白,它还不如半双工呢!)。并且,它是只允许客户端主动请求,而服务器端被动响应,即所谓的请求响应模式。显然这种模式是有一种缺陷的,对于某些功能的实现是很麻烦的!
例如,如果需要在客户端上维持某个数据的实时性,那么该如何实现呢? 如果这个数据发生了改变,服务器并不能主动通知到客户端,因此需要客户端自己去服务器上拉取数据。但是请求一次,只能知道当前数据是否更新,如果数据早就更新了呢?因此需要客户端不断的请求服务器,询问数据是否改变,这种方式即称为轮询(通常是ajax轮询)。轮询是一种很低效的方式,并且它只是伪实时的,因为轮询需要间隔一定的时间,如果时间长了数据的实时性就低了,时间短了,服务器的压力也很大的(客户端也会有一定的压力)。这里的伪实时指的是假如轮询间隔时间为t,那么数据更新以后到客户端获取到数据的时间间隔即为0-t。

再举一个很常见的例子,如果开发web的话,有时候出了问题,我们通常会刷新一下,这就是HTTP协议的特性限制的,你不刷新的话,是无法得到响应的。

那么有什么解决办法呢? 既然有需求,一定会有解决办法的!Http本身是基于请求响应的,但是它的底层是TCP,如果你有Socket编程经验的话,应该知道只要连接建立以后,任何一端都可以同时向对方发送数据,这本身就是一种全双工的工作方式。

注: 套接字是通信的基石,是支持TCP/IP协议的通信的基本操作单元。可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。

有一种技术应用称为RSS(简易信息聚合),它算是Web1.0时代的东西了,也算是客户端拉取数据的应用 之一了。现在,这种技术已经使用的不多了,普通用户基本没有接触过了。因为,现在的信息的更新已经可以推送到你面前了(手机上的主动推送信息),那你为什么还要去拉取呢?

WebSocket

WebSocket的百度百科定义:

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

因此当一个WebSocket连接建立以后,通信的两端就可以以全双工的模式进行通信了。这样对于上面那种需要维持数据实时性的需求,就可以抛弃掉轮询这种方式,转而使用WebSocket解决,并且大大提高了实时性,而且只需要维持一个WebSocket连接即可,这样也减轻了网络压力。

ajax轮询和WebSocket的关系
上面这幅图很好的展示了AJAX轮询和WebSocket之间的区别,并且你可以发现WebSocket是需要使用HTTP去建立连接的,这一点很重要,因为待会的代码实战需要用到它!

编程实战

上面算是一个简单的了解了,相信你已经对WebSocket有了一个认识了,下面让我们进入编程实战的部分吧!Talk is cheap, show me your code!

WebSocket是一个应用层协议,并且它是建立在TCP之上的,具体可以看下图即可知道它们的关系了。因此,这里的编程目标是使用Socket模拟一个WebSocket客户端与服务器进行通信。
在这里插入图片描述

这幅图很有意思,如果你看完了文章,再回头看一下它,会加深你的理解的。
在这里插入图片描述

WebSocket连接的建立及数据传输:
首先会发送一个HTTP报文,然后会响应一个HTTP报文,接下来会传输WebSocket协议的数据帧。
可以这样来理解,HTTP是建立在TCP上的协议,HTTP协议本身是TCP的数据部分(首部+实体),然后WebSocket是和HTTP平级的另一种应用层协议,它的协议数据帧部分也是TCP的数据部分。所以,理解上面,这个步骤之后,我们就可以去着手准备模拟的工作。

非常重要的部分:
模拟工作主要就是仿照上面这个步骤,首先建立一个TCP连接(使用java的Socket类),然后发送一个HTTP请求和服务端建立WebSocket连接,然后接下来发送WebSocket数据帧(控制部分+数据部分),最后关闭WebSocket连接,关闭Socket连接(即TCP连接)。


建立WebSocket连接的步骤

我们首先需要明白建立一个WebSocket连接的具体步骤,这里我们换一种方式了解一下!
因为我的目标是模拟WebSocket客户端,所以我首先需要有一个WebSocket服务器和客户端,这里提供一个简单的demo工程。
注:这个的demo是基于SpringBoot的工程。

服务器端

1.工程结构(这里的错误可以忽略,eclipse手动建立的springboot项目似乎不怎么支持。)
在这里插入图片描述

2.这里是需要导入的依赖:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-validation</artifactId>
	</dependency>
	
   <!-- 引入websocket依赖 -->
   <dependency>  
         <groupId>org.springframework.boot</groupId>  
         <artifactId>spring-boot-starter-websocket</artifactId>  
     </dependency> 

</dependencies>
package websocket_learn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {
	
	public static void main(String[] args) {
		SpringApplication.run(WebApplication.class, args);
	}
	
}
package websocket_learn.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
	
	/**
	 * 注入websocket的bean,不过这种直接创建对象的方式,
	 * 应该不是一个效率好的方式,不过这里作为演示是足够了。
	 * */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}
	
}
package websocket_learn.server;

import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@ServerEndpoint("/server/{userId}")
public class WebSocketServer {
 	static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
 	
	 /**
	 * 连接成功
	 *
	 * @param session
	 */
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("连接成功");
    }

    /**
     * 连接关闭
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        System.out.println("连接关闭");
    }

    /**
     * 接收到消息
     *
     * @param text
     */
    @OnMessage
    public void onMsg(Session session, String msg) throws IOException {
    	// 接收客户端发送的消息
    	log.info("WebSocket Client: {}", msg);
    	// 给客户端发送一条消息
    	session.getBasicRemote().sendText("WebSocket Server: " + "Time and tide wait for no man.");    	
    }
}

客户端

这里使用的是Chrome浏览器的Console。
在这里插入图片描述
依次执行上面代码,即完成了一个WebSocket连接的建立–>发送(接收)–>关闭。

测试功能

在这里插入图片描述

上面已经执行了一个完整的WebSocket流程,并且我们通过上面已经了解到了大概的步骤了,但是由于我们看不到具体的细节,因此还是无法进行模拟。为了了解到这些具体的细节,我们需要针对一个真实的协议通信进行分析,所以这里需要抓取网络数据包。这里介绍两个抓包工具:Fiddler(HTTP)、WireShark(TCP)。 这里的推荐使用WireShark,因为Fiddler是偏向于应用层了(据说高版本是支持WebSocket的,但是我可能没有设置好,所以主要还是使用了WireShark)。

让我们首先打开Fiddler和WireShark,再次运行下面的代码,这里添加了一个输出接收到的信息的函数,刚才忘记了。

浏览器客户端
在这里插入图片描述

服务器端
在这里插入图片描述

然后打开Fiddler,可以发现居然抓到了一个HTTP的包!但是,它之抓到了建立WebSocket连接的HTTP包,之后的WebSocket数据帧就没有了。

在这里插入图片描述

HTTP请求报文

GET http://127.0.0.1:9000/server/1 HTTP/1.1
Host: 127.0.0.1:9000
Connection: Upgrade                // 非常重要的字段
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Upgrade: websocket
Origin: chrome-search://local-ntp
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Sec-WebSocket-Key: q/rOgMV7pqwCKewaLidYTQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

HTTP响应报文

HTTP/1.1 101
Upgrade: websocket            // 非常重要的字段
Connection: upgrade
Sec-WebSocket-Accept: YQCqLSE6C+J3G3YM9eQ7DSlDMtM=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Date: Thu, 31 Dec 2020 10:26:52 GMT
EndTime: 18:27:26.287
ReceivedBytes: 56
SentBytes: 44

注意这两个字段,这里的意思是:客户端请求连接升级为WebSocket协议,然后服务器响应消息提示客户端连接已经升级了。
Connection: Upgrade
Upgrade: websocket

补充:
我发现了,Fiddler确实是有WebSocket,但是由于这里数据是被压缩了,所以无法看到每一个到底是什么了。不过其实这样也足够了,我只需要按照顺序发送这些数据就行了,但是这样对于学习的理解不够友好了。
在这里插入图片描述

这里有一个坑,由于我是抓取的浏览器的包,但是它默认会对数据进行压缩(由下面这一行首部进行控制),但是我不知道这个压缩方法是什么,所以也就没有办法模拟数据了。因此模拟操作一度中断了,后来的解决办法是不抓取浏览器的包,转而使用一个网上下载的WebSocket客户端工具。其实,如果不压缩的话,那么传输的数据就是原始数据,客户端发送给服务器的需要进行掩码操作,服务器发送给客户端的是不需要掩码操作的,但这个是模拟成功后才了解到的。
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

我这里查到了Fiddler高版本已经支持了WS协议,但是我这里没有找到,但是也没关系,我还有另一个更加强大的工具呢——WireShark。

这是我下载的WebSocket客户端测试工具:
在这里插入图片描述

测试
注意:它建立连接后会默认发送一条消息:
与服务器建立连接成功!(吾爱破解:skyxiaoyu. www.52pojie.cn)
这点我感觉不太好,虽然我的目的也是模拟这个软件的功能,实现一个简易的版本。
在这里插入图片描述

在这里插入图片描述

WireShark抓包截图:
在这里插入图片描述
注:
1.protocol为TCP的包可以忽略不看。
2.[MASKED]表示该包由客户端发送,服务器发送的都是没有masked的,这点很重要!


WebSocket协议帧

WebSocket也不是直接在Socket中传输的,它也是有固定结构的协议帧组成的,这样是为了避免TCP的一些问题,TCP只是提供了一条通路,具体传输数据的格式还是要自己设定。
在这里插入图片描述
所以,发送的数据需要以这种数据帧的形式发送。这里对于这个数据帧的解析,就不多介绍了,因为我也是参考的别人的资料,推荐你也去阅读。你可以在最后的参考资料中详细的了解到每一位的具体作用。

Masking-Key: 0 or 4 bytes,所有从客户端发往服务端的数据帧都已经与一个包含在这一帧中的32bit的掩码进行过了运算。为什么需要掩码?为了安全,但并不是为了防止数据泄密,而是为了防止早期版本的协议中存在的代理缓存污染攻击(proxy cache poisoning attacks)等问题。

这里这个第3行:Per-Message Compressed: True。表示是对消息进行压缩,我在这里被卡住了一段时间,所以我需要使用非浏览器的方式发送数据,来规避这一条。
在这里插入图片描述
客户端主动发送的WebSocket数据帧
注意:Mask: True 表示数据进行了掩码操作。
因为客户端的数据都需要进行一个掩码操作,所以以二进制显示的时候,后面那部分就是数据,但是它是显示不正常的。(Masked Data)
在这里插入图片描述

服务器端主动发送的WebSocket数据帧
注意:Mask: False 表示数据没有进行掩码操作。
服务器端发送的数据都是没有进行掩码操作的,因此你可以看到右下角那块数据是可以直接解码显示出来的。
在这里插入图片描述

客户端主动关闭WebSocket的数据帧
在这里插入图片描述

服务端收到客户端消息后,响应关闭WebSocket连接的数据帧
在这里插入图片描述

建立WebSocket连接的HTTP请求和响应就直接发送即可,因为它们都说文本格式的。但是WebSocket的数据帧是二进制的,所以就直接发送截图下面的二进制数据。
例如最后客户端主动关闭WebSocket连接的数据帧是:
2字节控制信息 + 4字节掩码 = 6字节的数据,这个就直接仿照上面抓取的包来发送即可了。

closeOutput.write((byte)0x88);
closeOutput.write((byte)0x80);
closeOutput.write(mask);

好了,介绍了这么多了,那么就开始我们最后的代码吧。代码写了很多注释了,如果有问题,可以在评论区留言。

模拟WebSocket客户端的 Java 代码

下面是模拟的代码了,完全就是仿照WireShark抓包的数据包格式,进行模拟的。但是,这里我注释了那行会导致数据压缩的首部。

package dragon;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class WebSocketClient {
	
	public static void main(String[] args) throws Exception {
		
		/**
		 * ws://127.0.0.1:9000/server/1
		 * */
		// 首先建立一个TCP连接,底层是TCP连接,至于更加底层的部分,我们不需要考虑。
		// Socket是对于TCP的一种封装,所以我们获取的数据其实只是TCP的数据部分(报文头部在这里是不可见的)
		Socket client = new Socket("127.0.0.1", 9000);
		// 获取输入输出流,HTTP或者是WebSocket对于Socket来说都是输入或者输出流
		// 全部使用缓冲流,提高程序的性能。
		InputStream input = new BufferedInputStream(client.getInputStream());
		OutputStream output = new BufferedOutputStream(client.getOutputStream());
		
		// 现在底层的网络连接已经具备了,即TCP连接已经建立,开始接下来的工作了。
		// 建立一个HTTP连接,websocket连接是需要通过HTTP来建立的,所以需要由客户端主动发起请求
		String requestMsg = "GET http://127.0.0.1:9000/server/1 HTTP/1.1\r\n" + 
				"Host: 127.0.0.1:9000\r\n" + 
				"Connection: Upgrade\r\n" + 
				"Pragma: no-cache\r\n" + 
				"Cache-Control: no-cache\r\n" + 
				"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36\r\n" + 
				"Upgrade: websocket\r\n" + 
				"Origin: chrome-search://local-ntp\r\n" + 
				"Sec-WebSocket-Version: 13\r\n" + 
				"Accept-Encoding: gzip, deflate, br\r\n" + 
				"Accept-Language: zh-CN,zh;q=0.9\r\n" + 
				"Sec-WebSocket-Key: z0hM8Z8r+RJwx6rCn+mzqg==\r\n" /* + 
				"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n" */
				+ "\r\n";  // 刚开始忘记了这个最后的 \r\n,导致程序无响应
		
		// 发送请求报文
		output.write(requestMsg.getBytes(StandardCharsets.UTF_8));
		// 刷新输出流
		output.flush();
		
		// 这里是一个粗略的处理,直接使用一个较大的数组读取所有的响应报文,然后直接输出
		// 这个输出流,即响应报文,表示已经建立了WebSocket连接了,但是我们可以忽略它,因为连接已经建立了。
		byte[] data = new byte[1024];
		int len = input.read(data);
		System.out.println("接收到的HTTP响应报文:");
		System.out.println(new String(data, 0, len, StandardCharsets.UTF_8));
		
		// 然后一个websocket连接就已经建立完毕了
		// 接下来就和HTTP没有关系了,完全回归了TCP的范围了。现在是属于WebSocket的内容了。
		
		// 当WebSocket连接建立时,服务器和客户端的通信形式是WebSocket数据帧
		// 它和HTTP报文的区别在于,数据帧可以由双方各自发起,没有先后顺序之分。
		// 而对于HTTP来说,必须由客户端主动发起,服务器被动响应,所以说它是基于请求响应式的。
		
		// WebSocket数据帧构建。
		// 数据帧包括开头的控制部分,以及接下来的负载部分(payload)
		ByteArrayOutputStream header = new ByteArrayOutputStream();
		
		// 这个和下面的形式一样,但是可以直观看到每一位的作用,但是使用不太方便。
//		header.write((byte)0b1100_0001);
//		header.write((byte)0b1010_0000);
//		header.write((byte)0b0100_1100);
//		header.write((byte)0b0110_1100);
//		header.write((byte)0b0011_1111);
//		header.write((byte)0b0000_1110);
		
		// 起始2字节 控制信息,至于这个值具体是多少,我是参考抓包的数据,直接使用的。
		// 因为这里的两字节其实是二进制形式的,具体的每一位都有不同的含义了。
		header.write((byte)0x81);
		header.write((byte)0x9f);
		// 掩码4字节 自定义一个浪漫的掩码:1314520
		byte[] mask = new byte[] {
				(byte)0x13,
				(byte)0x14,
				(byte)0x52,
				(byte)0x0
		};
		
		header.write(mask);	
		// payload
		// 对发送数据和掩码进行操作
		byte[] payload = "I love you yesterday and today!".getBytes(StandardCharsets.UTF_8);
		ByteArrayOutputStream maskPayload = new ByteArrayOutputStream();
		int count = 0; // 计数器
		byte temp1, temp2;
		for (byte b : payload) {
			temp1 = mask[count];
			temp2 = b;
			// 这里是很复杂的一个操作,但是它是协议中规定好的,只需要这样写即可。
			maskPayload.write((byte)((~temp1)&temp2) | (temp1&(~temp2)));
			count++;
			if (count == 4) {
				count = 0;  // 循环使用掩码
			}
		}
		
		// 发送应用数据
		output.write(header.toByteArray());      // websocket数据帧-->不包括数据体
		output.write(maskPayload.toByteArray()); // websocket数据帧--> 应用数据部分
		output.flush();
		
		System.out.println("服务器端响应的数据为:");
		// 接收数据: 2字节首部,剩下的是应用数据部分。
		len = input.read(data);
		int size = data[1];  // 第二字节的后7位表示长度,但是服务器发送的数据是没有进行掩码操作的,因此首位为0,可以直接使用(前提是payload长度  < 126)。
		System.out.println(new String(Arrays.copyOfRange(data, len-size, len), StandardCharsets.UTF_8));
		
		
		// 客户端主动关闭websocket连接,虽然可以直接关闭底层的socket连接,
		// 但是这样会产生一个问题,它是属于一种异常的关闭
		ByteArrayOutputStream closeOutput = new ByteArrayOutputStream();
		closeOutput.write((byte)0x88);
		closeOutput.write((byte)0x80);
		closeOutput.write(mask);
		
		output.write(closeOutput.toByteArray());
		output.flush();
		
		// 接收服务器最后的响应,即关闭连接的响应
		len = input.read(data);
		System.out.println("\nwebsocket关闭连接的最后报文,其本身形式是人不可读形式,所以应该以二进制形式打印,长度为:" + len + " 字节");
		// 这里包括2字节的控制部分,以及2字节的payload,即最后的status code。
		// 这个status code的意思是 Normal Closure 即正常关闭
		for (int i = 0; i < len; i++) {
			System.out.println(Arrays.toString(toBinaryString(Byte.toUnsignedInt(data[i]))));
		}
		
		// 关闭上层的websocket连接,然后最后关闭底层的socket连接,
		// 至于更底层的连接,这个不属于我们考虑的范围了。
		client.close();
	}
	
	// 一个自定义的工具类,用于将字节转成固定的8位二进制形式
	// 形参是int的原因是因为,byte是无符号的,但是Java没有无符号的数,所以只能转成int
	static char[] toBinaryString(int x) {
		// 将字节转成字符数组,每一位对应一个字符0/1
		char[] chs = new char[] {
				'0','0','0','0',
				'0','0','0','0'
		};
		
		// 注意口诀是:除2取余,逆序输出,所以需要倒过来存储。
		int i = 7;
		while (x != 0) {
			int a = x%2;
			x = x/2;
			chs[i--] = (a == 1 ? '1' : '0');
		}
		
		return chs;
	}
}

运行结果

客户端输出,服务器端数据不变。

接收到的HTTP响应报文:
HTTP/1.1 101 
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: kYmvW5MHdERfStkaIg8UFv4hboc=
Date: Thu, 31 Dec 2020 12:56:33 GMT


服务器端响应的数据为:
WebSocket Server: Time and tide wait for no man.

websocket关闭连接的最后报文,其本身形式是人不可读形式,所以应该以二进制形式打印,长度为:4 字节
[1, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 1, 1]
[1, 1, 1, 0, 1, 0, 0, 0]

说明

这里的代码基本上是很丑的,毕竟也是从不懂到懂开始写的,也没有进行提前的规划,只是感觉可以玩一玩就试了一下,后来太难了,我还准备放弃了呢!但是,也总算是多坚持了一会,找到了解决办法。通过这种方式的学习,我认为我自己对于WebSocket是有点理解了。如果别人问你WebSocket为什么是全双工的?相信你可以说一些自己的理解了。
不过,我现在还是不会WebSocket的编程,因为这里学习的是关于协议的一些知识,对于哪些实际的编程操作还是需要自己学习的!

附:

我写了一个GUI的客户端,在正确的操作下没有问题,但是代码写得也不是很好,就不贴出来了。如果有人感兴趣的话,那我就放到码云上面,这里放一个演示GIF吧。

在这里插入图片描述



参考资料

数据帧——WebSocket协议翻译
websocket 建立过程以及数据帧分析
WebSocket 和socket 的区别
WebSocket 教程
看完让你彻底搞懂Websocket原理

### 回答1: 【小滴课堂】websocket入门实战视课件是一门教授从基础到实际应用的WebSocket技术的课程。WebSocket是一种用于在客户端和服务器之间进行双向通信的协议,它允许实时的数据传输和即时通讯。这门课程的目的是帮助学员了解WebSocket的基本概念、原理和用法,并通过实战项目来巩固所学知识。 课程的第一部分是入门介绍,讲述了WebSocket的起源、发展和优势。学员将学会如何初始化和关闭WebSocket连接,了解WebSocket的生命周期和通信流程。 第二部分是WebSocket的基本概念和原理,包括握手过程、消息格式、心跳机制等。学员将学会如何通过WebSocket发送和接收消息,实现实时的双向通信。 第三部分是实战项目,通过一个实际的示例应用来演示WebSocket的使用。学员将学会搭建WebSocket服务器,处理不同类型的消息,实现群聊和私聊功能等。 课程的最后部分是课件,提供了学习WebSocket的详细文档和示例代码。学员可以随时查阅课件,复习和巩固所学内容。 通过【小滴课堂】websocket入门实战视课件,学员可以系统地学习和掌握WebSocket技术,为实际项目的开发提供了很好的基础。无论是Web开发还是移动应用开发,WebSocket都是一项非常有用的技术,能够提供更好的用户体验和功能。 ### 回答2: 【小滴课堂】websocket入门实战视课件是一门专注于教授websocket入门知识,并帮助学生通过实战视课件来巩固所学内容的在线课程。 websocket是一种在客户端和服务器之间建立持久连接的通信协议,它使得实时通信变得更加简单和高效。这门课程的目标是帮助学生理解websocket的基本概念和原理,并通过实际案例来实践使用websocket进行实时通信。 课程的内容安排从入门实战的顺序来进行。在入门部分,课程会介绍websocket的基本概念、特点和用途,并演示如何在网页中使用websocket进行实时通信。学生将学习如何在服务端和客户端配置websocket连接,并使用websocket进行双向通信。 接下来的部分将介绍websocket中的高级概念和技术,例如消息传输格式、错误处理和安全性等。学生将学习如何处理不同类型的消息和错误,并了解如何保护websocket连接的安全性。 在实战部分,课程将提供一系列的视觉课件,其中包含了实际的项目案例和练习。学生将根据课件的指导,使用websocket技术来实现不同类型的实时通信功能。这些案例将涵盖多个领域,例如在线聊天室、实时数据展示和多媒体传输等。 通过这门课程,学生将掌握websocket的基本理论知识,了解如何配置和使用websocket进行实时通信,并能够通过实践项目来巩固所学内容。这将为学生提供一个深入了解websocket技术和应用的机会,并为未来的开发工作奠定坚实的基础。 ### 回答3: 小滴课堂的《websocket入门实战》视课件是一套专门教授关于websocket相关知识的学习资料。本课程从入门实战,系统地介绍websocket的基本概念、原理、应用场景以及技术实现等方面的内容。 首先,课程通过准备章节,详细介绍websocket的相关背景知识,包括Ajax、HTTP协议、长轮询等概念,为学员提供了对websocket的前置了解。 接着,课程着重讲解了websocket的基本原理和工作流程。学员可以通过课件了解到websocket的握手过程、消息传递方式以及实现实时通信的原理等。课程还通过图示和实例代码,帮助学员深入理解websocket的相关概念和技术细节。 在实战部分,课件还提供了websocket的应用实例和具体开发案例。学员可以通过实践项目来巩固所学的知识。例如,通过编写一个在线聊天室的案例,学员能够实际运用websocket技术实现实时的双向通信,提升自己的技能和实践能力。 总体来说,小滴课堂的《websocket入门实战》视课件是一份全面和系统的学习资料,适合想要学习websocket相关知识的开发者或初学者使用。课件内容生动明了,通过图解和实例代码等形式,将复杂的websocket技术转化为易于理解和实践的知识,帮助学员快速上手和掌握websocket的开发技能。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值