Go 实现 WebSockets和什么是 WebSockets
作者:宇宙之一粟 发布时间:2024-04-26 17:15:42
前言
日常工作中,在不刷新页面的情况下发送消息并获得即时响应是我们认为理所当然的事情。但在过去,启用实时功能对开发人员来说是一个真正的挑战。开发者社区从 HTTP 长轮询和 AJAX 走过了漫长的道路,终于找到了构建真正实时应用程序的解决方案。
这个解决方案以 WebSockets 的形式出现,它可以在用户的浏览器和服务器之间打开一个交互式会话。 WebSockets 允许浏览器向服务器发送消息并接收事件驱动的响应,而无需轮询服务器以获取回复。
目前,WebSockets
是构建实时应用程序的第一大解决方案:在线游戏、即时通讯、跟踪应用程序等。
本文将解释 WebSockets
的运作方式,然后使用 Go 语言构建一个简单的 WebSocket 应用程序。
什么是 WebSockets
简而言之,WebSocket是一种 Web 技术,可以通过持久的单个套接字连接实现客户端和服务器之间的双向,全双工通信。WebSocket 是为 Web 应用程序开发人员提供基本上是一个接近原始的TCP通信层。
WebSocket 连接以 HTTP 请求/响应握手启动。如果此初始握手成功,则客户端和服务器已同意使用为 HTTP 请求作为 WebSocket 连接建立的现有 TCP / IP 连接。只要需要一旦 WebSocket 连接服务了它的目的,它可以通过关闭握手终止,客户端和服务器都可以启动。
WebSockets 标志着 Web 开发的转折点。直到 WebSockets 的出现,实时网络难以实现和慢于我们习惯于现在;它是通过使用像 Ajax 和 Comet (长)轮询的技术提供的技术,这些轮询没有真正优化用于实时应用。
WebSocket 技术具有广泛的适用性。您可以在不同的目的中使用它,例如后端服务之间的流数据,或者通过长期的全双工连接连接前端。简而言之,WebSockets 是架构事件驱动的系统和构建实时应用程序和服务的绝佳选择,在那里它必须随时随地提供数据所必需的数据。
我们可以将 WebSocket 用例大致分为两个不同的类别:
实时更新。通信是单向的,服务器将低延迟(通常是频繁的)更新流式传输到客户端。想想现场体育更新、警报、实时仪表板或位置跟踪,仅举几个用例
双向通信。客户端和服务器都发送和接收消息。示例包括聊天,虚拟事件和虚拟教室(最后两个通常涉及轮询,测验和 Q&AS )等功能。WebSocket 还可用于支撑多用户同步协作功能,例如同时编辑同一文档的多个人员
网络套接字与 WebSockets
网络套接字,或简称为套接字,用作在同一台计算机或同一网络上不同计算机上运行的应用程序之间交换数据的内部端点。
套接字是基于 Unix 和 Windows 的操作系统的关键部分,它们使开发人员更容易创建支持网络的软件。应用程序开发人员可以在他们的程序中包含套接字,而不是从头开始构建网络连接。由于网络套接字用于多种网络协议(HTTP、FTP 等),因此可以同时使用多个套接字。
套接字是由套接字的应用程序编程接口 (API) 定义的一组函数调用创建和使用的。
有几种类型的网络套接字:
数据报套接字(SOCK_DGRAM),也称为无连接套接字,使用用户数据报协议 (UDP)。数据报套接字支持双向消息流并保留记录边界。
流式套接字(SOCK_STREAM),也称为面向连接的套接字,使用传输控制协议 (TCP)、流控制传输协议 (SCTP) 或数据报拥塞控制协议 (DCCP)。这些套接字提供双向、可靠、有序且不重复的数据流,没有记录边界。
原始套接字(raw IP sockets) 通常在路由器和其他网络设备中可用。这些套接字通常是面向数据报的,尽管它们的确切特性取决于协议提供的接口。大多数应用程序不使用原始套接字。提供它们是为了支持新通信协议的开发,并提供对现有协议更深奥的设施的访问。
套接字通信
每个网络套接字由地址标识,地址是传输协议、IP 地址和端口号的三元组。
主机之间的通信主要有两种协议:TCP 和 UDP。让我们看看您的应用程序如何连接到 TCP 和 UDP 套接字。
连接到 TCP 套接字
为了建立 TCP 连接,Go 客户端使用 net 包中的 DialTCP 函数。 DialTCP 返回一个 TCPConn 对象。建立连接后,客户端和服务器开始交换数据:客户端通过 TCPConn 对象向服务器发送请求,服务器解析请求并发送响应,TCPConn 对象接收服务器的响应。
此连接保持有效,直到客户端或服务器关闭它。创建连接的函数如下:
客户端代码:
// init
tcpAddr, err := net.ResolveTCPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
conn, err := net.DialTCP(network, nil, tcpAddr)
if err != nil {
// handle error
}
// send message
_, err = conn.Write({message})
if err != nil {
// handle error
}
// receive message
var buf [{buffSize}]byte
_, err := conn.Read(buf[0:])
if err != nil {
// handle error
}
服务端代码:
// init
tcpAddr, err := net.ResolveTCPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
// handle error
}
// listen for an incoming connection
conn, err := listener.Accept()
if err != nil {
// handle error
}
// send message
if _, err := conn.Write({message}); err != nil {
// handle error
}
// receive message
buf := make([]byte, 512)
n, err := conn.Read(buf[0:])
if err != nil {
// handle error
}
连接到 UDP 套接字
与 TCP 套接字相比,使用 UDP 套接字时,客户端只需向服务器发送数据报。没有 Accept 函数,因为服务器不需要接受连接,只是等待数据报到达。
其他 TCP 函数有 UDP 对应函数;只需在上面的函数中将 TCP 替换为 UDP 即可。
客户端:
// init
raddr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
// handle error
}
conn, err := net.DialUDP("udp", nil, raddr)
if err != nil {
// handle error
}
.......
// send message
buffer := make([]byte, maxBufferSize)
n, addr, err := conn.ReadFrom(buffer)
if err != nil {
// handle error
}
.......
// receive message
buffer := make([]byte, maxBufferSize)
n, err = conn.WriteTo(buffer[:n], addr)
if err != nil {
// handle error
}
服务端:
// init
udpAddr, err := net.ResolveUDPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
// handle error
}
.......
// send message
buffer := make([]byte, maxBufferSize)
n, addr, err := conn.ReadFromUDP(buffer)
if err != nil {
// handle error
}
.......
// receive message
buffer := make([]byte, maxBufferSize)
n, err = conn.WriteToUDP(buffer[:n], addr)
if err != nil {
// handle error
}
来源:https://blog.51cto.com/yuzhou1su/5184571


猜你喜欢
- 一、概念介绍矩形树图(Treemap),即矩形式树状结构图,利用矩形的面积表示数值的大小,颜色用于类别区分,常用于呈现多类别的一维数值比较,
- 本文实例讲述了php数组索引与键值操作技巧。分享给大家供大家参考。具体如下:<?php $array = array("a&
- 很多小伙伴都会有这样的问题,说一个ip地址十分钟内之内注册一次,用来防止用户来重复注册带来不必要的麻烦逻辑:取ip,在数据库找ip是否存在,
- 在用sqlAlchemy写web应用的时候,经常会用json进行通信,跟json最接近的对象就是dict,有时候操作dict也会比操作ORM
- 说明:本例改编自《Python编程快速上手》。例子很简单我就不多说了 直接上代码,给初学python练手用。给你6次机会猜对一个预先生成好的
- 1.%格式符name = '李四'age = 18a = "姓名:%s,年龄:%s"%(name,age
- 全局变量与局部变量# num1是全局变量num1 = 1# num2是局部变量def func():num2 = 2在函数外(且不在函数里)
- 一、安装 FastAPI 和uvicorn可以使用 pip 命令进行安装:pip install fastapi uvicorn二、创建&n
- 技巧之一:提高使用Request集合的效率 访问一个ASP集合来提取一个值是费时的、占用计算资源的过程。因为这个操作包含了一系列对相关集合的
- 这一段时间,我在进行“09帮助中心升级”项目,负责其中的白板和视觉设计,总算和Axure有了第一次的正式会晤。由于之前已经零散地学习过一些A
- 前言对自己写的冗长代码,想重构但又无思路?小编整理了介绍python代码重构优化的一些方法,助你一臂之力。编写干净的 Pythonic 代码
- 一、介绍模块最小开发框架:基于python 的Pygame最小开发框架1、Pygame和sys模块import pygame #制
- ajax开发中, 常遇到下面的几种情况: 1 服务端需要返回一段普通文本给客户端 2 服务端需要返回一段HTML代码给客户端 3 服务端需要
- #mysqldump --help1.mysqldump的几种常用方法:(1)导出整个数据库(包括数据库中的数据)mysqldump -u
- 环境 python3.8pycharm2021.2知识点requests >>> pip install req
- 一、yield关键字实现方式以yield关键字方式实现协程代码如下所示:def fun1(): yield 1 &
- 我们去一个受欢迎的地方买东西,难免会需要排队等待。如果有多个窗口的话,就会有不同队列的产生,当然每个队伍的人数也会出现参差不齐的现象。我们今
- 管理认证系统最简单的方法是通过管理界面。然而,当你需要绝对的控制权的时候,有一些低层 API 需要深入专研,我们将在下面的章节中讨论它们。创
- 在html 5增加了新元素header、footer,测试过发现IE不能解析html 5新增的元素。代码如下:<!DOCTYPE&nb
- LSTM介绍关于LSTM的具体原理,可以参考:https://www.jb51.net/article/178582.htmhttps://