当前位置: 首页 > news >正文

go入门实践二-tcp服务端

文章目录

    • 前言
    • 接口与方法
    • 并发-协程
    • 项目管理
    • bufio包使用
    • 其他代码

前言

上一篇,我们通过go语言的hello-world入门,搭建了go的编程环境,并对go语法有了简单的了解。本文实现一个go的tcp服务端。借用这个示例,展示接口、协程、bufio的使用,与简单的go项目管理;

本文代码见:laboratory/14-go-tcp


接口与方法

首先,我们需要了解go中接口的语法。首先阅读欢迎使用 Go 指南-方法和接口, 了解基本使用。然后到Go 语言接口-菜鸟教程中看一个简单的示例。最后有个理解 Go interface 的 5 个关键点 (吐槽:示例中的变量命名太烂。类似的也可以阅读Go Interfaces 使用教程), 来个小结。

好了,有了上面的基础后,我们来考虑编程。

假定这里需要实现一个tcp的服务端。拓展考虑下:实现一个udp服务端;实现一个http服务端;实现一个socks5服务端。

从C++的角度来考虑:创建一个server类,其中包含一些虚函数。需要tcp服务器,则创建一个继承server类的tcp子类;需要udp服务器,则创建一个继承server类的udp子类;需要http服务端,则创建继承tcp类的http子类;需要socks5服务器,则创建继承tcp和udp类的socks5子类;

事情到了go中,则有所不同。go中没有类与继承。go不是根据类型可以容纳的数据类型来设计抽象,而是根据类型可以执行的操作来设计抽象。interface 是一种具有一组方法的类型。如果一个类型实现了一个 interface 中所有方法,我们说类型实现了该 interface。

代码如下。修改自:go入门指南-15.1. tcp 服务器、Go语言实现TCP服务端和客户端

package server// tips1: 包中需要导出的内容,需要大写字母开头import ("bufio""fmt""net""strconv"
)type Server interface {start()
}type TcpServer struct {Ip   stringPort int
}func (server *TcpServer) Start() {fmt.Println("tcp server start...")// 创建 listenerlistener, err := net.Listen("tcp", server.Ip+":"+strconv.Itoa(server.Port))if err != nil {fmt.Println("Error listening:", err.Error())return}// 监听并接受来自客户端的连接for {conn, err := listener.Accept()if err != nil {fmt.Println("Error accepting", err.Error())return}go tcpConnProcess(conn)}
}func tcpConnProcess(conn net.Conn) {defer conn.Close()// reader := bufio.NewReader(conn)for {reader := bufio.NewReader(conn) // 错误-应该写在外层var buf [128]byten, err := reader.Read(buf[:])if err != nil {fmt.Println("Error read", err)break}recvStr := string(buf[:n])fmt.Println("receive:", recvStr)conn.Write([]byte(recvStr))}
}

并发-协程

上面代码中对于协程的使用倒是很简单,使用协程来处理每个连接。下面,我们阅读些关于协程的链接。

首先了解基本的goroutine 和 channel的基本概念:欢迎使用 Go 指南-并发、Go by Example 中文版: 协程

看过上面任意一个链接,我们可以了解到下面内容。协程(goroutine) 是轻量级的执行线程。通道(channels) 是连接多个协程的管道。你可以从一个协程将值发送到通道,然后在另一个协程中接收。默认情况下,通道是 无缓冲 的,这意味着只有对应的接收(<- chan) 通道准备好接收时,才允许进行发送(chan <-)。 有缓冲通道 允许在没有对应接收者的情况下,缓存一定数量的值。我们可以使用通道来同步协程之间的执行状态。Go 的 选择器(select) 让你可以同时等待多个通道操作。 将协程、通道和选择器结合,是 Go 的一个强大特性…

上面是协程和通道的基本概念,更多的可以阅读下面链接:

Go语言协程使用最佳实践: 处理协程崩溃;除了使用channel进行协程控制,sync.WaitGroup也可用来协程的通过(sync本身和协程关系不大?)。

Go编程时光-4.9 学习 Go 协程:巧妙利用 Context:协程的退出。

看到协程的使用,直觉上来说,它可能是一个用户线程。进程是不同线程之间共享资源的集合;线程是内核调度的单位。假设一个线程的时间片没有用完,但是又被一个读取调用阻塞。如果此时这个内核线程中有多个用户线程,则可以在用户层进行切换,继续占用CPU进行运行。详细见:linux进程


项目管理

本文的示例代码,使用module进行管理。我在这个上面踩了些坑。项目管理的介绍,可以翻看下:第三章:项目管理。以本文的示例为例,简单顺下流程。

  • go mod init go-tcp-demo:初始化一个Modules。这时候,可以看到出现一个go.mod文件。它包含模块的引用路径,最低的go版本要求,依赖包。go-tcp-demo并充当模块中包导入路径的前缀的路径
  • 一个模块中包含多个包(package),但通常只有一个main package。main package中的main函数,是程序入口。
  • 但是,一个mod下也可以有多个main package,需要处于不同目录。
  • import导入的是一个路径,会导入该路径下所有的包。
  • 通常包名是所在目录的名称
  • 变量和函数使用驼峰命名法。如果变量或者函数需要被包外引用,变量的首字母需要大写
  • 如果需要同时修改多个存在依赖关系的mod,可以参考:Go 1.18工作区模式最佳实践

bufio包使用

上面代码中,给每个连接套一个用户层的缓冲区。因为,从io读取数据,可能是耗时/耗资源的操作。使用io用户层的缓冲区,可以提高效率。

但使用不当,可能也会带来一些问题。比如,上面代码中,当缓冲区存在超过128字节的时候,更多的内容被舍弃。

bufio本身的源码相对比较简单,可以阅读下。更多见:golang-bufio、Go语言使用buffer读取文件

buffer 是缓冲器的意思,Go语言要实现缓冲读取需要使用到 bufio 包。bufio 包本身包装了 io.Reader 和 io.Writer 对象,同时创建了另外的 Reader 和 Writer 对象,因此对于文本 I/O 来说,bufio 包提供了一定的便利性。


其他代码

这里是调用package server,创建一个tcp server。

package mainimport ("go-tcp-demo/server"
)func main() {s := server.TcpServer{Ip: "127.0.0.1", Port: 10000}s.Start()
}

这里是客户端的代码。

package mainimport ("bufio""fmt""net""os"
)func main() {conn, err := net.Dial("tcp", "127.0.0.1:10000")if err != nil {fmt.Println("Error dial", err)return}defer conn.Close()inputReader := bufio.NewReader(os.Stdin)for {input, isPrefix, err := inputReader.ReadLine()if isPrefix || err != nil {fmt.Println("The entered single line content is too long or there is an error", err)continue}_, err = conn.Write(input)if err != nil {fmt.Println("Error in conn write", err)continue}buf := [512]byte{}n, rerr := conn.Read(buf[:])if rerr != nil {fmt.Println("Error in conn read", err)continue}fmt.Println(string(buf[:n]))}
}

相关文章:

go入门实践二-tcp服务端

文章目录 前言接口与方法并发-协程项目管理bufio包使用其他代码 前言 上一篇&#xff0c;我们通过go语言的hello-world入门&#xff0c;搭建了go的编程环境&#xff0c;并对go语法有了简单的了解。本文实现一个go的tcp服务端。借用这个示例&#xff0c;展示接口、协程、bufio的…...

SprinMVC获取请求参数

SprinMVC获取请求参数 Spring MVC 提供的获取请求参数的方式 通过 HttpServletRequest 获取请求参数通过控制器方法的形参获取请求参数使用 RequestParam 注解获取请求参数通过实体类对象获取请求参数&#xff08;推荐&#xff09; 通过ServlstAPI获取 将HttpServletRequest…...

orangepi 4lts ubuntu安装RabbitMQ

4lts的emmc 系统安装选文件系统格式 ext4 需先安装erlang&#xff1a; sudo apt install erlang 安装RabbitMQ: sudo apt install rabbitmq-server - 添加用户以便远程访问&#xff1a; - 账号密码都是admin: sudo rabbitmqctl add_user admin admin -sudo rabbitmqct…...

SolidWorks 3D Interconnect介绍

目前市面上有的三维设计软件有很多&#xff0c;如UG、Pro/E、CATIA等&#xff0c;而且每个三维设计软件都会生成自己文件格式。由于产品设计的原因&#xff0c;我们避免不了的会需要去使用不同三维设计软件的文件&#xff0c;这对于工程师来说其实是一件比较麻烦的事。 为什么…...

MBG中update语句的区别

int updateByPrimaryKey(User record) thorws SQLException 按主键更新 int updateByPrimaryKeySelective(User record) thorws SQLException 按主键更新值不为null的字段 使用以上的方式更新数据时必须提供主键&#xff0c;MyBatis根据主键进行数据记录的更新。 int updateBy…...

论文阅读 - Few-shot Network Anomaly Detection via Cross-network Meta-learning

论文链接&#xff1a;https://arxiv.org/pdf/2102.11165.pdf 目录 摘要&#xff1a; 引言 问题定义 方法 Graph Deviation Networks Cross-network Meta-learning 摘要&#xff1a; 网络异常检测旨在找到与绝大多数行为显着不同的网络元素&#xff08;例如节点、边、子图…...

秋招算法备战第37天 | 738.单调递增的数字、968.监控二叉树、贪心算法总结

738. 单调递增的数字 - 力扣&#xff08;LeetCode&#xff09; 这个问题是关于找到一个小于或等于给定数字n的最大单调递增数字。 我们可以将数字n转换为字符数组&#xff0c;然后从左到右扫描&#xff0c;寻找第一个违反单调递增条件的位置。一旦找到这样的位置&#xff0c;…...

Windows server上用nginx部署vue3项目

Windows server上用nginx部署vue3项目 一、Node中node_modules文件夹及package.json文件的作用说明二、VUE3项目打包三、Windows Server上的Nginx部署 一、Node中node_modules文件夹及package.json文件的作用说明 node_modules是安装node后用来存放用包管理工具下载安装的包的…...

计算机视觉与图形学-神经渲染专题-pi-GAN and CIPS-3D

《pi-GAN: Periodic Implicit Generative Adversarial Networks for 3D-Aware Image Synthesis》 摘要 我们见证了3D感知图像合成的快速进展&#xff0c;利用了生成视觉模型和神经渲染的最新进展。然而&#xff0c;现有的方法在两方面存在不足&#xff1a;首先&#xff0c;它们…...

【FAQ】EasyGBS平台通道显示在线,视频无法播放并报错400的排查

EasyGBS是基于国标GB28181协议的视频云服务平台&#xff0c;它可以支持国标协议的设备接入&#xff0c;在视频能力上能实现直播、录像存储、检索与回放、云台控制、告警上报、语音对讲、平台级联等功能&#xff0c;既能作为业务平台使用&#xff0c;也能作为能力层平台调用。 我…...

G1和CMS

G1垃圾回收器要点&#xff1a; 1.什么是G1垃圾回收器&#xff1a; G1是一款专门针对于拥有多核处理器和大内存的机器的收集器&#xff0c;在满足了GC响应时间的延迟可控的情况下&#xff0c;也会尽可能提高的程序的吞吐量 2.G1垃圾回收器的优点&#xff1a; ①与CMS收集器一…...

详解Linux中的socket函数

2023年8月3日&#xff0c;周四下午 目录 函数原型参数domain参数type参数protocol举例说明参数type和参数protocol之间的关系 函数原型 #include <sys/socket.h>int socket(int domain, int type, int protocol);参数domain domain是“域”的意思&#xff0c;其值为AF…...

React Antd 实现表格合计功能

思路&#xff1a;首先拿到 表格数组对象&#xff0c;然后写一个工具类&#xff0c;然后向数组对象最后插入一条数据&#xff0c;这条数据的字段时根据表格数组里合计算出来的。 代码如下&#xff0c;需根据各自业务稍作改动&#xff1a; <Table dataSource{tableData}column…...

尝试一下Guava带返回值的多线程处理类ListenableFuture

文章目录 ListenableFuture&#xff0c;带返回值的Guava多线程处理工具类举个例子扩展阅读 最近在学习&#xff0c;Java实现异步编程的8种方式这篇博客的时候&#xff0c;没有找到比较好的一个学习demo&#xff0c;故在此整理一下。 ListenableFuture&#xff0c;带返回值的Gua…...

微信小程序真机调试报ERR_CERT_AUTHORITY_INVALID

微信小程序真机调试报ERR_CERT_AUTHORITY_INVALID 问题解决方法 问题 微信开发者工具中调试微信小程序&#xff0c;在开发工具里面调试没问题&#xff0c;但是真机调试的时候报ERR_CERT_AUTHORITY_INVALID错误 解决方法 到这个站点检查域名的Https证书的安全性 : 传送门(注:…...

JCommander + AutoService打造带子命令的Java命令行应用

文章目录 需求Java命令行工具库依赖库定义各个子命令主类CLI测试一下参考文档 需求 最近想将自己的一个Java应用包装成命令行工具&#xff0c;看了几个库&#xff0c;最后选取了JCommander&#xff0c;结合AutoService库&#xff0c;实现了带子命令的工具&#xff0c;方便扩展…...

pycharm运行pytest无法实时输出信息

需要去掉控制台输出。根据查询相关信息显示pycharm运行pytest无法实时输出信息&#xff0c;需要去掉pycharm里面的运行模式&#xff0c;点击减号&#xff0c;再点击加号&#xff0c;添加python执行文件即可实时输出信息。 问题描述&#xff1a; 使用pycharm运行代码时&#x…...

Mac 卸载 IntelliJ IDEA 方法

Mac 系统下 IDEA 没有一键卸载程序&#xff0c;也没有完全卸载的插件&#xff0c;若要彻底删除&#xff0c;除了在应用&#xff08;Application&#xff09;里删除 IDEA 到垃圾桶外&#xff0c;还需要在终端&#xff08;Terminal&#xff09;执行删除相应的文件及文件夹。 1 分…...

数据安全能力框架模型-详细解读(三)

数据安全能力框架内涵 “奇安信数据安全能力框架”体现了数据安全治理从组织机构安全治理&#xff0c;到数字化环境具体管控、分析能力分层逐步落实的工程方法。 它以企业数据安全的战略目标和风险容忍度为输入&#xff0c;明确数据安全治理的组织&#xff1b;以合规与治理需…...

vscode启动leiningen项目

要在 VS Code 中启动 Leiningen 项目&#xff0c;你可以按照以下步骤进行操作&#xff1a; 确保已经安装了 Leiningen。你可以在终端中输入 lein version 来检查是否已成功安装。 在 VS Code 中安装 Leiningen 扩展。打开 VS Code&#xff0c;点击左侧的扩展图标&#xff08;四…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...