Go语言net模块TCP和UDP编程实践

任何一种语言TCP和UDP网络编程总是必须的,接下来就将go语言中使用net标准库进行TCP和UDP编程进行梳理总结。

目录

1.代码结构

2.TCP通信

3.UDP通信

4.TCP模拟HTTP协议通信

5.利用TCP扫描那些端口被占用


1.代码结构

2.TCP通信

server.go

package main

import (
	"fmt"
	"net"
)

func main() {
	//1.监听端口
	listen, err := net.Listen("tcp", "0.0.0.0:18383")
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}

	fmt.Println("listen Start...")

	for {
		//2.接收客户端连接
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("accept failed, err:%vn", err)
			continue
		}
		//3.开启Goroutine处理连接
		go process(conn)
	}
}

// 处理请求,类型就是net.Conn
func process(conn net.Conn) {

	//处理结束后关闭链接
	defer conn.Close()
	for {
		var buf [128]byte
		n, err := conn.Read(buf[:])
		if err != nil {
			fmt.Printf("read from conn failed, err: %v", err)
			break
		}
		fmt.Printf("recv from client, content: %vn", string(buf[:n]))
	}

}

client.go

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)

func main() {
	conn, err := net.Dial("tcp", "0.0.0.0:18383")
	if err != nil {
		fmt.Printf("dial failed, err: %vn", err)
		return
	}

	fmt.Println("conn established...")

	reader := bufio.NewReader(os.Stdin)
	for {
		data, err := reader.ReadString('n')
		if err != nil {
			fmt.Printf("read from console failed, err:%vn", err)
			break
		}

		data = strings.TrimSpace(data)

		_, err = conn.Write([]byte(data))
		if err != nil {
			fmt.Printf("write failed, err:%vn", err)
			break
		}
	}
}

运行结果:

3.UDP通信

server.go

package main

import (
	"fmt"
	"net"
)

func main() {
	//建立一个UDP的监听,这里使用的是ListenUDP,并且地址是一个结构体
	listen, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: 8080,
	})
	if err != nil {
		fmt.Printf("listen failed, err:%vn", err)
		return
	}

	for {
		var data [1024]byte
		//读取UDP数据
		count, addr, err := listen.ReadFromUDP(data[:])
		if err != nil {
			fmt.Printf("read udp failed, err:%vn", err)
			continue
		}

		fmt.Printf("recv data: %s addr: %v count: %dn", string(data[0:count]), addr, count)
		//返回数据
		_, err = listen.WriteToUDP([]byte("hello client, I am UDP server ^_^ ^_^"), addr)
		if err != nil {
			fmt.Printf("write udp failed, err:%vn", err)
			continue
		}
	}
}

client.go

package main

import (
	"fmt"
	"net"
)

func main() {
	// 创建连接
	socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 8080,
	})
	if err != nil {
		fmt.Println("连接失败!", err)
		return
	}
	defer socket.Close()
	// 发送数据
	senddata := []byte("hello server, I am UDP client !")
	_, err = socket.Write(senddata)
	if err != nil {
		fmt.Println("发送数据失败!", err)
		return
	}
	// 接收数据
	data := make([]byte, 4096)
	read, remoteAddr, err := socket.ReadFromUDP(data)
	if err != nil {
		fmt.Println("读取数据失败!", err)
		return
	}
	fmt.Println(read, remoteAddr)
	fmt.Printf("%sn", data)
}

运行结果:

4.TCP模拟HTTP协议通信

server.go

package main

import (
	"fmt"
	"net/http"
)

func main() {
	//http://127.0.0.1:8181/hello
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello world !"))
		fmt.Println("recv client connect ...")
	})

	server := http.Server{
		Addr:    "127.0.0.1:8181",
		Handler: nil, // 对应DefaultServeMux路由
	}
	server.ListenAndServe()
}

client.go

package main

import (
	"fmt"
	"io"
	"net"
)

func conn_baidu() {
	conn, err := net.Dial("tcp", "www.baidu.com:80")
	if err != nil {
		fmt.Printf("dial failed, err:%vn", err)
		return
	}

	data := "GET / HTTP/1.1rn"
	data += "HOST: www.baidu.comrn"
	data += "connection: closern"
	data += "rnrn"

	//写入数据
	_, err = io.WriteString(conn, data)
	if err != nil {
		fmt.Printf("wirte string failed, err:%vn", err)
		return
	}

	var buf [1024]byte
	for {
		//读取返回的数据
		n, err := conn.Read(buf[:])
		if err != nil || n == 0 {
			break
		}

		fmt.Println(string(buf[:n]))
	}
}

func conn_myself() {
	conn, err := net.Dial("tcp", "127.0.0.1:8181")
	if err != nil {
		fmt.Printf("dial failed, err:%vn", err)
		return
	}

	data := "GET /hello HTTP/1.1rn"
	data += "HOST: 127.0.0.1rn"
	data += "connection: closern"
	data += "rnrn"

	//写入数据
	_, err = io.WriteString(conn, data)
	if err != nil {
		fmt.Printf("wirte string failed, err:%vn", err)
		return
	}

	var buf [1024]byte
	for {
		//读取返回的数据
		n, err := conn.Read(buf[:])
		if err != nil || n == 0 {
			break
		}

		fmt.Println(string(buf[:n]))
	}
}

func main() {
	conn_myself()
}

运行结果:

5.利用TCP扫描那些端口被占用

port_scan.go

package main

import (
	"flag"
	"log"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"
)

func processPortItem(port string) []string {
	var ports []string
	arr := strings.Split(port, ",")
	for _, p := range arr {
		if strings.Contains(p, "-") {
			ports = append(ports, rangeToArr(p)...)
		} else {
			ports = append(ports, p)
		}
	}
	return ports
}

func rangeToArr(s string) []string {
	if strings.Contains(s, "-") {
		var arr []string
		from, _ := strconv.Atoi(strings.Split(s, "-")[0])
		to, _ := strconv.Atoi(strings.Split(s, "-")[1])
		if from == 0 {
			from = 1
		}
		if to == 0 {
			to = 65535
		}
		for i := from; i <= to; i++ {
			arr = append(arr, strconv.Itoa(i))
		}
		return arr
	} else {
		return []string{s}
	}
}

func scan(ip string, port string, wg *sync.WaitGroup) {
	conn, err := net.DialTimeout("tcp", ip+":"+port, time.Second)
	if err != nil {
		wg.Done()
		return
	}
	wg.Done()
	defer conn.Close()
	log.Println(ip, port, "port use !")
}

func main() {
	ip := flag.String("h", "127.0.0.1", "scan IP")
	port := flag.String("p", "1-65536", "scan port")
	flag.Parse()
	log.Println("scan info is :", *ip, *port)

	//线程同步
	wg := &sync.WaitGroup{}

	for _, p := range processPortItem(*port) {
		wg.Add(1)
		go scan(*ip, p, wg)
	}
	wg.Wait()
}

运行结果: