Golang Sockek编程

Posted zhichaoma

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang Sockek编程相关的知识,希望对你有一定的参考价值。

网络基本概念

  • 网络编程的目的:直接或间接地通过网络协议与其他计算机进行通讯
  • 网络编程中两个主要问题:
  • 如何准确定位网络上一台或多台主机(通过 IP 地址)
  • 找到主机后如何进行数据传输(有 OSI 模型和 TCP/IP 模型)
  • OSI 模型将网络分为 7 层,过于理想化,未能广泛推广
  • TCP/IP 是事实上的国际标准
OSI TCP/IP TCP/IP 对应的协议
应用层 应用层 HTTP、FTP、DNS
表示层
会话层
传输层 传输层 TCP、UDP
网络层 网络层 IP、ARP、ICMP
数据链路层 物理数据层 Link
物理层
  • IP 分类:最开始是 32 位整数,后来用圆点隔开,分成 4 段,8 位一段

    • A 类:保留给政府结构,1.0.0.1 ~ 126.255.255.254
    • B 类:分配给中型企业,1.0.0.1 ~ 126.255.255.254
    • C 类:分配给任何需要的个人,192.0.0.1 ~ 223.255.255.254
    • D 类:用于组播,224.0.0.1 ~ 239.255.255.254
    • E 类:用于实验,240.0.0.1 ~ 255.255.255.254
    • 回环地址:127.0.0.1,指本地机,一般用于测试使用
  • 端口号:0~65535

什么是 socket

  • Socket 又称套接字,应用程序通常通过“套接字”向网络发出请求或者应答网络请求
  • 常用的 Socket 类型有两种:流式 Socket 和数据报式 Socket,流式是一种面向连接的 Socket,针对于面向连接的 TCP 服务应用,数据报式 Socket 是一种无连接的 Socket,针对于无连接的 UDP 服务应用
  • TCP:比较靠谱,面向连接,比较慢
  • UDP:不是太靠谱,比较快

TCP 编程

  • 实现服务端与客户端通信,保持连接,服务器接收到 exit 时再断开连接

服务端

package main

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

// 处理客户端数据
func clientHandle(conn net.Conn) {
    // 关闭客户端连接
    defer conn.Close()
    // 获取客户端地址
    clientAddr := conn.RemoteAddr()
    fmt.Printf("%v 已连接
", clientAddr)

    // 创建读去数据的缓冲区
    buf := make([]byte, 1024)
    for {
        // 读取数据
        // n是读取到的长度
        n, err := conn.Read(buf)
        if err == io.EOF { // 读取完毕
            break
        }
        if err != nil { // 读取失败
            fmt.Println("读取客户端数据失败, err: ", err)
            return
        }

        // 取出接收到的数据
        readResult := string(buf[:n])
        // 判断是否为退出指令
        if readResult == "exit" {
            fmt.Printf("%d退出连接", clientAddr)
            return
        }
        fmt.Printf("接收到来自[%v]数据: %s", clientAddr, readResult)
        // 回复客户端
        _, err = conn.Write([]byte(strings.ToUpper(readResult)))
        if err != nil {
            fmt.Printf("给 %v 发送数据失败: %v", clientAddr, err)
            return
        }
    }
}

func main() {
    // 1. 创建服务端监听
    listener, err := net.Listen("tcp", "127.0.0.1:8080")
    if err != nil {
        fmt.Println("启动服务端失败, err: ", err)
        return
    }
    // 关闭服务端资源
    defer listener.Close()

    fmt.Println("服务端启动成功")

    // 循环监听服务端
    for {
        // 堵塞监听
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("堵塞监听失败, err: ", err)
            continue
        }
        // 启动协程去处理客户端请求
        go clientHandle(conn)
    }
}

客户端

package main

import (
    "fmt"
    "net"
)

func main() {
    // 创建连接
    conn, err := net.Dial("tcp", "127.0.0.1:8080")
    if err != nil {
        fmt.Println("创建连接失败, err: ", err)
        return
    }
    defer conn.Close()
    // 创建缓冲区
    buf := make([]byte, 1024)

    for {
        fmt.Printf("请输入要发送的内容: ")
        _, err = fmt.Scan(&buf)
        if err != nil {
            fmt.Println("接收输入有误, err: ", err)
            continue
        }
        fmt.Printf("发送内容[%s]到服务端
", string(buf))

        // 发送数据
        _, err = conn.Write(buf)
        if err != nil {
            fmt.Println("发送数据失败")
            continue
        }

        // 读取数据
        rn, err := conn.Read(buf)
        if err != nil {
            fmt.Println("读取数据失败")
            continue
        }
        fmt.Printf("接收到数据: %s
", string(buf[:rn]))
    }
}

UDP 编程

  • 编写客户端发送信息给服务,服务端返回信息,返回完切断

服务端

package main

import (
    "fmt"
    "net"
)

func main() {
    // 创建udp监听
    conn, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(127, 0, 0, 1),
        Port: 8080,
    })
    if err != nil {
        fmt.Println("创建监听失败, err: ", err)
        return
    }
    defer conn.Close()

    for {
        // 创建缓冲区
        buf := make([]byte, 1024)

        // 接收UDP传输
        n, addr, err := conn.ReadFromUDP(buf)
        if err != nil {
            fmt.Println(err)
            continue
        }
        fmt.Printf("来自: %s 接收到数据: %s
", addr, string(buf[:n]))
        // 返回信息
        _, err = conn.WriteToUDP([]byte("666"), addr)
        if err != nil {
            fmt.Println("err")
            continue
        }
    }
}

客户端

package main

import (
    "fmt"
    "net"
    "time"
)

func main() {
    // 连接服务端
    conn, err := net.DialUDP("udp4", nil, &net.UDPAddr{
        IP:   net.IPv4(127, 0, 0, 1),
        Port: 8080,
    })
    if err != nil {
        fmt.Println("连接udp服务失败")
    }
    defer conn.Close()

    for {
        // 发送数据到服务端
        _, err = conn.Write([]byte("老铁"))
        if err != nil {
            fmt.Println("发送数据失败, err: ", err)
            return
        }

        buf := make([]byte, 1024)
        n, addr, err := conn.ReadFromUDP(buf)
        if err != nil {
            fmt.Println("接收服务端数据失败, err: ", err)
            return
        }
        fmt.Printf("服务端: %v, 数据: %s
", addr, string(buf[:n]))
        time.Sleep(time.Second)
    }
}

以上是关于Golang Sockek编程的主要内容,如果未能解决你的问题,请参考以下文章

golang goroutine例子[golang并发代码片段]

代码片段 - Golang 实现简单的 Web 服务器

代码片段 - Golang 实现集合操作

json [Golang] golang #golang #snippets中有用的片段

java golang oop 2文章片段

golang 去练习片段