net/socket 通信基本流程和文件传输案例|青训营笔记

151 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第四篇笔记

服务端

  1. 创建监听socket listener := net.Listen("tcp", "IP+port")
  2. 启动监听 conn := listener.Accept()
  3. 读取监听的数据 conn.Read()
  4. 回写给客户端数据 conn.Write()
  5. defer 注册关闭两个socket :listener,conn
func main() {
  listener, err := **net.Listen**("tcp", "127.0.0.1:8989")
  if err != nil {
    fmt.Println("net.Listen err:", err)
    return
  }
  defer listener.Close()

  fmt.Println("服务器已启动,正在监听....")

  conn, err := **listener.Accept()**
  if err != nil {
    fmt.Println("listener.accept err:", err)
    return
  }
  defer conn.Close()

  buf := make([]byte, 4096)
  n, err := **conn.Read(buf)**
  conn.Write([]byte(fmt.Sprintf("收到来自你的%d字节数据", n)))
}

并发服务器

  1. 创建 监听套接字 listener := net.Listen("tcp", 服务器的IP+port)
    • 同时注册关闭defer listener.Close()
  2. for 循环 阻塞监听 客户端连接事件 conn := listener.Accept()
  3. 创建 go程 对应每一个 客户端进行数据通信 go HandlerConnet()
  4. 实现 HandlerConnet(conn net.Conn)
    1. defer conn.Close()
    2. 获取成功连接的客户端 Addr conn.RemoteAddr()
    3. for 循环 读取 客户端发送数据 conn.Read(buf)
    4. 处理数据
    5. 回写转化后的数据 conn.Write(buf[:n])
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8090")
   //err..
defer listener.Close()
fmt.Println("服务器已启动,正在监听....")

for {
  conn, err := listener.Accept()
  //err..
  go handleCon(conn)
}
}

func handleCon(conn net.Conn) {
defer conn.Close()
addr := conn.RemoteAddr()
fmt.Println(addr, " 连接成功")
buf := make([]byte, 4096)
for {
  n, err := conn.Read(buf)
  if n == 0 {
    fmt.Println("对方已关闭连接")
    return
  }
  //err..
  fmt.Println("收到来自:", addr, ":", string(buf[:n]))
  conn.Write([]byte(fmt.Sprintf("收到来自你的%d字节数据\n", n)))
}

}

判断对端关闭

  • Read读客户端/服务器,返回 0
  • 注意发送数据时末尾自带的 '\n'

客户端

  1. conn, err := net.Dial("tcp", 服务器的IP+port)
  2. 写数据给 服务器 conn.Write()
  3. 读取服务器回发的 数据 conn.Read()
  4. conn.Close()
func main() {
  conn, err := net.Dial("tcp", "127.0.0.1:8989")
  if err != nil {
    fmt.Println("net.Dial err:", err)
    return
  }
  defer conn.Close()

  buf := make([]byte, 4096)
  conn.Write([]byte("你好,服务器"))
  conn.Read(buf)

  fmt.Println("读到来自服务器的消息:", string(buf))

}

文件传输案例

发送端(客户端)

  1. 获取绝对文件名 filepath
  2. 使用 os.Stat() 获取文件属性,得到纯文件名 fileName
  3. 主动发起连接服务器请求,结束时关闭连接。
  4. 发送文件名到接收端 conn.Write()
  5. 读取接收端回发的确认数据 conn.Read()
  6. 判断是否为“ok”。如果是,封装函数 SendFile() 发送文件内容。传参 filePath 和 conn
  7. 只读 Open 文件, 结束时Close文件
  8. 循环读本地文件,读到 EOF,读取完毕。
  9. 将读到的内容原封不动 conn.Write 给接收端(服务器)

接收端(服务器)

  1. 创建监听 listener,程序结束时关闭。
  2. 阻塞等待客户端连接 conn,程序结束时关闭conn。
  3. 读取客户端发送文件名。保存 fileName。
  4. 回发“ok”。
  5. 封装函数 RecvFile 接收客户端发送的文件内容。传参 fileName 和 conn
  6. 按文件名 Create 文件,结束时 Close
  7. 循环 Read 发送端网络文件内容,当读到 0 说明文件读取完毕。
  8. 将读到的内容原封不动Write到创建的文件中