GO实现TCP/UDP通信

目录

GO的网络编程

                客户端和服务端模型

        TCP通信

                server端

                client端

        聊天模式

                服务端

                client端

        UDP编程

                服务器配置

                客户端配置


GO的网络编程

                客户端和服务端模型

 

 

七层模型

 

        socket: BSD UNIX的进程通信机制,通常也称作'套接字”,用于描述IP地址和端口,是一个通信链的句柄。socket可以理解为TCP/IP网络的API,它定义了许多函数,程序员可以使用它来开发TCP/IP网络的应用程序。计算机上运行对应用程序通常通过“套接字”向网络发出请求或者应答网络请求。

 

服务端处理流程;

1)监听端口

2)接收客户端连接

3)创建goroutine,处理此连接

客户端处理流程:

1)建立与服务端连接

2)进行数据收发

3)关闭连接

Apache是同步模型,Nginx是异步模型

        TCP通信

                server端

一个TCP服务端可以同时连接很多个客户端,例如世界各地的用户使用自己电脑上的浏览器访问淘宝网。因为Go语言中创建多个goroutine实现并发非常方便和高效,所以我们可以每建立一次链接就创建一个goroutine去处理。

package main
​
import (
    "fmt"
    "net"
)
​
//处理客户端连接
func proe(conn net.Conn)  {
    //关闭conn资源
    defer conn.Close()
    //定义接受字节数组
    var buf [1024]byte
    //获取有效数据
    n,err :=conn.Read(buf[:])
​
    if  err!=nil {
        fmt.Println("获取信息失败,err:",err)
        return
    }
    fmt.Printf("收到客户端信息是:%s",string(buf[:n]))
}
func main() {
    listener,err := net.Listen("tcp","127.0.0.1:20000")
    if err != nil {
        
        fmt.Println("服务启动失败")
        return
    }
    defer listener.Close()
    //建立连接
    for {
        conn , err :=listener.Accept()
​
        if err!=nil {
            fmt.Println("接受信息失败",err)
            continue
        }
​
        //启动goroutine
        go proe(conn)
    }
}

                client端

package main
​
import (
    "bufio"
    "fmt"
    "net"
    "os"
)
​
//TCP客户端配置
func main() {
​
    //1、使用拨号方式链接服务器
    conn, err := net.Dial("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("连接服务器失败,err:", err)
        return
    }
    //关闭连接
    defer conn.Close()
    reader := bufio.NewReader(os.Stdin)
    for {
​
        input, err := reader.ReadString('\n')
        if input == "q\r\n" {
            return
        }
        if err != nil {
            fmt.Println("控制台输入失败,err", err)
            return
        }
        //向服务器发送信息
        _, err = conn.Write([]byte(input))
        if err != nil {
            fmt.Println("信息发送失败,err:", err)
            return
        }
​
    }
}

最后效果,先起service端,再起客户端

 

        聊天模式

                服务端

package main
​
import (
    "fmt"
    "net"
)
​
//var ConnMap map[string]*net.TCPConn
​
func main() {
    listen_socket, err := net.Listen("tcp", "127.0.0.1:20000") //打开监听接口
    if err != nil {                                            //如果有错误
        fmt.Println("服务器连接失败")
        return
    }
​
    defer listen_socket.Close() //延迟服务器端关闭
    fmt.Println("服务器运行中....")
​
    for {
        conn, err := listen_socket.Accept() //监听客户端的端口
        if err != nil {
            fmt.Println("客户端开始失败")
        }
        fmt.Println("连接服务器成功") //显示服务器端连接成功
​
        var msg string //声明msg为字符串变量
​
        for {
            //开始接收客户端发过来的消息
            msg = ""                         //字符串msg初始为空
            data := make([]byte, 255)        //创建并声明数据变量,为255位
            msg_read, err := conn.Read(data) //接收由客户端发来的消息,字节赋值给msg_read,err为错误
            if msg_read == 0 || err != nil { //如果读取的消息为0字节或者有错误
                fmt.Println("err")
            }
​
            msg_read_str := string(data[0:msg_read]) //将msg_read_str的字节格式转化成字符串形式
            if msg_read_str == "close" {             //如果接收到的客户端消息为close
                conn.Write([]byte("close"))
                break
            }
            //fmt.Println(string(data[0:msg_read]))
            fmt.Println("客户端给服务器发送消息 ", msg_read_str) //接收客户端发来的信息
​
            fmt.Printf("对客户端发送消息: ") //提示向客户端要说的话
            fmt.Scan(&msg)                //输入服务器端要对客户端说的话
            //conn.Write([]byte("hello client\n"))
            //msg_write := []byte(msg)
            conn.Write([]byte(msg)) //把消息发送给客户端
            //此处造成服务器端的端口堵塞
        }
        //fmt.Println("client Close\n")
        conn.Close() //关闭连接
    }
​
}
​

                client端

// One-to-one ChatRoom Client
package main
​
import (
    "fmt"
    "net"
)
​
func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("连接失败")
        return
    }
    defer conn.Close()
    fmt.Println("连接成功")
​
    var msg string //声明msg为字符串变量
​
    for {
        msg = "" //初始化msg为空值
        fmt.Printf("给服务器发送消息: ")
        fmt.Scan(&msg) //输入客户端向服务器端要发送的消息
        //fmt.Println(msg)
        //msg_write := []byte(msg)
        //conn.Write(msg_write)
        conn.Write([]byte(msg)) //信息转化成字节流形式并向服务器端发送
        //此处造成客户端程序端口堵塞
        //fmt.Println([]byte(msg))
​
        //等待服务器端发送信息回来
        data := make([]byte, 255)
        msg_read, err := conn.Read(data)
        if msg_read == 0 || err != nil {
            fmt.Println("err")
        }
        msg_read_str := string(data[0:msg_read])
        if msg_read_str == "close" {
            conn.Write([]byte("close"))
            break
        }
​
        fmt.Println("服务器回应:", msg_read_str)
    }
    conn.Close()
}
​

运行结果

        UDP编程

UDP是用户数据报协议,是一种无连接传输协议,不需要建立连接就可以直接发送和接收数据,属于不可靠的,没有时序的通信,UDP实时性好,适合直播环境。

                服务器配置

package main
​
import (
    "fmt"
    "net"
)
​
func Porecss(listener *net.UDPConn) {
    //退出是关闭资源
    defer listener.Close()
​
    var b string
    for {
        //获取连接输出
        var buf [1024]byte
​
        n, addr, err := listener.ReadFromUDP(buf[:])
        if err != nil {
            fmt.Println("读取udp失败err=", err)
            return
        }
        //信息输出
        fmt.Printf("来自%v的回复,内容是%v\n", addr, string(buf[:n]))
​
        //信息回复
        fmt.Println("给客户端回复")
        fmt.Scan(&b)
        _, err = listener.WriteToUDP([]byte(b), addr)
        if err != nil {
            fmt.Println("回复失败err=", err)
            return
        }
​
    }
}
func main() {
    listener, err := net.ListenUDP("udp", &net.UDPAddr{
        IP: net.ParseIP("0.0.0.0"),
​
        Port: 38080,
    })
    if err != nil {
        fmt.Println("连接异常,err=", err)
    }
    Porecss(listener)
​
}
​


                客户端配置

package main
​
import (
    "fmt"
    "net"
)
​
func main() {
    conn, err := net.Dial("udp", "127.0.0.1:38080")
​
    if err != nil {
        fmt.Println("连接服务器失败,err:", err)
        return
    }
​
    defer conn.Close()
    //发送消息
​
    var a string
    for {
        fmt.Println("输入要发送的信息")
        fmt.Scan(&a)
        _, err = conn.Write([]byte(a))
        if err != nil {
            fmt.Println("信息发送失败,err", err)
            return
        }
        //接受消息
        var buf [1024]byte
        n, err := conn.Read(buf[:])
        if err != nil {
            fmt.Println("读取失败,err", err)
            return
        }
        fmt.Println("收到服务端的信息是:", string(buf[:n]))
    }
​
}
​
 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MQTT是一种轻量级的通信协议,用于在低带宽和不稳定的网络环境中传输消息。它使用发布-订阅模式,可以在设备和应用程序之间进行可靠的消息传递。 TCP(传输控制协议)是一种面向连接的协议,提供可靠的数据传输。在MQTT中,TCP是一种常用的传输方式,用于在客户端和MQTT代理之间建立稳定的连接,并确保消息的可靠传递。 UDP(用户数据报协议)是一种无连接的协议,提供了一种无需建立连接即可进行快速数据传输的方式。在MQTT中,并不常用UDP作为传输方式,因为它不能保证消息的可靠性和顺序传递。 因此,MQTT通常使用TCP作为传输协议,以确保消息的可靠传递和顺序传输。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [2018最新精选的Go框架,库和软件的精选列表 二 https://awesome-go.com/](https://blog.csdn.net/sanshengshi134/article/details/86635877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [MQTT windows客户端 同时支持TCP/UDP/MQTT/HTTP C++开发](https://download.csdn.net/download/bona020/9887123)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小柏ぁ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值