首页 > 其他分享 >gnet--高性能的网络库

gnet--高性能的网络库

时间:2024-04-27 12:12:36浏览次数:19  
标签:return err nil -- gnet 高性能 data log

官网地址 https://github.com/panjf2000/gnet

这里要吐槽一下,官网没有任何使用文档,也没有example,源码test都么有。。。。

客户端

package main

import (
	"encoding/binary"
	"io"
	"log"
	"net"
)

// 封包函数
func packageData(data []byte) ([]byte, error) {
	length := len(data)
	lengthBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(lengthBytes, uint32(length))
	return append(lengthBytes, data...), nil
}

// 解包函数
func unpackageData(reader io.Reader) ([]byte, error) {
	// 读取长度前缀
	lengthBytes := make([]byte, 4)
	_, err := io.ReadFull(reader, lengthBytes)
	if err != nil {
		return nil, err
	}

	// 将长度前缀转换为整数
	length := binary.BigEndian.Uint32(lengthBytes)

	// 读取数据
	data := make([]byte, length)
	_, err = io.ReadFull(reader, data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		log.Fatal("连接失败:", err)
	}
	defer conn.Close()

	// 要发送的数据
	data := []byte("Hello, World!")

	// 封包
	packet, err := packageData(data)
	if err != nil {
		log.Fatal("封包失败:", err)
	}

	// 发送封包后的数据
	_, err = conn.Write(packet)
	if err != nil {
		log.Fatal("发送失败:", err)
	}

	// 接收响应
	response, err := unpackageData(conn)
	if err != nil {
		log.Fatal("解包失败:", err)
	}

	// 打印服务器响应
	log.Println("服务器响应:", string(response))
}

服务端

package main

import (
	"encoding/binary"
	"fmt"
	"github.com/panjf2000/gnet/v2"
	"io"
	"log"
	"net"
	"time"
)

func init() {
	fmt.Println("测试加载多少次")
}

var maps = make(map[net.Addr]struct{})

// TODO 假设我们的前缀都是4个字节
// 解包函数,从字节流中提取数据
func unpackageData(reader io.Reader) ([]byte, error) {
	// 读取长度前缀
	lengthBytes := make([]byte, 4)
	_, err := io.ReadFull(reader, lengthBytes)
	if err != nil {
		return nil, err
	}

	// 将长度前缀转换为整数
	length := binary.BigEndian.Uint32(lengthBytes)

	// 读取数据
	data := make([]byte, length)
	_, err = io.ReadFull(reader, data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// 封包函数,将数据和其长度序列化成字节流
func packageData(data []byte) ([]byte, error) {
	// 计算数据长度
	length := len(data)
	// 将长度转换为字节
	lengthBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(lengthBytes, uint32(length))

	// 拼接长度前缀和数据
	packet := append(lengthBytes, data...)

	return packet, nil
}

type myhandler struct{}

// OnBoot在引擎准备好接受连接时触发。 参数引擎包含信息和各种实用程序
func (c *myhandler) OnBoot(eng gnet.Engine) (action gnet.Action) {
	log.Println("程序启动")
	return
}

// 打开新连接时触发OnOpen。
func (c *myhandler) OnOpen(conn gnet.Conn) (out []byte, action gnet.Action) {
	log.Println("新连接触发,在线人数", len(maps))
	maps[conn.RemoteAddr()] = struct{}{}
	return
}

// 关闭时触发
func (c *myhandler) OnClose(conn gnet.Conn, err error) (action gnet.Action) {
	log.Println("连接关闭")
	return
}

// OnTraffic在套接字接收到远程数据时触发。
func (c *myhandler) OnTraffic(conn gnet.Conn) (action gnet.Action) {
	log.Println("接收到消息了")
	//解包
	data, err := unpackageData(conn)
	if err != nil {
		if err == io.EOF {
			log.Println("连接关闭")
			return gnet.Close
		}
		log.Println("解包错误")
		return
	}
	fmt.Println(string(data))
	//回复消息,封包
	data, err = packageData([]byte("hello"))
	if err != nil {
		log.Println("封包错误")
		return
	}
	//异步发消息,可以加回调
	conn.AsyncWrite(data, nil)
	//conn.AsyncWrite(data, func(conn gnet.Conn, err error) error {
	//	if err != nil {
	//		log.Println("发送消息错误")
	//		return err
	//	}
	//	return nil
	//})
	return
}

// OnTick定时器
func (c *myhandler) OnTick() (delay time.Duration, action gnet.Action) {
	log.Println("定时器")
	delay = 5 * time.Second // 每5秒触发一次
	return
}

// OnShutdown在引擎关闭时触发,它在关闭后被调用
func (c *myhandler) OnShutdown(eng gnet.Engine) {
	log.Println("关机了")
}

//启动时可选参数
/*
// Multicore表示引擎是否会被有效地创建为多核,如果是,
//那么你必须注意在所有事件回调之间同步内存,否则
//它将以单线程运行引擎。引擎中的线程数将自动计算
//指定当前进程可用的逻辑cpu的值。
Multicore bool

//设置NumEventLoop以启动给定数量的事件循环程序。
//注意:设置NumEventLoop将覆盖多核。
NumEventLoop int

// LB表示分配新连接时使用的负载均衡算法。
LB loadbalance

// ReuseAddr是否设置SO_REUSEADDR套接字选项。
ReuseAddr bool

// ReusePort是否设置SO_REUSEPORT套接字选项
ReusePort bool

// MulticastInterfaceIndex是组播UDP地址绑定的接口名称索引。
MulticastInterfaceIndex int

// ReadBufferCap是可读事件发生时可以从远程读取的最大字节数。
//默认值是64KB,它可以减少以避免饿死后续连接或增加
//从套接字读取更多数据。
//
//注意ReadBufferCap将始终被转换为大于的两个整数值的最小次幂
//或等于其实际金额。
ReadBufferCap int

// WriteBufferCap是静态出站缓冲区可以容纳的最大字节数,
//如果数据超过这个值,溢出的数据将被存储在弹性链表缓冲区中。
//默认为64KB。
//
//注意,WriteBufferCap总是会被转换为两个大于的整数的最小次幂
//或等于其实际金额。
WriteBufferCap int

// LockOSThread用于确定每个I/O事件循环是否与一个操作系统线程相关联,它在您
//需要某种机制,如线程本地存储,或调用某些C库(如图形库:GLib)
//需要通过go进行线程级操作,或者希望所有I/O事件循环实际上并行运行
//潜在的更高性能。
LockOSThread bool

// Ticker指示Ticker是否已设置。
股票行情自动收录器bool

// TCPKeepAlive设置(SO_KEEPALIVE)套接字选项的持续时间
TCPKeepAlive时间。持续时间

// TCPNoDelay控制操作系统是否应该延迟
//数据包传输希望发送更少的数据包(Nagle的算法)。
//
//默认为true(无延迟),表示发送数据
//写入操作完成后尽快返回。
TCPNoDelay TCPSocketOpt

// SocketRecvBuffer以字节为单位设置最大socket接收缓冲区。
SocketRecvBuffer int

// SocketSendBuffer以字节为单位设置最大socket发送缓冲区。
SocketSendBuffer int

// LogPath将写入日志的本地路径,这是设置日志记录的最简单方法;
// gnet使用这个给定的日志路径实例化一个默认的uber-go/zap日志记录器,你也可以使用
//通过实现以下日志,在生命周期内拥有日志记录器。日志界面。
//
//注意,这个选项可以被选项Logger覆盖。
LogPath字符串

// LogLevel表示日志级别,它应该与LogPath一起使用。
LogLevel日志记录。水平

// Logger是用于记录信息的自定义记录器,如果没有设置,
//那么gnet将使用由go.uber.org/zap提供支持的默认记录器。
日志记录。日志记录器

// EdgeTriggeredIO为底层epoll/kqueue事件循环启用边缘触发I/O。
//除非你100%确定你在做什么,否则不要启用它。
//注意,这个选项只对面向流的协议有效。
EdgeTriggeredIO bool
*/
func main() {
	my := new(myhandler)
    //WithNumEventLoop 可以用cpu核数
	err := gnet.Run(my, "tcp://0.0.0.0:8080",
		gnet.WithTicker(false),
		gnet.WithMulticore(false),
		gnet.WithNumEventLoop(8),
		gnet.WithReusePort(true),
		gnet.WithReuseAddr(true))
	fmt.Println(err)
}

开启多线程之后

标签:return,err,nil,--,gnet,高性能,data,log
From: https://www.cnblogs.com/qcy-blog/p/18161902

相关文章

  • 计算机Windows系统优化小知识
    目录目录什么是注册表优化优化工具什么是注册表注册表是保存所有系统设置数据的存储器。注册表保存了Windows运行所需的各种参数和设置,以及应用程序相关的所有信息。从Windows启动开始,到用户登录、应用程序运行等所有操作都需要以注册表中记录的信息为基础。注册表在Windows操......
  • CUDA和CUDNN版本切换
    0背景在用不同框架做深度学习时,难免会遇到需要不同版本的cuda和cudnn版本的情况,如果把原来版本的卸载掉重新安装新版本,则会影响其它框架的使用,最好的方法是在主机上安装多个版本的cuda和cudnn,需要用到哪种就切换到哪种,这样就免去了重复卸载安装的工作。cuda:由NVIDIA推出的通用......
  • 一键启动的AI离线知识库,无需复杂环境依赖,小白都能上手了
    简介在人工智能技术飞速发展的今天,我们经常面临一个挑战:如何快速、简便地部署和使用AI技术?AntSK项目,一个开源的AI知识库和智能体,就是为了解决这一问题而诞生的。现在,我们自豪地宣布,AntSK已经实现了无需复杂部署的一键启动功能,让每个人都能轻松拥抱AI的便利。为什么选择AntSK?......
  • Linux系统下jmeter 分布式压测环境部署
    使用jmeter做分布式压测时,需要一台主机master做控制,以及需要至少一台以上slave机器来做负载机。只需要在master,slave的jmeter.properties做简单的配置就可实现(jmeter版本及jdk版本最好一致,避免出现不必要的兼容问题)例如用19.13.198.236作为master控制机,19.13.198.238/237......
  • 使用 chezmoi & vscode, 管理你的 dotfiles
    什么是dotfilesInUnix-likeoperatingsystems,anyfileorfolderthatstartswithadotcharacter(forexample,/home/user/.config),commonlycalledadotfileordotfile.任何以.开头去命名的文件或者目录都可以称为dotfile,在Unix-like系统一般用的比较多......
  • Axum vs Actix vs Rocket
    Inthisarticle,wewillconductaperformancecomparisonofthreeofthemostpopularRustwebframeworks:Axum,Actix,andRocket.HowwearegoingtotestOneachframeworkwearegoingtoimplementsimpleWeb-servicewiththreeendpoints:POST/tes......
  • 计算机DIY之接驳线缆
    目录目录接驳线缆CPU供电:主板主供电显卡供电SATA供电大4pin供电主板接驳前面板接驳接驳线缆电源插头里还有3条ATX电源专有的线,一条绿色线,是PS-ON电源启动信号线;一条灰色线,是PowerOK电源正常工作线;一条紫色线,是+5VSB线,提供给主板+5VStandby电源,供电源启动电路使用。......
  • 芯科SiWx917学习笔记:1-测试Out of Box Demo
    实验目的:测试OutofBoxDemo实验环境:SimplicityStudioV5实验器材:WirelessStarterKitMainboard(BRD4002ARevA06)+ SiWG917SingleBandWi-FiandBLE8MBFlashRadioBoard(BRD4338ARevA01)实验开始:1.新建工程:在demos中找到OutofBoxDemo(SoC)应用演示工程......
  • 实验三
    实验任务11#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);//函数声明8voidprint_spaces(intn);//函数声明9voidprint......
  • 硬盘保存及维护基本常识
    目录目录硬盘使用寿命简介硬盘供电简介硬盘保存简介硬盘使用寿命简介硬盘在连续使用3-4年后就需要注意了(一般为质保期时间后一点),5-6年后就需要更换硬盘了.五年左右的时候留意更换机械硬盘,如果不是特备重要的数据,可以考虑观察,一旦有任意一块硬盘出现故障,不要犹豫,立刻重建数......