UDP程序设计

news2024/11/17 21:32:21

UDP协议概述

UDP,User Datagram Protocol,用户数据报协议,是一个简单的面向数据报(package-oriented)的传输层协议,规范为:RFC 768。

UDP提供数据的不可靠传递,它一旦把应用程序发给网络层的数据发送出去,就不保留数据备份。缺乏可靠性,缺乏拥塞控制(congestion control)。

基本示例

由于UDP是“无连接”的,所以服务器端不需要创建监听套接字,只需要监听地址,等待客户端与之建立连接,即可通信。

net包支持的典型UDP函数:

 // 解析UDPAddr
 func ResolveUDPAddr(network, address string) (*UDPAddr, error)
 // 监听UDP地址
 func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)
 // 连接UDP服务器
 func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
 // UDP读
 func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error)
 // UDP写
 func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

编写示例,一次读写操作:

服务端流程:

  • 解析UDP地址

  • 监听UDP

  • 读内容

  • 写内容

 func UDPServerBasic() {
     // 1.解析地址
     laddr, err := net.ResolveUDPAddr("udp", ":9876")
     if err != nil {
         log.Fatalln(err)
     }
 ​
     // 2.监听
     udpConn, err := net.ListenUDP("udp", laddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())
     defer udpConn.Close()
 ​
     // 3.读
     buf := make([]byte, 1024)
     rn, raddr, err := udpConn.ReadFromUDP(buf)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())
 ​
     // 4.写
     data := []byte("received:" + string(buf[:rn]))
     wn, err := udpConn.WriteToUDP(data, raddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())
 }
 ​

客户端流程:

  • 建立连接

  • 写操作

  • 读操作

 func UDPClientBasic() {
     // 1.建立连接
     raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
     if err != nil {
         log.Fatalln(err)
     }
     udpConn, err := net.DialUDP("udp", nil, raddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Println(udpConn)
 ​
     // 2.写
     data := []byte("Go UDP program")
     wn, err := udpConn.Write(data) // WriteToUDP(data, raddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())
 ​
     // 3.读
     buf := make([]byte, 1024)
     rn, raddr, err := udpConn.ReadFromUDP(buf)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())
 }

测试:

 > go test -run UDPServerBasic
 2023/05/25 17:26:34 UDP server is listening on [::]:9876
 2023/05/25 17:29:22 received Go UDP program from 127.0.0.1:58657
 2023/05/25 17:29:24 send received:Go UDP program(23) to 127.0.0.1:58657
 > go test -run UDPClientBasic
 2023/05/25 17:29:22 &{{0xc000108f00}}
 2023/05/25 17:29:22 send Go UDP program(14) to 127.0.0.1:9876
 2023/05/25 17:29:24 received received:Go UDP program from 127.0.0.1:9876

connected和unconnected的UDPConn

UDP的连接分为:

  • 已连接,connected, 使用方法 DialUDP建立的连接,称为已连接,pre-connected

  • 未连接,unconnected,使用方法 ListenUDP 获得的连接,称为未连接,not connected

如果 *UDPConnconnected,读写方法 ReadWrite。 如果 *UDPConnunconnected,读写方法 ReadFromUDPWriteToUDP

主要的差异在写操作上。读操作如果使用混乱,不会影响读操作本身,但一些参数细节上要注意:

示例:获取远程地址,conn.RemoteAddr()

unconnected,ListenUDP

 func UDPServerConnect() {
     // 1.解析地址
     laddr, err := net.ResolveUDPAddr("udp", ":9876")
     if err != nil {
         log.Fatalln(err)
     }
 ​
     // 2.监听
     udpConn, err := net.ListenUDP("udp", laddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())
     defer udpConn.Close()
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 ​
     // 3.读
     buf := make([]byte, 1024)
     rn, raddr, err := udpConn.ReadFromUDP(buf)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 ​
     // 4.写
     data := []byte("received:" + string(buf[:rn]))
     wn, err := udpConn.WriteToUDP(data, raddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 }

测试:

 > go test -run UDPServerConnect
 2023/05/25 18:24:19 UDP server is listening on [::]:9876
 2023/05/25 18:24:19 <nil>
 2023/05/25 18:24:32 received Go UDP program from 127.0.0.1:63583
 2023/05/25 18:24:35 <nil>
 2023/05/25 18:24:35 send received:Go UDP program(23) to 127.0.0.1:63583
 2023/05/25 18:24:35 <nil>

connected,DialUDP

 func UDPClientConnect() {
     // 1.建立连接
     raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
     if err != nil {
         log.Fatalln(err)
     }
     udpConn, err := net.DialUDP("udp", nil, raddr)
     if err != nil {
         log.Fatalln(err)
     }
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 ​
     // 2.写
     data := []byte("Go UDP program")
     wn, err := udpConn.Write(data) // WriteToUDP(data, raddr)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 ​
     // 3.读
     buf := make([]byte, 1024)
     rn, raddr, err := udpConn.ReadFromUDP(buf)
     if err != nil {
         log.Fatalln(err)
     }
     log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())
 ​
     // 测试输出远程地址
     log.Println(udpConn.RemoteAddr())
 }

测试:

> go test -run UDPClientConnect
2023/05/25 18:24:32 127.0.0.1:9876
2023/05/25 18:24:32 send Go UDP program(14) to 127.0.0.1:9876
2023/05/25 18:24:32 127.0.0.1:9876
2023/05/25 18:24:35 received received:Go UDP program from 127.0.0.1:9876
2023/05/25 18:24:38 127.0.0.1:9876

示例:connected+WriteToUDP错误

udpConn, err := net.DialUDP("udp", nil, raddr)
wn, err := udpConn.WriteToUDP(data, raddr)

测试:

> go test -run UDPClientConnect
2023/05/25 18:27:41 127.0.0.1:9876
2023/05/25 18:27:41 write udp 127.0.0.1:52787->127.0.0.1:9876: use of WriteTo with pre-connected connection

示例:unconnected+Write错误

udpConn, err := net.ListenUDP("udp", laddr)
wn, err := udpConn.Write(data)

测试:

write udp [::]:9876: wsasend: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.

Read的使用尽量遵循原则,但语法上可以混用,内部有兼容处理。

对等服务端和客户端

函数

func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)

可以直接返回UDPConn,是unconnected状态。在编程时,我们的客户端和服务端都可以使用该函数建立UDP连接。而不是一定要在客户端使用DialUDP函数。

这样创建的客户端和服务端时对等的关系。适用于例如广播类的网络通信项目中。

示例代码:

server:

func UDPServerPeer() {
	// 1.解析地址
	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
	if err != nil {
		log.Fatalln(err)
	}

	// 2.监听
	udpConn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())
	defer udpConn.Close()

	// 远程地址
	raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:6789")
	if err != nil {
		log.Fatalln(err)
	}

	// 3.读
	buf := make([]byte, 1024)
	rn, raddr, err := udpConn.ReadFromUDP(buf)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())

	// 4.写
	data := []byte("received:" + string(buf[:rn]))
	wn, err := udpConn.WriteToUDP(data, raddr)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())
}

client:

func UDPClientPeer() {
	// 1.解析地址
	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:6789")
	if err != nil {
		log.Fatalln(err)
	}
	// 2.监听
	udpConn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())
	defer udpConn.Close()

	// 远程地址
	raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
	if err != nil {
		log.Fatalln(err)
	}

	// 2.写
	data := []byte("Go UDP program")
	wn, err := udpConn.WriteToUDP(data, raddr)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("send %s(%d) to %s\n", string(data), wn, raddr.String())

	// 3.读
	buf := make([]byte, 1024)
	rn, raddr, err := udpConn.ReadFromUDP(buf)
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("received %s from %s\n", string(buf[:rn]), raddr.String())
}

测试:

> go test -run UDPServerPeer
2023/05/25 19:08:34 UDP server is listening on 127.0.0.1:9876
2023/05/25 19:08:46 received Go UDP program from 127.0.0.1:6789
2023/05/25 19:08:46 send received:Go UDP program(23) to 127.0.0.1:6789
> go test -run UDPClientPeer
2023/05/25 19:08:46 UDP server is listening on 127.0.0.1:6789
2023/05/25 19:08:46 send Go UDP program(14) to 127.0.0.1:9876
2023/05/25 19:08:46 received received:Go UDP program from 127.0.0.1:9876

多播编程

多播(Multicast)方式的数据传输是基于 UDP 完成的。与 UDP 服务器端/客户端的单播方式不同,区别是,单播数据传输以单一目标进行,而多播数据同时传递到加入(注册)特定组的大量主机。换言之,采用多播方式时,可以同时向多个主机传递数据。

多播的特点如下:

  • 多播发送端针对特定多播组

  • 发送端发送 1 次数据,但该组内的所有接收端都会接收数据

  • 多播组数可以在 IP 地址范围内任意增加

如图所示:

image.png

多播组是 D 类IP地址(224.0.0.0~239.255.255.255):

  • 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;

  • 224.0.1.0~224.0.1.255是公用组播地址,Internetwork Control Block;

  • 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;

  • 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效

Go的标准库net支持多播编程,主要的函数:

func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error)

用于创建多播的UDP连接。

示例:多播通信

接收端端

// 多播接收端
func UDPReceiverMulticast() {
	// 1.多播监听地址
	address := "224.1.1.2:6789"
	gaddr, err := net.ResolveUDPAddr("udp", address)
	if err != nil {
		log.Fatalln(err)
	}

	// 2.多播监听
	udpConn, err := net.ListenMulticastUDP("udp", nil, gaddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())

	// 3.接受数据
	// 循环接收
	buf := make([]byte, 1024)
	for {
		rn, raddr, err := udpConn.ReadFromUDP(buf)
		if err != nil {
			log.Println(err)
		}
		log.Printf("received \"%s\" from %s\n", string(buf[:rn]), raddr.String())
	}

}

发送端:

// 多播的发送端
func UDPSenderMulticast() {
	// 1.建立UDP多播组连接
	address := "224.1.1.2:6789"
	raddr, err := net.ResolveUDPAddr("udp", address)
	if err != nil {
		log.Fatalln(err)
	}
	udpConn, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()

	// 2.发送内容
	// 循环发送
	for {
		data := fmt.Sprintf("[%s]: %s", time.Now().Format("03:04:05.000"), "hello!")
		wn, err := udpConn.Write([]byte(data))
		if err != nil {
			log.Println(err)
		}
		log.Printf("send \"%s\"(%d) to %s\n", data, wn, raddr.String())

		time.Sleep(time.Second)
	}
}

测试:

启动发送端:

# go test -run UDPSenderMulticast
2023/05/26 16:36:43 send "[04:36:43.976]: hello!"(22) to 224.1.1.2:6789
2023/05/26 16:36:44 send "[04:36:44.977]: hello!"(22) to 224.1.1.2:6789
2023/05/26 16:36:45 send "[04:36:45.979]: hello!"(22) to 224.1.1.2:6789
2023/05/26 16:36:46 send "[04:36:46.980]: hello!"(22) to 224.1.1.2:6789

启动多个接收端,也可以在过程中继续启动:

# go test -run UDPReceiverMulticast
2023/05/26 16:36:00 UDP server is listening on 0.0.0.0:6789
2023/05/26 16:36:00 received "[04:36:43.499]: hello!" from 192.168.50.130:56777
2023/05/26 16:36:01 received "[04:36:43.500]: hello!" from 192.168.50.130:56777
2023/05/26 16:36:02 received "[04:36:43.500]: hello!" from 192.168.50.130:56777
# go test -run UDPReceiverMulticast
2023/05/26 16:36:00 UDP server is listening on 0.0.0.0:6789
2023/05/26 16:36:00 received "[04:36:43.499]: hello!" from 192.168.50.130:56777
2023/05/26 16:36:01 received "[04:36:44.500]: hello!" from 192.168.50.130:56777
2023/05/26 16:36:02 received "[04:36:45.500]: hello!" from 192.168.50.130:56777

附:Goland远程开发步骤截图:

  • 建立ssh连接

  • 打开项目

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

广播编程

广播地址,Broadcast,指的是将消息发送到在同一广播网络上的每个主机。

例如对于网络:

# ip a
ens33: <BROADCAST,MULTICAST,UP,LOWER_UP>
inet 192.168.50.130/24 brd 192.168.50.255

来说,IP ADDR 就是 192.168.50.130/24, 广播地址就是 192.168.50.255

意味着,只要发送数据包的目标地址(接收地址)为192.168.50.255时,那么该数据会发送给该网段上的所有计算机。

如图:

image.png

编码实现:

编码时数据发的发送端,同样使用 ListenUDP 方法建立UDP连接,调用WriteToUDP完成数据的发送。就是上面的对等服务端和客户端模式。

接收端:

// 广播接收端
func UDPReceiverBroadcast() {
	// 1.广播监听地址
	laddr, err := net.ResolveUDPAddr("udp", ":6789")
	if err != nil {
		log.Fatalln(err)
	}

	// 2.广播监听
	udpConn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())

	// 3.接收数据
	// 4.处理数据
	buf := make([]byte, 1024)
	for {
		rn, raddr, err := udpConn.ReadFromUDP(buf)
		if err != nil {
			log.Println(err)
		}
		log.Printf("received \"%s\" from %s\n", string(buf[:rn]), raddr.String())
	}
}

发送端:

// 广播发送端
func UDPSenderBroadcast() {
	// 1.监听地址
	// 2.建立连接
	laddr, err := net.ResolveUDPAddr("udp", ":9876")
	if err != nil {
		log.Fatalln(err)
	}
	udpConn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())

	// 3.发送数据
	// 广播地址
	rAddress := "192.168.50.255:6789"
	raddr, err := net.ResolveUDPAddr("udp", rAddress)
	if err != nil {
		log.Fatalln(err)
	}
	for {
		data := fmt.Sprintf("[%s]: %s", time.Now().Format("03:04:05.000"), "hello!")
		// 广播发送
		wn, err := udpConn.WriteToUDP([]byte(data), raddr)
		if err != nil {
			log.Println(err)
		}
		log.Printf("send \"%s\"(%d) to %s\n", data, wn, raddr.String())

		time.Sleep(time.Second)
	}
}

测试:

接收端:

# go test -run UDPReceiverBroadcast
2023/06/01 17:13:27 UDP server is listening on [::]:6789
2023/06/01 17:13:34 received "[05:13:34.707]: hello!" from 192.168.50.130:9876
2023/06/01 17:13:35 received "[05:13:35.709]: hello!" from 192.168.50.130:9876

发送端:

# go test -run UDPSenderBroadcast
2023/06/01 17:13:34 UDP server is listening on [::]:9876
2023/06/01 17:13:34 send "[05:13:34.707]: hello!"(22) to 192.168.50.255:6789
2023/06/01 17:13:35 send "[05:13:35.709]: hello!"(22) to 192.168.50.255:6789

文件传输案例

案例说明

UDP协议在传输数据时,由于不能保证稳定性传输,因此比较适合多媒体通信领域,例如直播、视频、音频即时播放,即时通信等领域。

本案例使用文件传输为例。

客户端设计:

  • 发送文件mp3(任意类型都ok)

  • 发送文件名

  • 发送文件内容

服务端设计:

  • 接收文件

  • 存储为客户端发送的名字

  • 接收文件内容

  • 写入到具体文件中

编码实现

客户端:

// 文件传输(上传)
func UDPFileClient() {
	// 1.获取文件信息
	filename := "./data/Beyond.mp3"
	// 打开文件
	file, err := os.Open(filename)
	if err != nil {
		log.Fatalln(err)
	}
	// 关闭文件
	defer file.Close()
	// 获取文件信息
	fileinfo, err := file.Stat()
	if err != nil {
		log.Fatalln(err)
	}
	//fileinfo.Size(), fileinfo.Name()
	log.Println("send file size:", fileinfo.Size())

	// 2.连接服务器
	raddress := "192.168.50.131:5678"
	raddr, err := net.ResolveUDPAddr("udp", raddress)
	if err != nil {
		log.Fatalln(err)
	}
	udpConn, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()

	// 3.发送文件名
	if _, err := udpConn.Write([]byte(fileinfo.Name())); err != nil {
		log.Fatalln(err)
	}

	// 4.服务端确认
	buf := make([]byte, 4*1024)
	rn, err := udpConn.Read(buf)
	if err != nil {
		log.Fatalln(err)
	}
	// 判断是否为文件名正确接收响应
	if "filename ok" != string(buf[:rn]) {
		log.Fatalln(errors.New("server not ready"))
	}

	// 5.发送文件内容
	// 读取文件内容,利用连接发送到服务端
	// file.Read()
	i := 0
	for {
		// 读取文件内容
		rn, err := file.Read(buf)
		if err != nil {
			// io.EOF 错误表示文件读取完毕
			if err == io.EOF {
				break
			}
			log.Fatalln(err)
		}

		// 发送到服务端
		if _, err := udpConn.Write(buf[:rn]); err != nil {
			log.Fatalln(err)
		}
		i++
	}
	log.Println(i)
	// 文件发送完成。
	log.Println("file send complete.")

	// 等待的测试
	time.Sleep(2 * time.Second)
}

服务端:

// UDP文件传输
func UDPFileServer() {
	// 1.建立UDP连接
	laddress := ":5678"
	laddr, err := net.ResolveUDPAddr("udp", laddress)
	if err != nil {
		log.Fatalln(err)
	}
	udpConn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer udpConn.Close()
	log.Printf("%s server is listening on %s\n", "UDP", udpConn.LocalAddr().String())

	// 2.接收文件名,并确认
	buf := make([]byte, 4*1024)
	rn, raddr, err := udpConn.ReadFromUDP(buf)
	if err != nil {
		log.Fatalln(err)
	}
	filename := string(buf[:rn])
	if _, err := udpConn.WriteToUDP([]byte("filename ok"), raddr); err != nil {
		log.Fatalln(err)
	}

	// 3.接收文件内容,并写入文件
	// 打开文件(创建)
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	// 网络读取
	i := 0
	for {
		// 一次读取
		rn, _, err := udpConn.ReadFromUDP(buf)
		if err != nil {
			log.Fatalln(err)
		}

		// 写入文件
		if _, err := file.Write(buf[:rn]); err != nil {
			log.Fatalln(err)
		}
		i++
		log.Println("file write some content", i)
	}
}

测试,将文件从win传输到linux(centos)中。

上传成功,但文件内容未完整接收,注意这个UDP内容传输的特点(劣势)

# ll
total 16344
-rw-r--r--. 1 root root 9954453 Jun  2 18:08 Beyond.mp3

# ll
total 16344
-rw-r--r--. 1 root root 9757845 Jun  2 18:14 Beyond.mp3

对比源文件大小:

> go test -run UDPFileClient
2023/06/02 18:14:54 send file size: 10409109

小结

  • UDP,User Datagram Protocol,用户数据报协议,是一个简单的面向数据报(package-oriented)的传输层协议

  • 单播,点对点

  • 多播,组内,使用多播(组播)地址

  • 广播,网段内,使用广播地址

  • udp连接

    • connected, net.DialUDP, Read, Write

    • unconnected, net.ListenUDP, ReadFromUDP, WriteToUDP

  • 场景:

    • 实时性要求高

    • 完整性要求不高

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

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

相关文章

NumpyPandas:Pandas库(50%-100%)

目录 前言 一、排序 1.使用索引排序 2.使用变量值排序 二、计算新变量 1.新变量为常量 2.根据原变量新增列 3.基于一个原变量做函数运算 4.在指定位置插入新列 三、修改替换变量值 1.对应数值替换 2.指定范围替换 四、虚拟变量变换 五、数值变量分组 六、数据分组…

Anaconda目录

安装目录 Anaconda 在默认情况下会安装到 C:\ProgramData\Anaconda3&#xff0c;而 conda 环境和包会安装在 C:\Users\username\.conda\ 目录下。 备注&#xff1a;我是在windows下安装 的Anaconda。我的安装目录是C:\Program Files\Anaconda3 pkgs目录 在以上两个目录下都有…

QQ微信头像制图工具箱小程序纯前端源码

微信小程序源码&#xff0c;经测试QQ小程序也可以完美运行&#xff0c;所以给大家分享一下这个QQ微信头像制图工具箱小程序纯前端源码。 主要功能有文字九格、头像挂件生成、爆趣九宫格、形状九宫格、创意长图、情侣头像、猫狗交流器。 这个QQ微信小程序源码是纯前端的&#x…

隧道可视化:实时监控保障行车安全

通过图扑可视化实现隧道的实时监控、数据分析及智能报警系统&#xff0c;提供全面的隧道管理和决策支持&#xff0c;提升行车安全&#xff0c;优化维护策略&#xff0c;确保交通顺畅。

notepad++如何跨文件搜索(比如搜索某个目录里的文件)

notepad如何跨文件搜索&#xff08;比如搜索某个目录里的文件&#xff09; notepad的搜索结果一直是比较迷&#xff0c;搜出一堆乱七八糟的东西&#xff0c;明显是缓存了&#xff0c;文件已经改名了都还不被notepad意识到

文案创作用这四款AI写作神器,告别熬夜赶稿!

都说懒人有懒福&#xff0c;现在的工具也越来越便捷于我们的日常和办公等等各种场景当中&#xff0c;其中文案的撰写和创作上也是令人脑瓜子疼的事情&#xff0c;所以锁着人工智能的兴起&#xff0c;ai智能写作工具助力我们快速地写作适合的文章&#xff0c;一起来看看下面这四…

数据容器-小结

目录 一、数据容器特点比较 二、数据容器操作小结 1、通用序列操作 2、通用的转换操作 3、案例演示 一、数据容器特点比较 二、数据容器操作小结 1、通用序列操作 2、通用的转换操作 3、案例演示 1&#xff09;list([iterable])&#xff1a;转换成列表 str_a "…

ctfshow解题方法

171 172 爆库名->爆表名->爆字段名->爆字段值 -1 union select 1,database() ,3 -- //返回数据库名 -1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema库名 -- //获取数据库里的表名 -1 union select 1,group_concat(…

jmeter-beanshell学习-try处理异常

有时候代码执行过程中&#xff0c;出现一些不能处理的情况&#xff0c;就会报错&#xff0c;还影响之后的代码执行&#xff0c;就需要跳过异常。 上面这情况报错了&#xff0c;还影响了下面的打印。beanshell用try和catch处理异常&#xff0c;下面是try的用法&#xff0c;和if有…

Linux系列--shell编程一

一、Linux系统结构 一、内核层 内核是Linux系统的核心部分&#xff0c;它负责管理系统各种硬件设备、文件系统、内存管理和进程管理等核心任务。Linux内核设计了良好的模块化结构&#xff0c;可以动态地加载和卸载内核模块&#xff0c;这使得内核可以兼容各种不同的硬件设备和…

【微软蓝屏】构建更加稳固和安全的网络环境:从“微软蓝屏”事件谈起

最近&#xff0c;那个让全球都头疼的“微软蓝屏”事件&#xff0c;简直就像是科技界的一场大地震。你说这背后的原因&#xff0c;竟然是一个软件更新的小失误&#xff1f;哎呀&#xff0c;这可真是让人哭笑不得。不过&#xff0c;笑归笑&#xff0c;这事儿也给我们提了个醒&…

学习调试:CubeMX点亮LED灯+按键点亮LED灯0.5ms后熄灭+使用User Lable提高代码的重用性

一、CubeMX 点亮 LED 灯 1.1 CubeMX 中操作 1、打开 CubeMX → file → new project 新建一个工程→ 搜索框里输入芯片型号→双击选择芯片对应封装等待 2、根据上面深蓝/浅蓝的导航对 IO 口进行配置&#xff1a; &#xff08;1&#xff09;Pinout & Configuration&…

如何利用开源Bug管理系统提高团队效率

国内外主流的10款开源bug管理系统对比&#xff1a;PingCode、Worktile、Trac、WebIssues、MantisBT、Bugzilla 、Fossil、The Bug Genie、TestLink 、OpenProject。 在软件开发的复杂世界中&#xff0c;Bug管理可能是一个令人头疼的问题&#xff0c;尤其是当工具不足以捕捉和解…

C语言进阶版—扫雷游戏

文章目录 1. 打印棋盘2. 游戏逻辑3. 游戏框架3.1 打印菜单3.2 do……while实现主逻辑3.3 创建棋盘3.4 初始化棋盘3.5 设置雷3.6 排查雷 完整游戏代码 1. 打印棋盘 在正式讲解扫雷游戏之前&#xff0c;我们简单来看一下打印出来的棋盘.   第一步我们要打印每行的框架 printf…

一文带你读懂TCP

文章目录 1 TCP协议1.1 TCP 基础1.1.1 TCP 特性1.2.2 TCP连接数 1.2 TCP 头1.2.1 TCP 头格式1.2.2 MTU&#xff0c;MSS&#xff0c;分片传输 1.3 TCP 连接三路握手1.4 TCP 断开四次挥手1.5 SYN攻击和防范1.6 重传机制1.6.1 超时重传1.6.2 快速重传1.6.3 SACK 1.7 滑动窗口1.8 流…

【Vulnhub系列】Vulnhub_DC-1靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_DC-1靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 1、在百度网盘中下载DC-1靶场。DC-1靶场受virtual box 的影响&#xff0c;在VM中直接打开是扫描不到IP 的…

基于Java的微博传播分析系统的设计与实现

1 项目介绍 1.1 摘要 本文致力于展示一项创新的微博传播分析系统设计与应用研究&#xff0c;该系统基于Java技术&#xff0c;巧妙利用大数据环境下的社交媒体——微博的庞大用户群及高度活跃特性&#xff0c;旨在深度探索信息传播的内在逻辑与社会影响机制。研究开篇明确定了…

【网络安全】文件上传黑白名单及数组绕过技巧

不安全的文件上传&#xff08;Unsafe FileUpload&#xff09; 不安全的文件上传是指Web应用程序在处理用户上传的文件时&#xff0c;没有采取足够的安全措施&#xff0c;导致攻击者可能利用这些漏洞上传恶意文件&#xff0c;进而对服务器或用户造成危害。 目录 一、文件上传…

20240729 每日AI必读资讯

Meta科学家最新采访&#xff0c;揭秘Llama 3.1是如何炼成的 - Llama 3.1都使用了哪些数据&#xff1f;其中有多少合成数据&#xff1f;为什么不使用MoE架构&#xff1f;后训练与RLHF流程是如何进行的&#xff1f;模型评估是如何进行的&#xff1f; - 受访者Thomas Scialom现任…

在Android上实现汉字笔顺动画效果——HanZiWriter

序&#xff0c;万般皆是命&#xff0c;半点不由人。 Hanzi Writer 是 javascript 免费开源库&#xff0c;根据汉字书写时按照笔画顺序的特征&#xff0c;可以播放正确笔画顺序的描边动画和练习测试。支持简体字和繁体字。可以让全球用户能够通过手绘模仿的方式来学习和练习书写…