Go语言学习-网络基础

系列文章目录

GO语言学习-网络基础



前言

GO语言网络学习,网络的底层实现原理还是通过p网络的osix api实现,net 包是实现了对于网络接口的高级封装。此文章网络模块的学习主要是对于net 包中接口的练习。


一、网络模块学习

GO语言联系net包中TCP的协议实现客户端和服务端,客户端通过命令实现文件的上传和下载。

二、功能模块

1.客户端代码

思路: 客户端,上传文件,打开文件,读取数据,然后发送数据
客户端下载文件, 在网络中获取数据,然后写入文件;

代码如下(示例):


package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path"
	"strings"
)

var (
	up       int
	fileName string
)

const SOURCE_DIR = "E:/GoSource/tcp-trans-file/tcp-trans-file/sourceFile/"
const DOWNLOAD_DIR = "E:/GoSource/tcp-trans-file/tcp-trans-file/download/"

// 实现命令行参数
func getComandArgs() {
	flag.IntVar(&up, "up", 1, "0 下载, 1 上传")
	flag.StringVar(&fileName, "f", "", "文件名称")
	flag.Parse()
}

func main() {
	log.SetFlags(log.Llongfile)
	getComandArgs()

	// 建立网络链接,监听localhsot:9090 端口
	conn, err := net.Dial("tcp", "localhost:9090")
	if err != nil {
		log.Println(err)
		return
	}

	defer conn.Close()
	// fileName 中路径中的window格式路径转换成linux 格式
	fileName = strings.ReplaceAll(fileName, "\\", "/")
	_, fileName = path.Split(fileName) // 分割术只识别”/“, 不能够识别”\“
	isUp := byte(1)

	if up != 1 {
		isUp = byte(0)
	}

	// 第一个包的格式 0:up/down 1Byte: filenamelen, 其它 filename
	fileInfoByte := make([]byte, 0, 1024) // 0 :len  1024 cap
	fileInfoByte = append(fileInfoByte, isUp, byte(len(fileName)))
	fileInfoByte = append(fileInfoByte, []byte(fileName)...)
	fileInfoByte = fileInfoByte[:1024]

	if _, err := conn.Write(fileInfoByte); err != nil {
		log.Println(err)
		return
	}

	if isUp == 1 {
		err := sendFile(conn, SOURCE_DIR+fileName)

		if err != nil {
			log.Println(err)
			return
		}
	} else {
		fmt.Printf("%s", DOWNLOAD_DIR+fileName)
		err := recvFile(conn, DOWNLOAD_DIR+fileName)

		if err != nil {
			log.Println(err)
			return
		}
	}

	//	fmt.Println(isUp)
	//	fmt.Println(fileInfoByte)

	/*
		data := make([]byte, 1024)
		copy(data, "hello server\n")

		number, err := conn.Write(data)
		if err != nil {
			fmt.Println(err)
			return
		}

		fmt.Println(number, err)

		data1 := make([]byte, 1024)
		n, err := conn.Read(data1)
		if err != nil {
			log.Println(err)
			return
		}

		fmt.Println(string(data1[:n]))
	*/
}

func sendFile(conn net.Conn, filePath string) (err error) {
	src, err := os.Open(filePath)
	if err != nil {
		log.Println(err)
		return
	}

	defer src.Close()

	buf := make([]byte, 1024)
	n := 0
	for {
		n, err = src.Read(buf)
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		} else {
			err = nil
		}

		if n == 0 {
			break
		}

		if _, err = conn.Write(buf[:n]); err != nil {
			log.Println(err)
			return
		}
	}
	return
}

func recvFile(conn net.Conn, filePath string) (err error) {
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Println(err)
		return
	}
	defer file.Close()

	buf := make([]byte, 1024)
	n := 0
	for {
		n, err = conn.Read(buf)
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		} else {
			err = nil
		}
		if n == 0 {
			break
		}
		file.Write(buf)
	}
	return
}

2.服务端代码

代码如下(示例):

package main

import (
	"io"
	"log"
	"net"
	"os"
)

const OP_UPLOAD = 1
const OP_DOWNLOAD = 0

const UPLOAD_DIR = "E:/GoSource/tcp-trans-file/tcp-trans-file/upload/"

const SOURCE_DIR = "E:/GoSource/tcp-trans-file/tcp-trans-file/sourceFile/"

func main() {
	log.SetFlags(log.Llongfile)
	listener, err := net.Listen("tcp", ":9090")
	if err != nil {
		log.Println(err)
		return
	}

	defer listener.Close()
	log.Println("listen on:", listener.Addr().String())

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			return
		}
		log.Println("new conn:", conn.RemoteAddr())
		go handle(conn)
	}
}

func handle(conn net.Conn) {
	defer func() {
		recover()
		log.Println("close conn", conn.RemoteAddr())
		conn.Close()
	}()
	//文件的前1024个字节存放文件信息,  0: 上传还是下载
	fileInfoBytes := make([]byte, 1024)
	_, err := conn.Read(fileInfoBytes)
	if err != nil {
		log.Println(err)
		return
	}

	op := int(fileInfoBytes[0])
	fileNameLen := int(fileInfoBytes[1])
	fileName := string(fileInfoBytes[2 : fileNameLen+2])

	if op == OP_UPLOAD {
		err := receFile(conn, UPLOAD_DIR+fileName)
		if err != nil {
			log.Println(err)
			return
		}
	} else if op == OP_DOWNLOAD {
		err := sendFile(conn, SOURCE_DIR+fileName)
		if err != nil {
			log.Println(err)
			return
		}
	}

	/*
		fmt.Println(string(data[:n]))

		n, err = conn.Write([]byte("recv:" + string(data[:n])))
		if err != nil {
			log.Println(err)
			return
		}
	*/
}

func receFile(conn net.Conn, filePath string) (err error) {
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0644)
	//file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Println(err)
		return
	}

	defer file.Close()

	buf := make([]byte, 1024)

	n := 0

	for {
		n, err = conn.Read(buf)
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		} else {
			err = nil
		}

		if n == 0 {
			break
		}
		file.Write(buf)
	}
	return
}

func sendFile(conn net.Conn, filePath string) (err error) {
	src, err := os.Open(filePath)
	if err != nil {
		log.Println(err)
		return
	}
	defer src.Close()
	buf := make([]byte, 1024)
	n := 0
	for {
		n, err = src.Read(buf)
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		} else {
			err = nil
		}
		if n == 0 {
			break
		}
		if _, err = conn.Write(buf[:n]); err != nil {
			log.Println(err)
			return
		}
	}
	return
}


总结

在网络模块的联系中,一定要注意语言的特性,使用双引号一定要是英文的,避免中文格式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值