壹 说明
该文章主要记录平时工作或者生活中经常使用的Golang
小脚本。
贰 小脚本
2.1 处理错误方法
// 处理错误方法
func HandlingErrors(err error, funname string) {
if err != nil {
fmt.Println("[\033[31;1m-\033[0m] ", funname, "Error:", err)
log.Panic(err)
}
}
2.2 标志
func TagPrint() {
// tag1
fmt.Println("\033[31;1m====================================================\033[0m\033[34;1m")
fmt.Println(" ______ ____\033[31;1m_\033[0m\033[34;1m__\033[31;1m___\033[0m\033[34;1m____\033[31;1m___")
fmt.Println(" /\033[0m\033[34;1m || 。 \033[33;1m。\033[0m\033[34;1m /")
fmt.Println(" / _ \033[31;1m|\033[0m\033[34;1m|____\033[31;1m__\033[0m\033[34;1m_ _ _/ T00ls:")
fmt.Println(" \033[31;1m/\033[0m\033[34;1m \033[31;1m/ |\033[0m\033[34;1m | / /\033[31;1m( )\033[0m\033[34;1m 工具名字")
fmt.Println(" / \033[31;1m/_\033[0m\033[34;1m_| | \033[31;1m/\033[0m\033[34;1m / ( ) ")
fmt.Println(" / ____ \033[31;1m|\033[0m\033[34;1m \033[35;1m<-—+—+—+--}\033[0m\033[34;1m\033[31;1m( )\033[0m\033[34;1m____\033[31;1m/|\033[0m\033[34;1m")
fmt.Println(" \033[31;1m/\033[0m\033[34;1m / | | / / ( \033[33;1m.\033[0m\033[34;1m . \033[31;1m)\033[0m\033[34;1m")
fmt.Println(" /\033[31;1m_\033[0m\033[34;1m_/ |_\033[31;1m__|\033[0m\033[34;1m \033[31;1m/_\033[0m\033[34;1m__/ (\033[31;1m__\033[0m\033[34;1m__=___) \033[31;1m❤\033[0m")
fmt.Println("\033[0m\033[31;1m====================================================\033[0m")
}
func TagPrint() {
// tag2
fmt.Println("\033[34;1m++++++++++++++++++++++++++++++++++++++++++++++++++++++++\033[0m\033[31;1m")
fmt.Println(" ______ _______________ ")
fmt.Println(" / \\ \\ \\ ")
fmt.Println(" / __ \\ \\___________ / ")
fmt.Println(" / / \\ \\ / / ")
fmt.Println(" / / \\ \\ / / ")
fmt.Println(" / /______\\ \\ \033[34;1m<—+————+-}\033[0m\033[31;1m ")
fmt.Println(" / __________ \\ | | ")
fmt.Println(" / / \\ \\ | | ")
fmt.Println(" / / \\ \\ | | ")
fmt.Println(" /____/ \\___\\ |____| ")
fmt.Println("\033[0m\033[34;1m++++++++++++++++++++++++++++++++++++++++++++++++++++++++\033[0m")
// tag3:别人的
fmt.Println("\033[36m -------------------------------------------------------- \033[0m")
fmt.Println("\033[31m ██████╗ █████╗ ████████╗██╗ ██╗███████╗██████╗ \033[0m")
fmt.Println("\033[31m ██╔════╝ ██╔══██╗╚══██╔══╝██║ ██║██╔════╝██╔══██╗ \033[0m")
fmt.Println("\033[31m ██║ ███╗███████║ ██║ ███████║█████╗ ██████╔╝ \033[0m")
fmt.Println("\033[31m ██║ ██║██╔══██║ ██║ ██╔══██║██╔══╝ ██╔══██╗ \033[0m")
fmt.Println("\033[31m ╚██████╔╝██║ ██║ ██║ ██║ ██║███████╗██║ ██║ \033[0m")
fmt.Println("\033[31m ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ \033[0m")
fmt.Println("\033[36m -------------------------------------------------------- \033[0m")
// tag4,使用尖锐的角更显得严肃
tag := `
________ |\
\ ___/___| | _______________|\ ___
| |__/ __| |/ / __/ __/ _* | \ |* /
| _/\ (__| <\__ \ (_| (_| | |\| | ❤
| | \___| |\__\__/\___\__,_|__\\ |
|/ |/ version: %8s \|
`
fmt.Printf(tag, version)
// tag5
tag := `
___ /| /| |\ |\
/ |/ | / | ____| |__ ______ ____| | __
/ /| || | __ __| | _^_ / __| _ \ + / __| |/ /
| |_| || |/|/ // _ |(_____)\ (__| | | | __/\ (__| <
| _ || * ^ *|| |/ | | * | \___| | |_\______\____| |\__\
|_| | ||______/\__/\| \_/ |/ |/
\| 比赛名称:` + YELLOW + competition + END
fmt.Println(tag)
// tag6:别人的
fmt.Println(" ,;;;, ")
fmt.Println(" ;;;;;;; ")
fmt.Println(" .- `\\, '/_ _____ _ ____ _ _ ")
fmt.Println(" .' \\ (`(_) |_ _| |_ |__ / (_)_ _ ____ __ ___ __| |_ ___ _ _ ")
fmt.Println(" / `-,. \\ \\_/ | | | ' \\ |_ \\ | | ' \\(_-< '_ \\/ -_) _| _/ _ \\ '_| ")
fmt.Println(" \\ \\/ \\ `--` |_| |_||_|___/ |_|_||_/__/ .__/\\___\\__|\\__\\___/_| V 1.9")
fmt.Println(" \\ \\ \\ \033[0;31m[\033[0;33m127.0.0.1\033[0;31m] \033[0;37m|_|\033[0;31m [\033[1;34m192.168.1.1\033[0;31m] \033[0;37m")
fmt.Println(" / /| | \033[0;31m[\033[0;37mCoded BY Mohamed Riahi\033[0;31m]\033[0;37m")
fmt.Println(" /_/ |_| ")
fmt.Println(" ( _\\ ( _\\ #:## #:##")
fmt.Println(" #:## ")
}
2.3 切片去重
// 使用了1.18的泛型,如果使用的是go1.18以下版本建议改成对应类型
// 去重
// 去重函数
func RemoveDuplicate[T any](old []T) (result []T) {
// 将第一个切片元素赋值,构建一个新的字符串切片
result = old[:1]
// 遍历str1的元素
for _, word := range old {
i := 0
for ; i < len(result); i++ {
if reflect.ValueOf(word).Interface() == reflect.ValueOf(result[i]).Interface() {
break
}
}
if i == len(result) {
result = append(result, word)
}
}
return result
}
// 或者
func RemoveDuplicate[T any](old []T) (result []T) {
temp := map[any]struct{}{}
for _, item := range old {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return
}
2.4 排除内网IP
func DeleteLocalIP(iplist []string) []string {
// 用于输出排除内网的字符串切片
var out []string
// 循环遍历iplist
for _, v := range iplist {
// 判断元素是否是内网地址,如果不是增加到out切片
rege, _ := regexp.Compile(`^(127\.0\.0\.1)|(localhost)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(0.0.0.0)|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3})$`)
matched := rege.MatchString(v)
if !matched {
out = append(out, v)
}
}
return out
}
2.5 IP的正则表达式
regexp.Compile(`[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}`)
2.6 终端颜色
// 终端颜色
var (
ERR string = "[\033[1;31m✘\033[0m]"
RIGHT string = "[\033[1;32m✓\033[0m]"
WARNING string = "[\033[0;38;5;214m!\033[0m]"
GREY string = "\033[1;30m"
RED string = "\033[1;31m"
GREEN string = "\033[1;32m"
YELLOW string = "\033[1;33m"
BLUE string = "\033[1;34m"
PURPLE string = "\033[1;35m"
MAIN string = "\033[1;36m"
ORANGE string = "\033[0;38;5;214m"
END string = "\033[0m"
)
func Tag() {
fmt.Printf("\x1b[%dmhello world 30: 黑 \x1b[0m\n", 30)
fmt.Printf("\x1b[%dmhello world 31: 红 \x1b[0m\n", 31)
fmt.Printf("\x1b[%dmhello world 32: 绿 \x1b[0m\n", 32)
fmt.Printf("\x1b[%dmhello world 33: 黄 \x1b[0m\n", 33)
fmt.Printf("\x1b[%dmhello world 34: 蓝 \x1b[0m\n", 34)
fmt.Printf("\x1b[%dmhello world 35: 紫 \x1b[0m\n", 35)
fmt.Printf("\x1b[%dmhello world 36: 深绿 \x1b[0m\n", 36)
fmt.Printf("\x1b[%dmhello world 37: 白色 \x1b[0m\n", 37)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 47: 白色 30: 黑 \n", 47, 30)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 46: 深绿 31: 红 \n", 46, 31)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 45: 紫 32: 绿 \n", 45, 32)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 44: 蓝 33: 黄 \n", 44, 33)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 43: 黄 34: 蓝 \n", 43, 34)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 42: 绿 35: 紫 \n", 42, 35)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 41: 红 36: 深绿 \n", 41, 36)
fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 40: 黑 37: 白色 \n", 40, 37)
}
2.7 字符串类型的端口转换为int切片的端口
// 将字符串端口转换为int切片端口
func PortParse(port string) []int {
var ports []int
if port == "" {
// 不设置端口,使用默认端口
defPort := configs.DefaultPorts
return defPort
} else if len(regexp.MustCompile("-").FindAllStringIndex(port, -1)) == 1 {
grep := regexp.MustCompile("(.*)-(.*)")
// 获取IP段的头尾
portHead := grep.FindStringSubmatch(port)[1]
portTail := grep.FindStringSubmatch(port)[2]
// 将IP的头尾转换成int类型
intHead, _ := strconv.Atoi(portHead)
intTail, _ := strconv.Atoi(portTail)
// 赋值IP切片
for p := intHead; p <= intTail; p++ {
ports = append(ports, p)
}
return ports
} else {
// 将IP字符串分开
CustomPorts := strings.Split(port, ",")
// 迭代赋值给int切片
for _, port := range CustomPorts {
p, _ := strconv.Atoi(port)
ports = append(ports, p)
}
return ports
}
}
2.8 将int转换为字符串
int_1, _ := strconv.Atoi("asasas")
str_1 := strconv.Itoa(100)
fmt.Println(int_1)
fmt.Println(str_1)
2.9 Ping通主机以及判断操作系统类型
// hosthost是主机
// timeout是过期时间
func Ping(host string, timeout int) bool {
// 将int类型的timeout转换为string类型的timeout
var to = strconv.Itoa(timeout)
// ping对应主机
var cmd *exec.Cmd
// 判断操作系统
switch runtime.GOOS {
case "windows":
cmd = exec.Command("ping", host, "-n", "1", "-w", to)
case "linux":
cmd = exec.Command("ping", host, "-c", "1", "-w", to)
case "darwin":
cmd = exec.Command("ping", host, "-c", "1", "-W", to)
}
// 判断cmd是否为空
if cmd == nil {
return false
}
// 执行cmd的命令
err := cmd.Run()
return err == nil
}
2.10 实现SHA256生成散列值
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
//SHA256生成哈希值
func GetSHA256HashCode(str string)string{
message := []byte(str)
//方法一:
//创建一个基于SHA256算法的hash.Hash接口的对象
hash := sha256.New()
//输入数据
hash.Write(message)
//计算哈希值
bytes := hash.Sum(nil)
//将字符串编码为16进制格式,返回字符串
hashCode := hex.EncodeToString(bytes)
//返回哈希值
return hashCode
//方法二:
//bytes2:=sha256.Sum256(message)//计算哈希值,返回一个长度为32的数组
//hashcode2:=hex.EncodeToString(bytes2[:])//将数组转换成切片,转换成16进制,返回字符串
//return hashcode2
}
func main(){
hashCode:=GetSHA256HashCode("hello world")
fmt.Println(hashCode)
}
2.11 获取当前目录下所有文件
func GetAllFile(path string) []string {
// 存放文件名
filename := []string{}
// 读取当前目录中的所有文件和子目录
files, err := ioutil.ReadDir(path)
if err != nil {
panic(err)
}
// 获取文件,并输出它们的名字
for _, file := range files {
filename = append(filename, file.Name())
}
return filename
}
2.12 生成随机数
package main
import "fmt"
import "math/rand"
func main() {
fmt.Println(rand.Intn(100)) //产生0-100的随机整数
fmt.Println(rand.Float64()) //产生0.0-1.0的随机浮点点
s1 := rand.NewSource(42) //用指定值创建一个随机数种子
r1 := rand.New(s1)
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
s2 := rand.NewSource(42) //同前面一样的种子
r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
}
2.13 Base64编码
package main
import (
"encoding/base64"
"fmt"
)
func main() {
info := []byte("https://www.bilibili.com/aa*()s/?=")
fmt.Println("==============标准的Base64编码==============")
encodeinfo := base64.StdEncoding.EncodeToString(info)
decodeinfo, _ := base64.StdEncoding.DecodeString(encodeinfo)
fmt.Printf("编码后:%s,解码后:%s\n", encodeinfo, decodeinfo)
fmt.Println("==============URL的Base64编码==============")
URLencodeinfo := base64.URLEncoding.EncodeToString(info)
URLdecodeinfo, _ := base64.URLEncoding.DecodeString(URLencodeinfo)
fmt.Printf("编码后:%s,解码后:%s\n", URLencodeinfo, URLdecodeinfo)
}
2.14 判断字符串是否包含某个字符
func main() {
if find := strings.Contains("test-v1", "v1"); find {
fmt.Println("find the character.")
}
}
2.15 字符串反转
package main
import "fmt"
func main() {
s := "foobar"
a := []rune(s)
fmt.Printf("%s\n", s)
fmt.Printf("字符串逆转过程:\n")
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
fmt.Println(string(a))
}
fmt.Printf("%s\n", string(a))
}
2.16 读取json文件
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type Post struct { //带结构标签,反引号来包围字符串
Id int `json:"id"`
Content string `json:"content"`
Author Author `json:"author"`
Comment []Comment `json:"comments"`
}
type Author struct {
Id int `json:"id"`
Name string `json:"name"`
}
type Comment struct {
Id int `json:"id"`
Content string `json:"content"`
Author string `json:"author"`
}
func main() {
// 打开json文件
jsonFile, err := os.Open("post.json")
if err != nil {
fmt.Println("不存在json文件!")
return
}
defer jsonFile.Close()
// 读取json文件
jsonData, err := ioutil.ReadAll(jsonFile)
if err != nil {
fmt.Println("读取json文件错误!")
return
}
fmt.Printf("JSON文件:%s\n", jsonData)
var post Post
// json文件反序列化
json.Unmarshal(jsonData, &post)
fmt.Printf("反序列化后文件的内容:%v\n",post)
}
// post.json
{
"id": 1,
"content": "hello golang",
"author": {
"id": 2,
"name": "miller Fan"
},
"comments": [
{
"id": 3,
"content": "Have a good night",
"author": "屈原"
},
{
"id": 4,
"content": "道德经",
"author": "老子"
}
]
}
2.17 进度条
package main
import (
"fmt"
"os"
"strings"
"time"
)
func main() {
num := 100
for i := 0; i <= num; i++ {
// 时间50秒
time.Sleep(50 * time.Millisecond)
h := strings.Repeat("=", i) + strings.Repeat(" ", num-i)
fmt.Printf("\r%3d%%[\x1b[1;0;%dm%s\x1b[0m]", i, 30+(i%7), h)
os.Stdout.Sync()
}
fmt.Println("\n已完成!")
}
2.18 动态加载
package main
import (
"fmt"
"time"
)
func main() {
// 需要启动一个线程
// 需要控制top的值
top := true
fmt.Println("[\033[33;1m*\033[0m] 扫描开始!")
go func() {
for top {
time.Sleep(100 * time.Millisecond)
fmt.Printf("[\033[34;1m—\033[0m] 扫描中。。。\r")
time.Sleep(100 * time.Millisecond)
fmt.Printf("[\033[34;1m\\\033[0m] 扫描中。。。\r")
time.Sleep(100 * time.Millisecond)
fmt.Printf("[\033[34;1m|\033[0m] 扫描中。。。\r")
time.Sleep(100 * time.Millisecond)
fmt.Printf("[\033[34;1m/\033[0m] 扫描中。。。\r")
}
fmt.Println()
}()
for i := 0; i < 10; i++ {
time.Sleep(1000 * time.Millisecond)
}
top = false
fmt.Printf("\r")
fmt.Println("\n[\033[33;1m*\033[0m] 扫描结束!")
}
2.19 汉字转拼音
package main
import (
"fmt"
"github.com/mozillazg/go-pinyin"
)
func main() {
hans := "中国人"
// 默认
a := pinyin.NewArgs()
fmt.Println(pinyin.Pinyin(hans, a))
// [[zhong] [guo] [ren]]
// 包含声调
a.Style = pinyin.Tone
fmt.Println(pinyin.Pinyin(hans, a))
// [[zhōng] [guó] [rén]]
// 声调用数字表示
a.Style = pinyin.Tone2
fmt.Println(pinyin.Pinyin(hans, a))
// [[zho1ng] [guo2] [re2n]]
// 开启多音字模式
a = pinyin.NewArgs()
a.Heteronym = true
fmt.Println(pinyin.Pinyin(hans, a))
// [[zhong zhong] [guo] [ren]]
a.Style = pinyin.Tone2
fmt.Println(pinyin.Pinyin(hans, a))
// [[zho1ng zho4ng] [guo2] [re2n]]
fmt.Println(pinyin.LazyPinyin(hans, pinyin.NewArgs()))
// [zhong guo ren]
fmt.Println(pinyin.Convert(hans, nil))
// [[zhong] [guo] [ren]]
fmt.Println(pinyin.LazyConvert(hans, nil))
// [zhong guo ren]
name := ""
for _, val := range pinyin.LazyConvert(hans, nil) {
name += val
}
fmt.Println(name)
// zhongguoren
}
2.20 获取客户端IP
package main
import (
"flag"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func getip(c *gin.Context) {
// 获取客户端真实ip地址
reqIP := c.ClientIP()
if reqIP == "::1" {
reqIP = "127.0.0.1"
}
fmt.Println("\x1b[33m[*]\x1b[0m 客户端的的IP为" + reqIP)
c.String(http.StatusOK, "[+] 您访问的的IP为"+reqIP)
}
func main() {
var port string
flag.StringVar(&port, "p", "8082", "监听的端口")
flag.Parse()
fmt.Println("\x1b[32m[+]\x1b[0m 默认监听8082端口!")
r := gin.Default()
// 如果应用程序不在代理之后,“ForwardedByClientIP”应设置为 false,因此“X-Forwarded-For”将被忽略。
// 如果在代理后面将其设置为true
r.ForwardedByClientIP = true
r.GET("/", getip)
r.Run(":" + port)
}
2.21 格式化用户输入的IP
// IP的形式无非4种:逗号隔开,/和-连续的形式,以及单个IP
// 由于逗号是一个分类大方向,所以先是判断逗号的,然后根据/和-连续这两种不同形式,进行划分,分出-和/,然后/的格式单一,所以统一转换成-格式,最后转换成单个
package main
import (
"flag"
"fmt"
"math/rand"
"net"
"regexp"
"strconv"
"strings"
)
// 处理ip
func ProcessIPs(ips string) (hostlist []string) {
// 判断是否有逗号
if strings.Contains(ips, ",") {
// 如果有逗号将其划分多个IP表
IPList := strings.Split(ips, ",")
// 存放IP用与hosts变量一致
var ips []string
// 循环处理IP表
for _, ip := range IPList {
ips = parseIP(ip)
hostlist = append(hostlist, ips...)
}
} else {
hostlist = parseIP(ips)
}
return RemoveDuplicate(hostlist)
}
// 根据用户给出的ip形式进行分类
func parseIP(ip string) []string {
reg := regexp.MustCompile(`[a-zA-Z]+`)
switch {
case strings.HasSuffix(ip, "/8"):
// 扫描/8时,由于A段太多了,只扫网关和随机IP,避免扫描过多IP
return parseIP8(ip)
case strings.Contains(ip, "/"):
// 解析 /24 /16等
return parseIP2(ip)
case reg.MatchString(ip):
// 域名用lookup获取ip
host, err := net.LookupHost(ip)
if err != nil {
return nil
}
return host
case strings.Contains(ip, "-"):
// 处理192.168.1.1-192.168.1.100或者192.168.1.1-24
return parseIP1(ip)
default:
// 处理单个ip
testIP := net.ParseIP(ip)
if testIP == nil {
return nil
}
return []string{ip}
}
}
// 把 192.168.x.x/xx 转换成IP列表
func parseIP2(host string) (hosts []string) {
// 使用 net.ParseCIDR() 方法解析给定的网段,返回网段的 IP 地址和子网掩码
// 检查给定的网段是否正确
ipone, ipNet, err := net.ParseCIDR(host)
if err != nil {
return
}
// 把 192.168.x.x/xx 转换成 192.168.x.x-192.168.x.x 并转成IP列表
hosts = parseIP1(IPRange(ipone.String(), ipNet))
return
}
// 解析ip段: 192.168.111.1-255,192.168.111.1-192.168.112.255
func parseIP1(ip string) []string {
// 如果有逗号将其划分多个
IPRangelist := strings.Split(ip, "-")
// 确认该IP格式是否为正确IP
testIP := net.ParseIP(IPRangelist[0])
// 创建一个存储所有IP列表
var allIP []string
// 通过len函数来确认IPRangelist[1]是192.168.1.255形式还是数字形式
if len(IPRangelist[1]) < 4 {
// 处理数字形式
// 将字符串转成数字
Range, err := strconv.Atoi(IPRangelist[1])
// 判断合理性
if testIP == nil || Range > 255 || err != nil {
return nil
}
// 分离IP
SplitIP := strings.Split(IPRangelist[0], ".")
// 转换为数字
ip1, err1 := strconv.Atoi(SplitIP[3])
// 拼接
PrefixIP := SplitIP[0] + "." + SplitIP[1] + "." + SplitIP[2]
// 判断合理性
if ip1 > Range || err1 != nil {
return nil
}
// 循环拼接IP
for i := ip1; i <= Range; i++ {
allIP = append(allIP, PrefixIP+"."+strconv.Itoa(i))
}
} else {
// 处理192.168.1.255形式
// 分离IP
SplitIP1 := strings.Split(IPRangelist[0], ".")
SplitIP2 := strings.Split(IPRangelist[1], ".")
// 判断合理性
if len(SplitIP1) != 4 || len(SplitIP2) != 4 {
return nil
}
// 用于存放起始IP和结束IP列表
start, end := [4]int{}, [4]int{}
// 循环读取4段IP
for i := 0; i < 4; i++ {
// 转换为数字
ip1, err1 := strconv.Atoi(SplitIP1[i])
ip2, err2 := strconv.Atoi(SplitIP2[i])
// 判断合理性
if ip1 > ip2 || err1 != nil || err2 != nil {
return nil
}
// 添加到起始IP和结束IP列表
start[i], end[i] = ip1, ip2
}
// 通过移位运算,将地址改为数字的形式
startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3]
endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3]
// 通过循环将数字转成地址
for num := startNum; num <= endNum; num++ {
ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff)
allIP = append(allIP, ip)
}
}
return allIP
}
// 获取把 192.168.x.x/xx 转换成 192.168.x.x-192.168.x.x的起始IP、结束IP
func IPRange(start string, c *net.IPNet) string {
// 16进制子网掩码
mask := c.Mask
// 创建一个net.ip类型
bcst := make(net.IP, len(c.IP))
// 将dreams值给bcst
copy(bcst, c.IP)
// 获取结束IP
for i := len(mask) - 1; i >= 0; i-- {
bcst[i] = c.IP[i] | ^mask[i]
}
end := bcst.String()
// 返回用-表示的ip段,192.168.1.1-192.168.255.255
return fmt.Sprintf("%s-%s", start, end)
}
// 处理B段IP
func parseIP8(ip string) []string {
// 去掉最后的/8
realIP := ip[:len(ip)-2]
// net.ParseIP 这个方法用来检查 ip 地址是否正确,如果不正确,该方法返回 nil
testIP := net.ParseIP(realIP)
// 判断该IP是否为正常IP
if testIP == nil {
return nil
}
// 获取IP的头部
IP8head := strings.Split(ip, ".")[0]
// 存放B段IP
var allIP []string
// 构造B段的随机IP表
for a := 0; a <= 255; a++ {
for b := 0; b <= 255; b++ {
// 一般情况下网关为1或者254
allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, 1))
allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(2, 80)))
allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(81, 170)))
allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(171, 253)))
allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, 254))
}
}
return allIP
}
// 去重函数
func RemoveDuplicate(old []string) []string {
result := []string{}
temp := map[string]struct{}{}
for _, item := range old {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
// 随机数
func RandInt(min, max int) int {
if min >= max || min == 0 || max == 0 {
return max
}
return rand.Intn(max-min) + min
}
// 主函数
func main() {
// 定义命令行参数方式
var IPs string
flag.StringVar(&IPs, "ip", "", "ip地址")
// 解析命令行参数
flag.Parse()
// 判断是否输入IP
if IPs == "" {
fmt.Println("[\033[31;1m-\033[0m] 没有输入IP!")
flag.Usage()
return
}
// 对用户输入的IP参数进行格式化处理
hosts := ProcessIPs(IPs)
for i, val := range hosts {
fmt.Println(i, val)
}
}
2.22 文件写入
// 文件写入
func WriteFile(result string, filename string) {
var text = []byte(result + "\n")
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("[\033[31;1m-\033[0m] 打开文件 %s 失败, %v\n", filename, err)
return
}
_, err = f.Write(text)
f.Close()
if err != nil {
fmt.Printf("[\033[31;1m-\033[0m] 写入文件 %s 失败, %v\n", filename, err)
}
}
2.23 判断字符串是否在列表中
// 判断字符串是否在列表中
func strinlist(str string, str_array []string) bool {
for _, s := range str_array{
if str == s{
return true
}
}
return false
}
2.24 读取json文件内容并设置为结构体
// 读取json文件
func Readjsonfile(filename string) ([]jsonType, error) {
// 设置json文件列表
// jsonType是自定义的结构体,用来反序列化的
var jsonlist []jsonType
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
err = json.Unmarshal(data, &jsonlist)
if err != nil {
return nil, err
}
return jsonlist, nil
}
2.25 结构体转换为json文件
// 结构体转换为json
func Switchjson(date []AvType) error {
jsonByteData, err := json.Marshal(date)
if err != nil {
return err
}
// 这里使用了前面 2.22 文件写入方法
WriteFile(string(jsonByteData), "demo.json")
return nil
}
2.26 格式化用户输入的端口
// 端口格式化与IP格式化差不多
package main
import (
"flag"
"fmt"
"strconv"
"strings"
)
// 格式化处理端口
func ParsePort(ports string) (scanPorts []int) {
// 判断端口是否为空
if ports == "" {
return
}
// 根据逗号切割端口
slices := strings.Split(ports, ",")
// 循环获取端口
for _, port := range slices {
// 去除空白符
port = strings.TrimSpace(port)
// 判断去除后空白符的端口是否正确
if port == "" {
continue
}
upper := port
// 判断端口是否有-这样连续的
if strings.Contains(port, "-") {
// 分离端口
ranges := strings.Split(port, "-")
// 判断分离出的端口是否多个
if len(ranges) < 2 {
continue
}
// 设置端口范围的开始和结束
startPort, _ := strconv.Atoi(ranges[0])
endPort, _ := strconv.Atoi(ranges[1])
if startPort < endPort {
port = ranges[0]
upper = ranges[1]
} else {
port = ranges[1]
upper = ranges[0]
}
}
// 赋值
start, _ := strconv.Atoi(port)
end, _ := strconv.Atoi(upper)
// 将端口赋值给scanPorts
for i := start; i <= end; i++ {
scanPorts = append(scanPorts, i)
}
}
// 端口去重
scanPorts = removeDuplicate(scanPorts)
return scanPorts
}
// 去重函数
func removeDuplicate(old []int) []int {
result := []int{}
temp := map[int]struct{}{}
for _, item := range old {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
// 主函数
func main() {
// 定义命令行参数方式
var Ports string
flag.StringVar(&Ports, "p", "", "端口")
// 解析命令行参数
flag.Parse()
// 判断是否输入Port
if Ports == "" {
fmt.Println("[\033[31;1m-\033[0m] 没有输入Ports!")
flag.Usage()
return
}
// 对用户输入的IP参数进行格式化处理
Portslist := ParsePort(Ports)
for i, val := range Portslist {
fmt.Println(i, val)
}
}
2.27 快速判断文件类型
在正常情况下,我们需要判断文件类型有两种方法:
- 根据文件的扩展名来判断,比如
.jpg
表示JPEG
图像,.mp3
表示MP3
音频等- 优点:简单快速
- 缺点:容易被伪造或者缺失
- 根据文件内容的特征来判断,比如
JPEG
图像的前几个字节是FF D8 FF
,MP3
音频的前几个字节是ID3
等。- 优点:准确可靠
- 缺点:需要读取文件内容并进行分析
而在Go
语言的标准库net/http
包中提供了一个简单的判断文件类型的方法DetectContentType()
,该方法是读取文件内容的前512
个字节内容,返回一个MIME
类型字符串。它使用了mimesniff
算法,根据一组预定义的规则来匹配文件内容的特征和对应的MIME
类型。这个方法既不依赖于文件扩展名,也不需要完整地读取文件内容,因此既快速又准确。同时我们可以使用mime.ExtensionsByType
获取该类型可能的后缀名:
package main
import (
"fmt"
"log"
"mime"
"net/http"
"os"
)
// 处理错误方法
func HandlingErrors(err error, funname string) {
if err != nil {
fmt.Println("[\033[31;1m-\033[0m] ", funname, "Error:", err)
log.Panic(err)
}
}
func main() {
// 打开一个 MP3 文件
file, err := os.Open("a.jpg")
if err != nil {
fmt.Println(err)
return
}
// 关闭文件
defer file.Close()
// 读取文件的前 512 个字节到一个缓冲区
buffer := make([]byte, 512)
n, err := file.Read(buffer)
if err != nil {
HandlingErrors(err, "file.Read")
}
// 调用 http.DetectContentType 方法判断文件类型,并传入了缓冲区中的数据,这个方法会返回一个字符串表示文件的 MIME 类型
// 实际上,如果字节数超过 512,该函数也只会使用前 512 个字节
contentType := http.DetectContentType(buffer[:n])
// 返回文件类型可能的文件后缀名
ext, err := mime.ExtensionsByType(contentType)
if err != nil {
HandlingErrors(err, "mime.ExtensionsByType")
}
// 输出文件类型
fmt.Println("[\033[0;38;5;214m!\033[0m] 文件类型为:", contentType)
// 输出文件类型可能的文件后缀名
fmt.Println("[\033[0;38;5;214m!\033[0m]", contentType, "类型可能的后缀名:", ext)
}
2.28 搭建http文件下载服务
package main
import (
"flag"
"fmt"
"io/fs"
"io/ioutil"
"net/http"
"os"
"strconv"
)
// 获取文件信息
func getfile() ([]fs.FileInfo, error) {
directory := "./"
files, err := os.Open(directory)
if err != nil {
fmt.Println("打开目录时出错:", err)
return nil, err
}
defer files.Close()
fileInfos, err := files.Readdir(-1)
if err != nil {
fmt.Println("读取目录时出错:", err)
return nil, err
}
return fileInfos, nil
}
// 显示首页
func index(rw http.ResponseWriter, r *http.Request) {
files, err := getfile()
if err != nil {
fmt.Fprintln(rw, err)
}
html := ""
for _, val := range files {
html = html + "<a href='download?filename=" + val.Name() + "'>" + val.Name() + "</a></br>"
}
fmt.Fprintln(rw, html)
}
// 下载功能
func download(rw http.ResponseWriter, r *http.Request) {
//获取请求参数
fn := r.FormValue("filename")
//设置响应头
header := rw.Header()
header.Add("Content-Type", "application/octet-stream")
header.Add("Content-Disposition", "attachment;filename="+fn)
//使用ioutil包读取文件
b, _ := ioutil.ReadFile(fn)
//写入到响应流中
rw.Write(b)
}
func main() {
// 设置端口
var port int
flag.IntVar(&port, "p", 9090, "自定义端口")
// 解析命令行参数
flag.Parse()
if port <= 0 || port > 65535 {
fmt.Printf("[x] 该端口不合规!\n")
return
}
fmt.Println("[!] 服务端口为:" + strconv.Itoa(port))
http.HandleFunc("/", index)
http.HandleFunc("/download", download)
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err != nil {
fmt.Printf("[x] http服务器失败,err:%v\n", err)
return
}
}
2.29 判断为空方法
func main() {
// 判断字符串为空
str := ""
if str != "" {
fmt.Println("字符串为空")
}
// 判断数组或者切片为空
List := []string{}
if len(List) != 0 {
fmt.Println("数组为空")
}
// 判断map为空
Map := make(map[string]int)
if len(Map) != 0 {
fmt.Println("数组为空")
}
}
2.30 以行的方式读取文件内的字符串
// 读取文件并以[]string形式返回内容
func ReadingLines(filename string) []string {
// 设置结果变量
var result []string
// 打开文件
file, err := os.Open(filename)
if err != nil {
return result
}
defer file.Close()
// 开始读取文件
scanner := bufio.NewScanner(file)
// 循环读取
for scanner.Scan() {
val := scanner.Text()
// 判断是否为空
if val == "" {
continue
}
// 拼接
result = append(result, val)
}
// 判断是否存在终止错误
if err := scanner.Err(); err != nil {
return result
}
return result
}