day3| 从socket部分继续学习

package mainimport ("fmt""log""net/http""github.com/gorilla/websocket"
)var UP = websocket.Upgrader{/*握手时间缓冲区(包括写和读)缓冲池指定用于生成HTTP错误响应的函数对过来的请求进行校验指定服务器是否应尝试根据进行协商消息压缩*/ReadBufferSize:  1024,WriteBufferSize: 1024,
}var conns []*websocket.Connfunc handler(w http.ResponseWriter, r *http.Request) {conn, err := UP.Upgrade(w, r, nil)if err != nil {log.Println(err)return}conns = append(conns, conn)for {m, p, e := conn.ReadMessage() //读取消息if e != nil {fmt.Println(err)break}for i := range conns {conns[i].WriteMessage(websocket.TextMessage, []byte(string(p)))//变成渣男了,可以对所有给他发消息的人进行说话}fmt.Println(m, string(p))}defer conn.Close()log.Println("服务关闭")
}
func main() {http.HandleFunc("/", handler)http.ListenAndServe(":8888", nil)}
package mainimport ("bufio""fmt""github.com/gorilla/websocket""os"
)func main() {dl := websocket.Dialer{} //这是websocket提供的的结构体/*一切提供的东西都和业务挂钩,和学习无关*/conn, _, err := dl.Dial("ws://127.0.0.1:8888", nil)if err != nil {fmt.Println(err)return}go send(conn)for {m, p, e := conn.ReadMessage()if e != nil {break}//只要连接还在,不断的读fmt.Println(m, string(p))}
}func send(conn *websocket.Conn) {for {reader := bufio.NewReader(os.Stdin)l, _, _ := reader.ReadLine()conn.WriteMessage(websocket.TextMessage, l)}
}

首先需要了解下列知识:

WebSocket 是一种在单个 TCP 连接上提供全双工通信的网络协议。它可以让客户端和服务器之间进行双向通信,而无需通过 HTTP 请求和响应。在理解 WebSocket 的底层代码知识时,以下是您可能需要了解的一些重要概念:

  1. 握手(Handshake)
  • WebSocket 通信始于一个 HTTP 握手过程,客户端发起 WebSocket 握手请求,服务器接受并响应这个请求,然后建立起 WebSocket 连接。

  • 握手过程通常发生在 HTTP/HTTPS 的特定端点上,例如 "/ws" 或 "/websocket"。

  1. 帧(Frame)
  • WebSocket 数据通过帧进行传输,每个帧代表了一个消息的一部分。

  • 帧可以是文本、二进制数据或控制帧。控制帧用于连接管理,例如关闭连接。

  1. 数据帧格式
  • 数据帧通常由几个字节的控制头部和数据部分组成。

  • 控制头部包括一些标志位和指示数据类型的信息,如数据是否被分片、数据类型(文本或二进制)、是否是最后一个片段等。

  1. 状态码(Status Codes)
  • WebSocket 握手过程和连接管理中使用了一系列状态码来表示不同的状态和结果。

  • 例如,101 表示握手成功,而 1006 表示连接异常关闭。

  1. 心跳(Heartbeat)
  • 为了保持连接活跃,WebSocket 可以周期性地发送心跳帧。

  • 心跳帧通常是空的或包含特定的数据,用于告知对端连接依然存在。

  1. 拓展(Extensions)
  • WebSocket 支持通过拓展机制增加协议的功能。

  • 拓展可以用于压缩数据、加密通信等目的。

  1. 子协议(Subprotocols)
  • WebSocket 握手阶段可以指定一个或多个子协议,以便客户端和服务器之间选择适当的通信协议。
  1. 安全性
  • WebSocket 连接的安全性可以通过使用 TLS/SSL 加密来保障。

  • 这通常通过在标准的 HTTP(S) 端口上启用 WebSocket,或者在自定义端口上使用 wss:// URL 来实现

gin包

r := gin.Default()/*GET 查  ->放在地址栏里面uri传参POST 增  ->参数在form /body /uriDELETE 删  -> uri同样也可以用bodyPUT 改   -> 参数在 form/body/uriRestful 就是这四款uri的格式:"/path/:id" 可以取得id只存在面试*/r.GET("/path/:id", func(c *gin.Context) {id := c.Param("id")//user是放在地址栏后面的,我们称为Query传参user := c.Query("user")//如果说想要有一个默认值user := c.DefaultQuery("user", "qimiao")、//就是我输入uri的时候是没有user这个值的,但是反馈到服务器是需要有的pwd := c.Query("pwd")c.JSONP(200, gin.H{"id":   id,"user": user,"pwd":  pwd,})})r.POST("/path", func(c *gin.Context) {/*form表单*/user := c.DefaultPostForm("user", "xzc")pwd := c.PostForm("pwd")c.JSONP(200, gin.H{"user": user,"pwd":  pwd,})})r.DELETE("/path/:id", func(c *gin.Context) {id := c.Param("id")//DELETE也可以解析表单c.JSONP(200, gin.H{"id":  id,})})r.PUT("/path", func(c *gin.Context) {/*form表单*/user := c.DefaultPostForm("user", "xzc")pwd := c.PostForm("pwd")c.JSONP(200, gin.H{"user": user,"pwd":  pwd,})})

接着来到第二课,接触了Bind,这个是啥嘞

有时候听他说话都听不懂,我心想第二遍肯定会好点

type PostParm struct {Name string `json:"name"`Age  int    `json:"age"`Sex  bool   `json:"sex"`
}
r := gin.Default()r.POST("/testBind", func(c *gin.Context) {var p PostParmerr := c.ShouldBind(&p)if err != nil {c.JSON(200, gin.H{"msg":  "wrong","data": gin.H{},})} else {c.JSON(200, gin.H{"msg":  "success","data": p,})}})

之后又增加了Query and uri的绑定形式

type PostParm struct {Name string `json:"name" uri:"name" form:"name"`Age  int    `json:"age" uri:"age" form:"age"`Sex  bool   `json:"sex" uri:"sex" form:"sex"`
}func main() {r := gin.Default()r.POST("/testBind", func(c *gin.Context) {var p PostParmerr := c.ShouldBindQuery(&p) //这里换上之后 上面的结构体会增加tag//err := c.ShouldBindURI(&p)if err != nil {c.JSON(200, gin.H{"msg":  "wrong","data": gin.H{},})} else {c.JSON(200, gin.H{"msg":  "success","data": p,})}})

还有一个shouldBind这里可以大致看一下

// If `GET`, only `Form` binding engine (`query`) used.// 如果是Get,那么接收不到请求中的Post的数据??// 如果是Post, 首先判断 `content-type` 的类型 `JSON` or `XML`, 然后使用对应的绑定器获取数据.// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48if c.ShouldBind(&person) == nil {log.Println(person.Name)log.Println(person.Address)log.Println(person.Birthday)}

如果是GET,那么这个方法就只会拿到query数据

如果是POST,会判断content-type的格式

//之后我们研究这个binding,这其实是一个表单验证的功能
type PostParm struct {Name string `json:"name" binding:"required"`Age  int    `json:"age" binding:"required"`Sex  bool   `json:"sex" biding:"required"`
}r.POST("/testBind", func(c *gin.Context) {var p PostParmerr := c.ShouldBindJSON(&p) //这里换上之后 上面的结构体会增加tagif err != nil {fmt.Println(err.Error())c.JSON(200, gin.H{"msg":  "wrong","data": gin.H{},})} else {c.JSON(200, gin.H{"msg":  "success","data": p,})}})

然后我们做了一个实验,如果我们只传入name这个参数,将会返回什么呢

image.png

image.png

这个是返回的一个错误,说我们age的必填项没有填

然后我们继续加限制

type PostParm struct {Name string `json:"name" `Age  int    `json:"age" binding:"required,mustBig"`Sex  bool   `json:"sex" `
}
//然后接下来的什么,这个mustBig又自己写了一个func mustBig(f1 validator.FieldLevel) bool {if f1.Field().Interface().(int) <= 18 {return false}return true
}//验证规则
/*
内部通过反射的形式判断年龄的大小是否符合标准*/
//main里面在 接收前也要编写一个if v, ok := binding.Validator.Engine().(*validator.Validate); ok {v.RegisterValidation("mustBig", mustBig)}

image.png

这个是报错的信息,说明它违反了mustBig的tag

r.POST("/testBind", func(c *gin.Context) {if v, ok := binding.Validator.Engine().(*validator.Validate); ok {v.RegisterValidation("mustBig", mustBig)//绑定一个注册规则}var p PostParmerr := c.ShouldBindJSON(&p) //这里换上之后 上面的结构体会增加tagif err != nil {fmt.Println(err.Error())c.JSON(200, gin.H{"msg":  "wrong","data": gin.H{},})} else {c.JSON(200, gin.H{"msg":  "success","data": p,})}})r.Run(":8080")

一般情况要使用ShouldBind,因为MustBind返回的code不好控制

ShouldBind有一个自定义验证

gin对于文件的接受和返回

前端给后端传文件

首先设置Header

image.png

然后再发送文件

联想截图_20240331215611.png

r.POST("/testUpload", func(c *gin.Context) {file, _ := c.FormFile("file")c.SaveUploadedFile(file, "./"+file.Filename) //接受一个文件的格式还有路径(保存位置)/*会返回一个文件流和err*/c.JSON(200, gin.H{"msg": file,})})
r := gin.Default()r.POST("/testUpload", func(c *gin.Context) {file, _ := c.FormFile("file")//将文件和postform都传给后台//接收文件in, _ := file.Open()defer in.Close()out, _ := os.Create("./" + file.Filename)//接受一个文件路径还有一个名字,用来搞清楚保存在哪里defer out.Close()io.Copy(out, in)//给前端返回文件c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment;filename=%s", file.Filename))c.File("./" + file.Filename)})

第二遍看需要自己手动写了

file, _ := c.FormFile("file")in, _ := file.Open()//打开文件并知晓其内容defer in.Close()out, _ := os.Create("./"+file.Filename)//在给定的路径下创建一个文件defer out.Close()io.Copy(out,in)//将一开始复制的文件中的内容复制到刚创建的文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/788485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RUST Rover 条件编译 异常处理

按官方处理发现异常 会报异常 error: failed to parse manifest at C:\Users\topma\RustroverProjects\untitled2\Cargo.toml 修改模式如下才能正常编译 网上说明 这样处理 [features] print-a [] print-b [] full ["print-a","print-b"]

Mybatis——一对多关联映射

一对多关联映射 一对多关联映射有两种方式&#xff0c;都用到了collection元素 以购物网站中用户和订单之间的一对多关系为例 collection集合的嵌套结果映射 创建两个实体类和映射接口 package org.example.demo;import lombok.Data;import java.util.List;Data public cla…

【TypeScript系列】与其它构建工具整合

与其它构建工具整合 构建工具 BabelBrowserifyDuoGruntGulpJspmWebpackMSBuildNuGet Babel 安装 npm install babel/cli babel/core babel/preset-typescript --save-dev.babelrc {"presets": ["babel/preset-typescript"] }使用命令行工具 ./node_…

P1002 过河卒:图论动态规划入门

本题链接&#xff1a;P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a; 本题与之前的动态规划不一样&#xff0c;比如背包问题和子序列问题等都是线性dp&#xff0c;也就是dp数组其实主要用于存储计算的结果&#xff0c;而这题…

面试算法6/400-和至少为 K 的最短子数组

题目 给你一个整数数组 nums 和一个整数 k &#xff0c;找出 nums 中和至少为 k 的 最短非空子数组 &#xff0c;并返回该子数组的长度。如果不存在这样的 子数组 &#xff0c;返回 -1 。 子数组 是数组中 连续 的一部分。 示例 1&#xff1a; 输入&#xff1a;nums [1], …

vue 基础回顾

vue 基础回顾 一、重要文件 node_modules&#xff1a;当前项目依赖的 js 包assets&#xff1a;静态资源存放目录(图片)components&#xff1a;公共组件存放目录App.vue&#xff1a;主组件&#xff0c;页面的入口文件main.js&#xff1a;整个项目入口文件package.json&#xf…

LabVIEW专栏二、调用子VI

该节目标是创建带子vi&#xff0c;修改vi属性&#xff0c;测试可重入和不可重入的区别 一 、设置子VI 把VI封装成为子VI&#xff0c;可以帮助模块化程序&#xff0c;简化代码结构。 任何VI本身都可以成为别的VI的子VI。 1.1、设置输入输出端子 1、在前面板空白处&#xff0…

Matlab|基于关键场景辨别算法的两阶段鲁棒微网优化调度

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该模型主要求解的是微网两阶段鲁棒优化调度问题&#xff0c;与目前大部分用CCG算法不同&#xff0c;模型创新性的采用关键场景辨别法&#xff0c;通过少量的迭代辨别出最恶劣的场景&#xff0c;针对光伏出力的…

obs直播推流 + ffmpeg参数

OBS 启动参数设为 --startstreaming &#xff0c; 可以让它启动后自动开始直播 对应ffmpeg参数&#xff1a; echo off :loop ffmpeg -re -i a.mp4 -r 24 -c:v libx264 -preset ultrafast -profile:v baseline -g 24 -keyint_min 24 -x264-params nal-hrdcbr -b:v 2500k -minr…

mybatis批量新增数据

数据量大的时候如果在循环中执行单条新增操作&#xff0c;是非常慢的。那么如何在mybatis中实现批量新增数据呢&#xff1f; 方法 insert 标签的 foreach 属性可以用于批量插入数据。您可以使用 foreach 属性遍历一个集合&#xff0c;并为集合中的每个元素生成一条插入语句。…

洛谷P1000超级玛丽游戏题解[Python, Rust, Go]

题目 打印超级玛丽字符图像 小技巧 直接复制题目的超级玛丽符号首行会有空格问题&#xff0c;一直AC不过&#xff0c;一行一行地复制就OK了&#x1f44c;。 Rust 题解 fn main() {println!(" ********************####....#.#..###.....##....###...…

pip和conda 设置安装源

pip和conda 设置安装源 conda查看 channels添加 channels移除 channelschannels 配置文件 pip查看 index-url添加 index-url移除 index-urlindex-url 配置文件 常用源 conda 查看 channels conda config --show channels添加 channels conda config --add channels https:/…

企业周年庆3d云展厅促进了客企间交流与互动

在数字化浪潮席卷而来的今天&#xff0c;传统的展示方式已难以满足现代人对信息获取与体验的高标准需求。为此&#xff0c;一种革命性的展示方式——线上3D虚拟展厅应运而生&#xff0c;以其独特的魅力逐渐引领展示方式的革新。 线上3D虚拟展厅开发&#xff0c;不仅为参与者带来…

JVM垃圾收集——相关概念

本贴讲解的内容包括System.gc()、内存溢出、内存泄漏、STW机制以及垃圾收集的串行、并行、并发三种情况&#xff0c;还有强引用、软引用、弱引用、虚引用四种引用。 1、System.gc()的理解 在默认情况下&#xff0c;通过System.gc()或者Runtime.getRuntime().gc()的调用&#…

k8s 加 jenkins 和 gitlab 结合 maven生成快速devops平台内网快速部署

要实现Docker、Jenkins和GitLab的结合&#xff0c;以及通过Maven生成快速DevOps平台内网快速部署&#xff0c;可以按照以下步骤进行操作&#xff1a; 安装Docker&#xff1a;首先需要在服务器上安装Docker&#xff0c;可以根据操作系统的不同&#xff0c;参考Docker官方文档进行…

提升常州小程序软件开发的搜索排名:关键步骤解析

在移动互联网的浪潮中&#xff0c;小程序作为连接用户与服务的桥梁&#xff0c;其重要性日益凸显。对于常州的小程序软件开发企业来说&#xff0c;如何让自己的产品在浩如烟海的互联网信息中脱颖而出&#xff0c;提升搜索排名&#xff0c;成为了亟待解决的问题。本文将为您解析…

HarmonyOS 应用开发之自定义组件冻结功能

自定义组件处于非激活状态时&#xff0c;状态变量将不响应更新&#xff0c;即Watch不会调用&#xff0c;状态变量关联的节点不会刷新。通过freezeWhenInactive属性来决定是否使用冻结功能&#xff0c;不传参数时默认不使用。支持的场景有&#xff1a;页面路由&#xff0c;TabCo…

完美解决layui多图上传时,动态给每个图片增加参数

需求&#xff1a;当我在使用layui框架上传多图时&#xff0c;我想动态给每一张图都把它的名称传给后台 data: {id: function(){return $(#id).val();} } 这是官网给的动态传参的方法 我自己根据官网给的案例设置 data:{filesIndex:function(index, file){return file.name}},…

什么是智慧公厕?智慧旅游下的智慧公厕功能和特点

智慧旅游下的智慧公厕功能和特点&#xff1f;智慧旅游是景区、公园、游乐场、文化场馆等领域的一种信息化解决方案&#xff0c;智慧公厕是智慧旅游极为重要的一部分&#xff0c;能大大提升游客满意度。智慧公厕采用物联网、互联网、大数据、云计算等技术&#xff0c;实现旅游景…

gitlab备份与恢复

1.1.1 查看系统版本和软件版本 cat /etc/debian_version cat /opt/gitlab/embedded/service/gitlab-rails/VERSION 1.1.2 数据备份 打开/etc/gitlab/gitlab.rb配置文件&#xff0c;查看一个和备份相关的配置项 sudo vim /etc/gitlab/gitlab.rb gitlab_rails[backup_path] &q…