Go语言笔记:UDP基础使用与广播

news2024/10/6 1:45:10

文章目录

  • 目的
  • 基础说明
  • 作为服务器使用
  • 作为客户端使用
  • 广播
  • 总结

目的

UDP是比较基础常用的网络通讯方式,这篇文章将介绍Go语言中UDP基础使用的一些内容。

本文中使用 Packet Sender 工具进行测试,其官网地址如下:
https://packetsender.com/

基础说明

UDP是一种面向无连接的通讯,抛开业务逻辑来说UDP使用上不需要像TCP那样先建立连接才能使用,收就是收、发就是发,干净利落。

很多语言中UDP使用一般逻辑如下:

  1. 建立UDP类型Socket对象,用于数据收发;
  2. 发送时只需要指定 对方地址与端口号 就可以发送数据;
  3. 接收的话只需要监听 自身某个端口号
  4. 如果要实现双向通讯可以使用同一个Socket对象进行监听与发送;
  5. 很多时候都有一对一通讯的需求,所以标准库中都提供了一些面向连接的方法。但其实这只是在应用层面上的处理而已,实际上底层还是收就是收发就是发;

这里特别想要吐槽的一点是Go标准库使用UDP收发数据并不是给的Socket对象,而都是需要通过 UDPConn 这个对象,这个思路就是上面的第5条思路了。我个人使用UDP单发送时比较喜欢上面第2条的方式,就是单纯的发送。在Go中找了半天没有找到这种可以直接发送的方式,感觉挺变扭的。

本文中用到的一些函数与方法如下:

// 从字符串获得IP地址
func ResolveUDPAddr(network, address string) (*UDPAddr, error)

// 建立UDP(预)连接
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
// 启动UDP监听
func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)

// 建立连接的情况下发送数据
func (c *UDPConn) Write(b []byte) (int, error)
// 建立连接的情况下读取数据
func (c *UDPConn) Read(b []byte) (int, error)

// 获取远程地址
func (c *UDPConn) RemoteAddr() Addr

// 接收数据并获得远程地址
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error)
// 向指定地址发送数据
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

作为服务器使用

下面是个作为服务器使用的简单例子,功能是监听指定端口号,收到数据时输出到控制台,然后向远程端应答消息:

package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	udpAddr, err := net.ResolveUDPAddr("udp4", ":22333") // 转换地址,作为服务器使用时需要监听本机的一个端口
	checkError(err)
	conn, err := net.ListenUDP("udp", udpAddr) // 启动UDP监听本机端口
	checkError(err)

	for {
		var buf [128]byte
		len, addr, err := conn.ReadFromUDP(buf[:]) // 读取数据,返回值依次为读取数据长度、远端地址、错误信息 // 读取操作会阻塞直至有数据可读取
		checkError(err)
		fmt.Println(string(buf[:len])) // 向终端打印收到的消息

		_, err = conn.WriteToUDP([]byte("233~~~"), addr) // 写数据,返回值依次为写入数据长度、错误信息 // WriteToUDP()并非只能用于应答的,只要有个远程地址可以随时发消息
		checkError(err)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error %s", err.Error())
		os.Exit(1)
	}
}

在这里插入图片描述

作为客户端使用

作为客户端使用也不复杂,下面是个简单的示例:

package main

import (
	"fmt"
	"net"
	"os"
	"time"
)

func main() {
	udpAddr, err := net.ResolveUDPAddr("udp4", "192.168.31.189:53771") // 转换地址,作为客户端使用要向远程发送消息,这里用远程地址与端口号
	checkError(err)
	conn, err := net.DialUDP("udp", nil, udpAddr) // 建立连接,第二个参数为nil时通过默认本地地址(猜测可能是第一个可用的地址,未进行测试)发送且端口号自动分配,第三个参数为远程端地址与端口号
	checkError(err)

	go receive(conn) // 使用DialUDP建立连接后也可以监听来自远程端的数据

	for {
		_, err = conn.Write([]byte("naisu233~~~")) // 向远程端发送消息
		checkError(err)
		time.Sleep(4 * time.Second) // 等待4s
	}
}

func receive(conn *net.UDPConn) {
	for {
		var buf [128]byte
		len, err := conn.Read(buf[0:]) // 读取数据 // 读取操作会阻塞直至有数据可读取
		checkError(err)
		fmt.Println(string(buf[0:len]))
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error %s", err.Error())
		os.Exit(1)
	}
}

在这里插入图片描述

广播

广播主要就是指发送时向内网中所有设备发送消息了,操作上最主要就是发送消息时地址使用 广播地址 ,广播地址计算方式可以参考下面文章:

《UDP IPv4广播地址计算(附Node.js示例代码)》
https://blog.csdn.net/Naisu_kun/article/details/127221349

下面是Go中广播地址获取代码:

// 返回广播地址列表
func GetBroadcastAddress() ([]string, error) {
	broadcastAddress := []string{}

	interfaces, err := net.Interfaces() // 获取所有网络接口
	if err != nil {
		return broadcastAddress, err
	}

	for _, face := range interfaces {
		// 选择 已启用的、能广播的、非回环 的接口
		if (face.Flags & (net.FlagUp | net.FlagBroadcast | net.FlagLoopback)) == (net.FlagBroadcast | net.FlagUp) {
			addrs, err := face.Addrs() // 获取该接口下IP地址
			if err != nil {
				return broadcastAddress, err
			}
			for _, addr := range addrs {
				if ipnet, ok := addr.(*net.IPNet); ok { // 转换成 IPNet { IP Mask } 形式
					if ipnet.IP.To4() != nil { // 只取IPv4的
						var fields net.IP // 用于存放广播地址字段(共4个字段)
						for i := 0; i < 4; i++ {
							fields = append(fields, (ipnet.IP.To4())[i]|(^ipnet.Mask[i])) // 计算广播地址各个字段
						}
						broadcastAddress = append(broadcastAddress, fields.String()) // 转换为字符串形式
					}
				}
			}
		}
	}

	return broadcastAddress, nil
}

因为工作原因我的电脑上有非常多的实体的或是虚拟的网卡,下面是我电脑上部分网络情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面是广播地址获取演示:
在这里插入图片描述

需要注意的是如果设备上有多个网卡的话就可能有多个广播地址,要全局广播的话就要向每个广播地址分别发送消息。操作上来说可以用服务器的方式,拿到 UDPConn 对象后使用 WriteToUDP 方法分别向各个广播地址发送消息。

总结

UDP的使用比较简单,这里没有提及的是组播和任意播功能,因为我不太用这两种所以这里也就不介绍了。

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

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

相关文章

知识站点上关于Notes Domino话题几个问答

大家好&#xff0c;才是真的好。 今天周一我们继续不讲技术&#xff0c;介绍一下知识网站上关于Notes/Domino几个有趣问题的讨论。 国内的知识网站头把交椅是知乎&#xff0c;在中文界中是扛把子.不过在国外&#xff0c;最流行的知识网站叫做Quora&#xff0c;上面关于Notes/…

【Java】【系列篇】【Spring源码解析】【三】【体系】【PostProcessors体系】

PostProcessor英文翻译为后置处理器&#xff0c;在Spring体系里面主要针对的对象为Bean和BeanFactory.有着收尾或完善的作用。一、BeanPostProcessor分支 1.1、作用 在Bean对象在实例化和依赖注入完毕后&#xff0c;在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean…

【学习笔记】【Pytorch】十六、模型训练套路

【学习笔记】【Pytorch】十六、模型训练套路一、内容概述二、模型训练套路1.代码实现&#xff1a;CPU版本2.代码实现&#xff1a;优先GPU版本a3.代码实现&#xff1a;优先GPU版本b4.计算测试集上的正确率三、使用免费GPU训练模型一、内容概述 本内容主要是介绍一个完整的模型训…

信用评分分卡简介

背景 随着金融科技初创企业的兴起&#xff0c;过去 5 年中出现了许多新的消费信贷机构&#xff0c;与传统银行展开竞争。他们通常瞄准银行认为规模太小或因金融危机期间发生的后期损失而不得不削减贷款的细分市场。通俗的讲就是消费金融公司瞄准了银行的次贷市场。 这些新的消…

【C语言】文件操作修改通讯录(升级版本)可以存储数据

文件操作的内容&#xff0c;我们在上文已经学习了&#xff0c;那么如果有不明白的小伙伴请看这篇文章 【C语言】小王带您实现文件操作&#xff08;简单图示讲解&#xff09;_小王学代码的博客-CSDN博客 通讯录我们在之前也学习实现了静态、动态通讯录 【C语言】使用C语言实现静…

分享80个PHP源码,总有一款适合您

PHP源码 分享80个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 80个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1yJ1aR6vt2kDjiVyqj0gPuw?pwdlfl9 提取码&#xff…

深信服EDR任意用户登录与命令执行漏洞

深信服EDR任意用户登录与命令执行漏洞1.深信服EDR简介2.深信服EDR漏洞2.1.后台任意用户登录漏洞2.1.1.漏洞描述2.1.2.影响版本2.1.3.漏洞复现2.2.任意命令执行漏洞2.2.1.漏洞描述2.2.2.影响版本2.2.3.漏洞复现2.2.3.1.构建URL2.2.3.2.效果1.深信服EDR简介 终端检测响应平台&…

C生万物 | 使用宏将一个整数的二进制位的奇数位和偶数位交换

&#x1f451;作者主页&#xff1a;Fire_Cloud_1 &#x1f3e0;学习社区&#xff1a;烈火神盾 &#x1f517;专栏链接&#xff1a;万物之源——C 淋漓尽致——位运算✒题目分析 && 实现思路[位运算]1、获取这个整数的奇数位和偶数位2、使用移位运算使【奇变偶】【偶变奇…

如何通过限流算法防止系统过载

限流算法&#xff0c;顾名思义&#xff0c;就是指对流量进行控制的算法&#xff0c;因此也常被称为流控算法。 我们在日常生活中&#xff0c;就有很多限流的例子&#xff0c;比如地铁站在早高峰的时候&#xff0c;会利用围栏让乘客们有序排队&#xff0c;限制队伍行进的速度&am…

扫雷——“C”

各位uu们我又来啦&#xff0c;今天&#xff0c;小雅兰给大家介绍的又是一个小游戏&#xff0c;就是扫雷这款游戏&#xff0c;这个游戏和我昨天给大家介绍的三子棋游戏有异曲同工之妙&#xff0c;相信很多人都玩过&#xff0c;话不多说&#xff0c;我们进入正题吧. 《扫雷》是一…

【学习笔记】【Pytorch】十七、模型测试套路

【学习笔记】【Pytorch】十七、模型测试套路一、内容概述二、模型测试套路代码实现一、内容概述 利用已经训练好的模型&#xff0c;然后给它提供输入&#xff0c;判断输出是否正确&#xff0c;即模型的应用测试。 在模型测试也会有一些坑&#xff1a; 神经网络的输入一般是4…

【错误记录】Kotlin 代码编译时报错 ( Variable ‘name‘ must be initialized | 初始化块定义在所有属性之后 )

文章目录一、报错信息二、问题分析三、解决方案 ( 初始化块定义在所有属性之后 )一、报错信息 在 Kotlin 中 , init 初始化块 要 定义在所有成员属性之后 ; 如果在 init 初始化块 中 , 使用到了 成员属性 , 有可能出现 编译时报错信息 ; 报错代码示例 : class Hello{init {va…

seata安装及配置

1.下载 下载地址&#xff1a;https://github.com/seata/seata/tags 本文选用seata-1.4.2版 2.解压 tar -zxvf seata-server-1.4.2.tar.gz 3. 初始化数据库 登录mysql&#xff0c;然后创建数据库和数据表&#xff1a; -- -------------------------------- The script used…

【Java】【系列篇】【Spring源码解析】【三】【体系】【Environment体系】

整体结构图 本篇文章仅作简单了解&#xff0c;详细还等到Springboot系列里面详解PropertyResolver 作用 用于针对任何基础源解析属性(Property)的接口 方法解析 // 查看规定指定的key是否有对应的value 对应key的值是null的话也算是不能解析 boolean containsProperty(Stri…

持续丰富营销玩法 东风标致408X引领品牌向上焕新

1月5日&#xff0c;东风标致408X首秀——XSHOW开演&#xff0c;标致全球战略车型408X正式在中国亮相&#xff0c;定位为“新法式无界座驾”&#xff0c;它是东风标致全面向电动化、智能化、网联化的发展的一款汽车&#xff0c;也是引领东风标致向上焕新的一款全新车型。作为东风…

十五天学会Autodesk Inventor,看完这一系列就够了(终章),答疑

众所周知&#xff0c;Autocad是一款用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;现已经成为国际上广为流行的绘图工具。Autodesk Inventor软件也是美国AutoDesk公司推出的三维可视化实体模拟软件。因为很多人都熟悉Autocad&#xff0c;所以再学习Inventor&…

python SciPy 优化器

SciPy 优化器SciPy 的 optimize 模块提供了常用的最优化算法函数实现&#xff0c;我们可以直接调用这些函数完成我们的优化问题&#xff0c;比如查找函数的最小值或方程的根等。NumPy 能够找到多项式和线性方程的根&#xff0c;但它无法找到非线性方程的根&#xff0c;如下所示…

工具类库 Hutool介绍与使用(请记得收藏)

工具类库 Hutool介绍 Hutool是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&#xff0c;使Java拥有函数式语言般的优雅&#xff0c;让Java语言也可以“甜甜的”。Hutool中的工具方法来自于每个用户的精雕…

VMware vCenter上用OVF模板部署虚拟机

前言 在我们项目操作过程中&#xff0c;使用VMware vCenter系统&#xff0c;经常会出现使用原有部署环境来部署虚拟机&#xff0c;供项目组使用&#xff0c;此时我们克隆虚拟机就要用到OVF模板来克隆操作&#xff0c;这是一个非常实用的功能。 一、打开Vcenter&#xff0c;选定…

Redis学习笔记2_数据结构

Redis数据结构Redis数据结构二、数据结构2.1Redis核心对象2.2底层数据结构2.2.1 SDS-simple dynamic stringsds内存布局sds的操作为什么使用SDS&#xff0c;SDS的优势&#xff1f;2.2.2 listlist内存布局2.2.3 dictdict内存布局2.2.4 zskiplistzskiplist内存布局2.2.5 intsetin…