当前位置: 首页 > news >正文

用Go语言重写Linux系统命令 -- nc简化版

用Go语言重写Linux系统命令 – nc简化版

1. 引言

netcat,简称 nc,被誉为网络工具中的“瑞士军刀”,是网络调试与分析的利器。它的功能十分强大,然而平时我们经常使用的就是他的连通性测试功能,但是nc是被设计用来测试TCPUDP的,对于HTTP支持不是太好,于是,我决定用 Go 语言重新实现一个简化版的 nc,专注于联通性测试功能,并扩展支持测试HTTPPing的连通性测试。通过这个项目,你不仅能深入学习网络编程,还能体验用 Go 语言开发系统工具的乐趣!

小目标:让我们的工具小而美,轻松搞定网络连通性调试!

2. 需求分析

在开始编写代码之前,我们需要明确工具的功能和设计目标:

  • 核心功能

    1. TCP 测试:检查指定 IP 和端口是否可建立连接,支持数据发送与接收。
    2. UDP 测试:发送 UDP 数据包并接收响应。
    3. HTTP 测试:测试指定 URL 是否可访问,支持自定义请求方法(如 GET/POST)。
    4. Ping 测试:检查目标 IP 是否可达,并测量响应时间。
  • 用户体验设计

    • 使用命令行参数指定测试类型和选项(如目标 IP、端口、超时)。
    • 错误提示清晰直观,方便排查问题。
  • 性能目标:快速响应,保持简洁。

3. 项目初始化

3.1 安装开发环境

确保已安装 Go 编译器(推荐版本 ≥ 1.20)。执行以下命令检查 Go 是否可用:

go version

3.2 初始化项目

创建项目目录并初始化 Go 模块:

mkdir gonc
cd gonc
go mod init gonc

项目结构:

gonc/
├── main.go        # 入口文件
├── tcp.go         # TCP 测试模块
├── udp.go         # UDP 测试模块
├── http.go        # HTTP 测试模块
├── ping.go        # Ping 测试模块
└── go.mod         # 依赖管理文件

4. 模块实现

4.1 实现 TCP 测试功能

tcp.go 中编写代码,建立 TCP 连接,发送和接收数据:

package myncimport ("fmt""log""net""time"
)// TestTCP 测试TCP端口是否连通,并支持发送和接收数据
func FireTCP(ip string, port, timeout int, data string) error {address := fmt.Sprintf("%s:%d", ip, port)// 设置连接超时时间conn, err := net.DialTimeout("tcp", address, time.Duration(timeout)*time.Second)if err != nil {log.Printf("Failed to connect to %s: %v\n", address, err)return err}defer conn.Close()fmt.Printf("Successfully connected to %s\n", address)// 发送数据if data != "" {fmt.Printf("Sending data: %s\n", data)_, err = conn.Write([]byte(data))if err != nil {log.Printf("Failed to send data: %v\n", err)} else {fmt.Println("Data sent successfully")}}// 接收响应数据buffer := make([]byte, 1024)conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second))// 读取响应数据// 如果超时则提示用户, 服务器没有发送数据n, err := conn.Read(buffer)if err != nil {if netErr, ok := err.(net.Error); ok && netErr.Timeout() {fmt.Println("No response from server")} else {log.Printf("Failed to read response: %v\n", err)}} else {fmt.Printf("Received: %s\n", string(buffer[:n]))}return err
}

4.2 实现 UDP 测试功能

udp.go 中实现 UDP 数据包的发送与接收:

package myncimport ("fmt""log""net""time"
)// TestUDP 测试UDP端口是否连通,并支持发送和接收数据
func FireUDP(ip string, port, timeout int, data string) error {address := fmt.Sprintf("%s:%d", ip, port)conn, err := net.Dial("udp", address)if err != nil {log.Printf("Failed to connect to %s: %v\n", address, err)return err}defer conn.Close()fmt.Printf("Successfully connected to %s\n", address)// 设置写超时conn.SetWriteDeadline(time.Now().Add(time.Duration(timeout) * time.Second))_, err = conn.Write([]byte(data))if err != nil {log.Printf("Failed to send data: %v\n", err)return err}fmt.Println("Data sent successfully")// 设置读超时conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second))buffer := make([]byte, 1024)n, err := conn.Read(buffer)if err != nil {log.Printf("No response received: %v\n", err)} else {fmt.Printf("Received: %s\n", string(buffer[:n]))}return err
}

4.3 实现 HTTP 测试功能

http.go 中构建 HTTP 请求:

package myncimport ("fmt""io""log""net/http""time"
)// TestHTTP 测试HTTP/HTTPS连接
func FireHTTP(url, method string, headers map[string]string, timeout int) error {client := &http.Client{Timeout: time.Duration(timeout) * time.Second,}// 创建HTTP请求req, err := http.NewRequest(method, url, nil)if err != nil {log.Printf("Failed to create HTTP request: %v\n", err)return err}// 设置请求头for key, value := range headers {req.Header.Set(key, value)}// 发送HTTP请求resp, err := client.Do(req)if err != nil {log.Printf("HTTP request failed: %v\n", err)return err}defer resp.Body.Close()// 读取响应内容body, err := io.ReadAll(resp.Body)if err != nil {log.Printf("Failed to read response body: %v\n", err)return err}fmt.Printf("HTTP Status: %s\n", resp.Status)fmt.Printf("Response Body:\n%s\n", string(body))return err
}

4.4 实现 Ping 测试功能

ping.go 中:


import ("fmt""log""net""os""time"
)const icmpEchoRequest = 8// Ping 测试目标IP是否可达
func Ping(ip string, timeout int) error {conn, err := net.Dial("ip4:icmp", ip)if err != nil {log.Printf("Failed to connect to %s: %v\n", ip, err)return err}defer conn.Close()// 构造ICMP请求包id := os.Getpid() & 0xffffseq := 1msg := []byte{icmpEchoRequest, 0, 0, 0, // ICMP Type, Code, and Checksum placeholderbyte(id >> 8), byte(id & 0xff), // Identifierbyte(seq >> 8), byte(seq & 0xff), // Sequence number}checksum := calculateChecksum(msg)msg[2] = byte(checksum >> 8)msg[3] = byte(checksum & 0xff)// 设置写超时conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))start := time.Now()_, err = conn.Write(msg)if err != nil {log.Printf("Failed to send ICMP request: %v\n", err)return err}// 接收ICMP响应buffer := make([]byte, 1024)_, err = conn.Read(buffer)if err != nil {log.Printf("Failed to receive ICMP response: %v\n", err)return err}elapsed := time.Since(start)fmt.Printf("Ping %s successful! Time=%v\n", ip, elapsed)return err
}// calculateChecksum 计算ICMP校验和
func calculateChecksum(data []byte) uint16 {var sum intfor i := 0; i < len(data)-1; i += 2 {sum += int(data[i])<<8 | int(data[i+1])}if len(data)%2 == 1 {sum += int(data[len(data)-1]) << 8}for (sum >> 16) > 0 {sum = (sum >> 16) + (sum & 0xffff)}return uint16(^sum)
}

4.5 命令行解析与功能整合

main.go 中,将上述模块整合,并解析命令行参数:

package mainimport ("flag""fmt""net/url""os""strconv""strings""mync"
)func main() {// 定义命令行参数var method, data stringvar httpHeaders httpHeaderMapvar timeout intflag.StringVar(&method, "method", "GET", "HTTP method to use (default: GET)")flag.StringVar(&data, "data", "", "Data to send (for TCP or UDP)")flag.Var(&httpHeaders, "header", "Custom HTTP header (key=value pairs, can use multiple times)")flag.IntVar(&timeout, "timeout", 5, "Timeout in seconds (default: 5)")// 自定义 Usageflag.Usage = func() {fmt.Fprintf(os.Stderr, "Usage: %s <protocol>://<target> [options]\n\n", os.Args[0])fmt.Fprintf(os.Stderr, "options:\n")fmt.Fprintf(os.Stderr, "  -method <method>     HTTP method to use (default: GET)\n")fmt.Fprintf(os.Stderr, "  -data <data>         Data to send (for TCP or UDP)\n")fmt.Fprintf(os.Stderr, "  -header <header>   Custom HTTP header (key=value pairs, can use multiple times)\n")fmt.Fprintf(os.Stderr, "  -timeout <seconds>   Timeout in seconds (default: 5)\n")fmt.Fprintf(os.Stderr, "Examples:\n")fmt.Fprintf(os.Stderr, "  Test TCP connection:\n")fmt.Fprintf(os.Stderr, "    %s tcp://192.168.1.1:80 -data \"Hello, TCP!\" -timeout 10\n", os.Args[0])fmt.Fprintf(os.Stderr, "  Test UDP connection:\n")fmt.Fprintf(os.Stderr, "    %s udp://192.168.1.1:53 -data \"Hello, UDP!\" -timeout 5\n", os.Args[0])fmt.Fprintf(os.Stderr, "  Test HTTP connection:\n")fmt.Fprintf(os.Stderr, "    %s http://example.com -method GET -timeout 5\n", os.Args[0])fmt.Fprintf(os.Stderr, "  Ping a target:\n")fmt.Fprintf(os.Stderr, "    %s ping://192.168.1.1 -timeout 3\n", os.Args[0])}// 解析 flag 参数flag.Parse()// 必须至少有一个非 flag 参数args := flag.Args()if len(args) < 1 {fmt.Println("Error: Missing protocol and target. Example usage: tcp://192.168.1.1:80")flag.Usage()os.Exit(1)}// 解析第一个参数为协议和目标targetURL := args[0]parsedURL, err := url.Parse(targetURL)if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {fmt.Printf("Error: Invalid protocol or target format: %s\n", targetURL)flag.Usage()os.Exit(1)}protocol := parsedURL.Schemetarget := parsedURL.Host// 根据协议执行对应的功能switch protocol {case "tcp":ip, port, err := parseTarget(target)if err != nil {fmt.Println("Error:", err)os.Exit(1)}if err := mync.FireTCP(ip, port, timeout, data); err != nil {fmt.Println("TCP Test Error:", err)}case "udp":ip, port, err := parseTarget(target)if err != nil {fmt.Println("Error:", err)os.Exit(1)}if err := mync.FireUDP(ip, port, timeout, data); err != nil {fmt.Println("UDP Test Error:", err)}case "http", "https":headerMap := httpHeaders.ToMap()if err := mync.FireHTTP(targetURL, method, headerMap, timeout); err != nil {fmt.Println("HTTP Test Error:", err)}case "ping":if err := mync.Ping(target, timeout); err != nil {fmt.Println("Ping Test Error:", err)}default:fmt.Printf("Error: Unsupported protocol: %s\n", protocol)flag.Usage()os.Exit(1)}
}// parseTarget 解析 <ip>:<port> 格式
func parseTarget(target string) (string, int, error) {parts := strings.Split(target, ":")if len(parts) != 2 {return "", 0, fmt.Errorf("invalid target format: %s, expected format <ip>:<port>", target)}ip := parts[0]port, err := strconv.Atoi(parts[1])if err != nil {return "", 0, fmt.Errorf("invalid port number: %s", parts[1])}return ip, port, nil
}// httpHeaderMap 用于保存用户指定的多个 -header 参数
type httpHeaderMap []stringfunc (h *httpHeaderMap) String() string {return strings.Join(*h, ", ")
}func (h *httpHeaderMap) Set(value string) error {*h = append(*h, value)return nil
}// ToMap 将 httpHeaderMap 转换为 map
func (h *httpHeaderMap) ToMap() map[string]string {headerMap := make(map[string]string)for _, header := range *h {parts := strings.SplitN(header, "=", 2)if len(parts) == 2 {headerMap[parts[0]] = parts[1]}}return headerMap
}

5 测试

#!/bin/bashset -eip=192.168.100.10
port=3333timeout=2# 测试tcp端口
echo ">>> Testing tcp port $port..."
./gonc tcp://$ip:$port -data "Hello" -timeout $timeout# 测试udp端口
echo ">>> Testing udp port $port..."
./gonc udp://$ip:$port -data "Hello" -timeout $timeout# 测试http服务
echo ">>> Testing http service..."
./gonc http://example.com -method GET -timeout $timeout# 测试ping
echo ">>> Testing ping..."
sudo ./gonc ping://$ip -timeout $timeout

由于测试ping时使用了原始套接字,所以需要root权限

相关文章:

用Go语言重写Linux系统命令 -- nc简化版

用Go语言重写Linux系统命令 – nc简化版 1. 引言 netcat&#xff0c;简称 nc&#xff0c;被誉为网络工具中的“瑞士军刀”&#xff0c;是网络调试与分析的利器。它的功能十分强大&#xff0c;然而平时我们经常使用的就是他的连通性测试功能&#xff0c;但是nc是被设计用来测试…...

面试复盘 part 02·1202-1207 日

作品集讲述部分 分析反思 作品集讲述部分&#xff0c;视觉讲述部分需要更换&#xff0c;需要换成其他视觉相关的修改 具体话术 这是一个信息展示优化方案&#xff0c;用户为财务&#xff0c;信息区分度不足&#xff0c;理解成本较高&#xff0c;因此选择需要降低理解成本。…...

Linux评估网络性能

网络性能直接影响应用程序对外提供服务的稳定性和可靠性 ping命令检测网络的连通性 如果网络反应缓慢&#xff0c;或连接中断&#xff0c;可以用ping来测试网络的连通情况 time值(单位为毫秒)显示了两台主机之间的网络延时情况。如果此值很大&#xff0c;则表示网络的延时很大…...

实战ansible-playbook(四) -文件操作重定向/追加

原始命令: ----------阶段1--------------- apt-get update -y apt install nano vim iputils-ping net-tools dialog gcc apt-utils make -y systemctl stop unattended-upgradessystemctl disable unattended-upgradesecho APT::Periodic::Update-Package-Lists "1&qu…...

简单题:1.两数之和

题目描述&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 要求&#xff1a; 可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素…...

RTCMultiConnection 跨域问题解决

js套件地址 https://github.com/muaz-khan/RTCMultiConnection server套件地址 https://github.com/muaz-khan/RTCMultiConnection-Server 要解决的就是server代码的跨域问题 原装写法&#xff1a; 解决写法&#xff1a; // 喜欢组合语法的自己组 const io new ioServer.S…...

23种设计模式之解释器模式

目录 1. 简介2. 代码2.1 Expression &#xff08;抽象表达式类&#xff09;2.2 TerminalExpression &#xff08;终结符表达式类&#xff09;2.3 OrExpression &#xff08;非终结符表达式类&#xff09;2.4 AndExpression &#xff08;非终结符表达式类&#xff09;2.5 Test &…...

Postgresql内核源码分析-表数据膨胀是怎么回事

专栏内容&#xff1a;postgresql内核源码分析个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 表数据膨胀的由来 什么时候产生膨胀 首先是update 还有delete 如何消…...

github使用SSH进行克隆仓库

SSH 密钥拉取git 查询密钥是否存在 s -al ~/.ssh这个文件夹下 known_hosts 就是存在的密钥文件 创建密钥文件 ssh-keygen -t rsa -b 4096 -C "testtt.com"-t rsa 是 rsa 算法加密 -b 是指定密钥的长度&#xff08;以位为单位&#xff09;。 -C 是用于给密钥添加注…...

【Linux系统】 Linux内核与UNIX设计哲学的结合

Linux 内核虽然不是 UNIX 的直接衍生物&#xff0c;但它深受 UNIX 设计哲学的影响。Linux 的开发者&#xff0c;尤其是 Linus Torvalds&#xff0c;在设计和实现 Linux 时&#xff0c;借鉴了 UNIX 的核心思想&#xff0c;使 Linux 成为一个类 UNIX 系统。 以下从 UNIX 设计哲学…...

以太网PHY_RGMII通信(基于RTL8211)--FPGA学习笔记22

一、以太网基础知识 FPGA千兆网口数据传输MDIO接口——FPGA学习笔记3_yt8531sh原理图-CSDN博客 二、通信协议 1、MDIO协议格式 (1)Pre:前导码32bit全是1,同步通信 32bit (2)ST:开始字段 01 表示开始通信 2bit…...

PowerShell 脚本实战:解决 GitLab 仓库文件批量重命名难题

使用PowerShell脚本解决文件重命名问题&#xff1a;一次实践经验分享 在软件开发过程中&#xff0c;我们经常会遇到需要批量处理文件的情况。最近&#xff0c;我在一个项目中就遇到了这样一个需求&#xff1a;将GitLab仓库中所有的.ts和.py文件的扩展名修改为原扩展名加上&quo…...

数据分析及应用:滴滴出行打车日志数据分析

目录 0 日志数据集介绍 1 构建数据仓库 1.1 ods创建用户打车订单表 1.2 创建分区 1.3 上传到对应分区...

Odoo :一款免费且开源的食品生鲜领域ERP管理系统

文 / 贝思纳斯 Odoo金牌合作伙伴 引言 提供业财人资税的精益化管理&#xff0c;实现研产供销的融通、食品安全的追踪与溯源&#xff0c;达成渠道的扁平化以及直面消费者的 D2C 等数字化解决方案&#xff0c;以此提升运营效率与核心竞争力&#xff0c;支撑高质量的变速扩张。…...

请求路径中缺少必需的路径变量[xxxId]

一、请求路径中缺少了必需的路径变量 xxxId。 这通常发生在构建API请求时&#xff0c;未正确设置URL中的参数。以下是解决此问题的步骤&#xff1a; 检查API文档&#xff1a;确认 xxxId是否确实是请求路径中的必需参数。 构建请求URL&#xff1a;确保在构建请求URL时&#xff…...

【在Linux世界中追寻伟大的One Piece】HTTP cookie

目录 1 -> 引入HTTP cookie 1.1 -> 定义 1.2 -> 工作原理 1.3 -> 分类 1.4 -> 安全性 2 -> 认识cookie 2.1 -> 基本格式 2.2 -> GMT vs UTC 3 -> cookie的生命周期 3.1 -> 安全性考虑 3.2 -> 安全测试cookie 3.2.1 -> 测试co…...

COLA学习之DDD各种术语分析(一)

小伙伴们&#xff0c;你们好&#xff0c;我是老寇&#xff0c;前段时间&#xff0c;老寇刚看完张健飞老师的两本书《代码精进之路&#xff1a;从码农到工匠》和《程序员的底层思维》&#xff0c;书中的内容让我受益匪浅&#xff0c;因此&#xff0c;我把对COLA的理解做成专栏分…...

Pygments:高效的语法高亮工具

简介&#xff1a;Pygments 是一个强大的 Python 库&#xff0c;旨在为代码和文本提供优雅的语法高亮支持。无论是 Web 开发、文档生成&#xff0c;还是代码审阅&#xff0c;Pygments 都能轻松应对多种编程语言的高亮需求。其设计简洁、功能丰富&#xff0c;适合需要频繁进行代码…...

算法-字符串-43.字符串相乘

一、题目 二、思路解析 1.思路&#xff1a; 1.双重for循环&#xff0c;倒序依次相乘 2.在倒序处理进位问题 3.最后返回参数的类型是string&#xff0c;用StringBuilder拼接&#xff0c;再转换为字符串 2.常用方法&#xff1a; 1.equals,比较对象内容是否一致 "0".eq…...

linux的vdagent框架设计

1、vdagent Linux 的 spice 客户代理由两部分组成&#xff0c;一个系统范围的守护进程 spice-vdagentd 和一个 X11 会话代理 spice-vdagent&#xff0c;每个 X11 会话有一个。spice-vdagentd 通过 Sys-V initscript 或 systemd 单元启动。 如下图&#xff1a;spice-vdagent&a…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统

核心速览 研究背景 ​​研究问题​​&#xff1a;这篇文章要解决的问题是当前大型语言模型&#xff08;LLMs&#xff09;在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色&#xff0c;但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成&#xff08;RA…...