亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Golang 學習筆記——網絡編程

標簽:
Go

Golang 主要面向后端服务编程,网络通信是服务端程序必不可少的重点。主流通信协议有 udp 和 tcp,通过编程语言封装成 socket,简化编程。主要实现对应的服务端和客户端。

  • golang udp
  • golang tcp
  • golang kcp

Golang udp

server

import (
	"fmt"
	"net"
)

func main() {
	laddr, err := net.ResolveUDPAddr("udp", ":9000")
	if err != nil {
		fmt.Println("地址解析失败!", err)
		return
	}
	conn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		fmt.Println("udp服务启动失败!", err)
		return
	}
	fmt.Println("udp服务启动成功")
	defer conn.Close()

	for {
		buf := make([]byte, 65535)
		num, remoteAddr, err := conn.ReadFromUDP(buf)
		if err != nil {
			fmt.Println("接收数据失败!", err)
			continue
		}

		fmt.Println("客户端地址:", remoteAddr)
		fmt.Printf("接收客户端数据长度:%d, 数据:%s", num, buf)

		send := []byte("receive success!")

		_, err = conn.WriteToUDP(send, remoteAddr)
		if err != nil {
			fmt.Println("发送数据失败!", err)
			continue
		}
	}
}

client

import (
	"fmt"
	"net"
)

func main() {

	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9000")
	if err != nil {
		fmt.Println("地址解析失败!", err)
		return
	}
	conn, err := net.DialUDP("udp", nil, laddr)
	if err != nil {
		fmt.Println("连接服务失败!", err)
		return
	}

	send := []byte("hello world!")

	_, err = conn.Write(send)
	if err != nil {
		fmt.Println("发送数据失败!", err)
		return
	}
	buf := make([]byte, 65535)
	num, remoteAddr, err := conn.ReadFromUDP(buf)
	if err != nil {
		fmt.Println("接收数据失败!", err)
		return
	}

	fmt.Println("服务端地址:", remoteAddr)
	fmt.Printf("接收服务端数据长度:%d, 数据:%s", num, buf)
}

图片描述
图片描述

Golang tcp

server


import (
	"fmt"
	"net"
)

func main() {
	laddr, err := net.ResolveTCPAddr("tcp", ":9000")
	if err != nil {
		fmt.Println("地址解析失败!", err)
		return
	}
	listener, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		fmt.Println("tcp服务启动失败!", err)
		return
	}
	fmt.Println("tcp服务启动成功")
	defer listener.Close()
	for {

		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Println("建立连接失败!", err)
			continue
		}
		go handleTcpClient(conn)
	}
}

func handleTcpClient(conn *net.TCPConn) {
	buf := make([]byte, 4096)
	for {
		num, err := conn.Read(buf)
		if err != nil {
			fmt.Println("接收数据失败!", err)
			return
		}
		fmt.Println("客户端地址:", conn.RemoteAddr())
		fmt.Printf("接收客户端数据长度:%d, 数据:%s", num, buf[:num])

		if fmt.Sprintf("%s", buf[:num]) == "ByeBye" {
			// 接收到 ByeBye 就断线
			fmt.Println("客户端离线!")
			return
		}
		send := []byte("receive success!")
		_, err = conn.Write(send)
		if err != nil {
			fmt.Println("发送数据失败!", err)
			return
		}
	}
}

client

import (
	"fmt"
	"net"
)

func main() {

	laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:9000")
	if err != nil {
		fmt.Println("地址解析失败!", err)
		return
	}
	conn, err := net.DialTCP("tcp", nil, laddr)
	if err != nil {
		fmt.Println("连接服务失败!", err)
		return
	}

	send := []byte("hello world!")
	buf := make([]byte, 65535)
	for i := 0; i < 10; i++ {
		_, err = conn.Write(send)
		if err != nil {
			fmt.Println("发送数据失败!", err)
			return
		}
		num, err := conn.Read(buf)
		if err != nil {
			fmt.Println("接收数据失败!", err)
			return
		}

		fmt.Println("服务端地址:", conn.RemoteAddr())
		fmt.Printf("接收服务端数据长度:%d, 数据:%s", num, buf[:num])
	}
	bye := []byte("ByeBye")
	_, err = conn.Write(bye)
	if err != nil {
		fmt.Println("发送数据失败!", err)
		return
	}
}

图片描述
图片描述

Golang kcp

简介:kcp是一个基于udp实现快速、可靠、向前纠错的的协议,能以比TCP浪费10%-20%的带宽的代价,换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果。
kcp-go是用go实现了kcp协议的一个库.

server

import (
	"fmt"
	"github.com/xtaci/kcp-go"
)

func main() {
	// 不加密,不设置
	listener, err := kcp.ListenWithOptions(":9000", nil, 0, 0)
	if err != nil {
		fmt.Println("udp服务启动失败!", err)
		return
	}
	fmt.Println("kcp服务启动成功")
	defer listener.Close()
	for {

		conn, err := listener.AcceptKCP()
		if err != nil {
			fmt.Println("建立连接失败!", err)
			continue
		}
		fmt.Println("客户端地址:", conn.RemoteAddr())
		go handleKcpClient(conn)
	}
}

func handleKcpClient(conn *kcp.UDPSession) {
	buf := make([]byte, 4096)
	for {
		num, err := conn.Read(buf)
		if err != nil {
			fmt.Println("接收数据失败!", err)
			return
		}
		fmt.Printf("接收客户端数据长度:%d, 数据:%s\n", num, buf[:num])

		if fmt.Sprintf("%s", buf[:num]) == "ByeBye" {
			// 接收到 ByeBye 就断线
			fmt.Println("客户端离线!")
			return
		}
		send := []byte("receive success!")
		_, err = conn.Write(send)
		if err != nil {
			fmt.Println("发送数据失败!", err)
			return
		}
	}
}

client

import (
	"fmt"
	"github.com/xtaci/kcp-go"
	"strconv"
	"time"
)

var data = []byte("hello world!")

func main() {

	conn, err := kcp.DialWithOptions("127.0.0.1:9000", nil, 0, 0)
	if err != nil {
		fmt.Println("连接服务失败!", err)
		return
	}
	fmt.Println("服务端地址:", conn.RemoteAddr())

	go handleKcpConn(conn)

	select {}
}

func handleKcpConn(conn *kcp.UDPSession) {
	buf := make([]byte, 65535)

	for {
		send := append(data, strconv.FormatInt(time.Now().Unix(), 10)...)
		num, err := conn.Write(send)
		if err != nil {
			fmt.Println("发送数据失败!", err)
			return
		}
		num, err = conn.Read(buf)
		if err != nil {
			fmt.Println("接收数据失败!", err)
			return
		}
		fmt.Printf("接收服务端数据长度:%d, 数据:%s\n", num, buf[:num])

		time.Sleep(time.Second)
	}
}

图片描述
图片描述

kcp-go实现的 kcp 编程看上去和 tcp 很相似,但是实际底层使用的是 udp 协议。kcp 头部占24个字节,kcp 发送数据会先分包,加装 kcp 头部,再通过 udp 发送数据到远端。远端需要返回 ack,根据返回的ack来判断数据段是否需要重传还是在队列里清除该数据段。用抓包工具抓包就会发现有很多24字节的 udp 包。

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
全棧工程師
手記
粉絲
2
獲贊與收藏
2

關注作者,訂閱最新文章

閱讀免費教程

  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消