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
}

总结


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

目录
相关文章
|
11天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
23 7
|
11天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
11天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
88 71
|
11天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
96 67
|
13天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
86 62
|
11天前
|
存储 Go
go语言中映射
go语言中映射
29 11
|
13天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
28 12
|
12天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
22 9
|
12天前
|
Go 索引
go语言使用range关键字
go语言使用range关键字
21 7
|
13天前
|
Go
go语言for 遍历字符串
go语言for 遍历字符串
25 8