Golang——TCP、UDP实现并发(服务端与客户端)

Server端常用函数、接口:

Listen函数:func Listen(network, address string) (Listener, error)network:选用的协议:TCP、UDP, 	如:“tcp”或 “udp”address:IP地址+端口号, 			如:“127.0.0.1:8000”或 “:8000”Listener 接口:
type Listener interface {Accept() (Conn, error)Close() errorAddr() Addr
}Conn 接口:
type Conn interface {Read(b []byte) (n int, err error)Write(b []byte) (n int, err error)Close() errorLocalAddr() AddrRemoteAddr() AddrSetDeadline(t time.Time) errorSetReadDeadline(t time.Time) errorSetWriteDeadline(t time.Time) error
}

TCP-服务端实现:

func main() {// 指定服务器的通讯协议、ip、端口,Listen本身不做监听,这一步是创建了一个用于监听的Socketlisten, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出错:", err)return}defer listen.Close()fmt.Println("服务器启动完毕,等待客户端连接")// 阻塞监听客户端连接请求,成功建立连接后会返回用于通信的Socketaccept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出错:", err)return}defer accept.Close()fmt.Println("服务器与客户端连接成功")// 读取客户端发动的请求buf := make([]byte, 4096)read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("服务器获取到:", string(buf[:read]))
}

Mac可以通过netcat进行测试:

在这里插入图片描述

TCP-客户端实现:

func main() {// 指定用户端的通讯协议、ip、端口,Listen本身不做监听,这一步是创建了一个用于监听的Socketdial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出错:", err)return}defer dial.Close()// 发送数据dial.Write([]byte("我是客户端"))// 接收服务器返回的数据buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("客户端获取到:", string(buf[:read]))
}

TCP实现并发-服务器:

上面都是单机版的客户端通信,如果想要实现并发,需要使用Goroutine+循环实现

  • 循环读取客户端发送的数据
  • 如果客户端强制关闭连接需要做处理
  • 客户端发送exit时

演示:

package mainimport ("fmt""net""strings"
)func main() {// 创建监听套接字listen, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出错:", err)return}defer listen.Close()// 创建客户端连接请求fmt.Println("服务器启动成功,等待客户端连接!")for {accept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出错:", err)return}// 调用服务器和客户端通信的函数go HandlerConnect(accept)}
}func HandlerConnect(accept net.Conn) {defer accept.Close()// 获取客户端发送的数据// 获取连接客户端的网络地址addr := accept.RemoteAddr()fmt.Println(addr, "客户端连接成功!")buf := make([]byte, 4096)for {read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}fmt.Println("服务器读到数据:", string(buf[:read]))// 模拟服务器收到数据后,回发给客户端,小写转大写data := strings.ToUpper(string(buf[:read]))accept.Write([]byte(data))}
}

在这里插入图片描述

TCP实现并发-客户端:

演示:

package mainimport ("fmt""net""os"
)func main() {//主动发送连接请求dial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("et.Dial出错了", err)return}defer dial.Close()// os.Stdin():获取用户键盘录入,go func() {str := make([]byte, 4096)for {read, err := os.Stdin.Read(str)if err != nil {fmt.Println("os.Stdin.Read出错了", err)continue}// 读到的数据写给服务器,读多少写多少dial.Write(str[:read])}}()buf := make([]byte, 4096)// 回显服务器发送的数据,转成大写for {read, err := dial.Read(buf)// read=0的说明对端关闭连接,如果关闭连接这里就不需要往下读数据了if read == 0 {fmt.Println("检测到服务端端已经断开连接!")return}if err != nil {fmt.Println("回显服务器发送的数据dial.Read出错了", err)return}fmt.Println("客户端读到服务器的回显数据", string(buf[:read]))}
}

在这里插入图片描述

UDP实现并发-服务器:

由于UDP是“无连接”的,所以,服务器端不需要额外创建监听套接字,只需要指定好IP和port,然后监听该地址,等待客户端与之建立连接,即可通信。

创建监听地址:

	func ResolveUDPAddr(network, address string) (*UDPAddr, error) 

创建监听连接:

	func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) 

接收udp数据:

	func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error)

写出数据到udp:

	func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

演示:

package mainimport ("fmt""net"
)func main() {// 指定服务器的ip和端口,和TCP协议不一样,需要先写好再传给ListenUDP使用ServerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.ResolveUDPAddr err:", err)return}fmt.Println("服务器启动成功!")// 创建用户通信的SocketudpConnect, err := net.ListenUDP("udp", ServerAddr)if err != nil {fmt.Println("net.ListenUDP err:", err)return}defer udpConnect.Close()fmt.Println("服务器创建Socket成功!")// 读写客户端的数据buf := make([]byte, 4096)count := 0for {// 返回值:n int(读到的字节数), addr *UDPAddr(客户端的地址), err errorudpBytes, ConnectAddr, err := udpConnect.ReadFromUDP(buf)if err != nil {fmt.Println("udpConnect.ReadFromUDP err:", err)return}count++// 模拟处理数据fmt.Printf("服务器读到第%v条数据 %v :%s\n", count, ConnectAddr, string(buf[:udpBytes]))go func() {// 回写数据到客户端udpConnect.WriteToUDP([]byte("回写数据到客户端\n"), ConnectAddr)}()}
}

UDP实现并发-客户端:

package mainimport ("fmt""net""time"
)func main() {dial, err := net.Dial("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出错:", err)return}defer dial.Close()for {// 发送数据dial.Write([]byte("我是客户端"))// 接收服务器返回的数据buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("客户端获取到:", string(buf[:read]))time.Sleep(time.Second)}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中 将字符串时间 '2015-9-8 17:05:06' 转化为格式 '2015-09-08 17:05:06'

/** * 将字符串时间2015-9-8 17:05:06转化为格式2015-09-08 17:05:06 */import java.text.SimpleDateFormat; public class TestDate{ public static void main(String[] args) throws Exception{ String time "2015-9-8 17:05:06";//注意:时分秒必须都…

详解TCP协议三次握手四次挥手

三次握手: 三次握手表示建立通信阶段,在TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠,由于这种面向连接的特性, TCP协议可以保证传输数据的安全,…

Golang——实现文件传输

借助TCP完成文件的传输,基本思路如下: 发送方(客户端)向服务端发送文件名,服务端保存该文件名。接收方(服务端)向客户端返回一个消息ok,确认文件名保存成功。发送方(客户…

Golang——HTTP编程请求和响应实现

请求: HTTP 请求报文由请求行、请求头部、空行、请求包体4个部分组成,如下图所示: 请求行: 请求行由方法字段、URL 字段 和HTTP 协议版本字段 3个部分组成,他们之间使用空格隔开。常用的 HTTP 请求方法有 GET、POST。…

zabbix v3.0安装部署【转】

关于zabbix及相关服务软件版本: Linux:oracle linux 6.5 nginx:1.9.15 MySQL:5.5.49 PHP:5.5.35 一、安装nginx: 安装依赖包: yum -y install gcc gcc-c autoconf automake zlib zlib-devel ope…

WeChatTweak-微信小助手安装教程

github下载:https://github.com/Sunnyyoung/WeChatTweak-macOS CSDN下载:https://download.csdn.net/download/weixin_45477086/83895866 双击解压下载的WeChatTweak-macOS-***.zip在终端输入cd ,并敲一个空格,然后把解压的文件夹拖到终端 …

nodejs开发工具

我选择的是Hbuilder作为node项目的开发工具。先在Hbuilder 里面安装nodeEclipse插件,然后重启工具。点击添加项目,选择其他选项,出现下图选项,然后选择圈住的选项点击下一步:3. 如果不使用缺省位置,那么你的路径一定要…

排序之外部排序

有时,待排序的文件很大,计算机内存不能容纳整个文件,这时候对文件就不能使用内部排序了(这里做一下说明,其实所有的排序都是在内存中做的,这里说的内部排序是指待排序的内容在内存中就可以完成,…

Golang——Json的序列化和反序列化

JSON: JSON(JavaScript Object Notation):是一种轻量级的数据交换格式。 它是基于 ECMAScript 规范的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写…

安装配置 flannel - 每天5分钟玩转 Docker 容器技术(59)

上一节我们部署了 etcd,本节安装和配置 flannel。 build flannel flannel 没有现成的执行文件可用,必须自己 build,最可靠的方法是在 Docker 容器中 build。不过用于做 build 的 docker 镜像托管在 gcr.io,国内可能无法直接访问&a…

人人都是产品经理?

产品经理顾名思义就是产品经理。那么只要搞懂产品是什么、经理又什么什么,就明白了产品经理是什么。 产品是什么: 产品是满足需求的载体,能被市场、人们使用和消费,并能满足人们某种需求(创造价值)的任何东…

搭建一个简单的FTP服务器

本文介绍通过win7自带的IIS来搭建一个只能实现基本功能的FTP服务器,第一次装好WIN7后我愣是没整出来,后来查了一下网上资料经过试验后搭建成功,其实原理和步骤与windows前期的版本差不多,主要是对新的操作系统还不是很熟悉。相信用…

3D文档(BRD、MRD、PRD)怎么写

3D文档: 一般来说,BRD作为战略方向的制定,是最早产出的文档,而MRD则是在战略方向的基础上对市场进行的分析,同时对后续工作的方向进行一些说明和指导,也可以说是通过对市场环境、竞品的分析,明确…

需求收集、分析、管理的方法

需求: 什么是需求 百度百科给的解释:指人们在某一特定的时期内在各种可能的价格下愿意并且能够购买某个具体商品的需要。所以要想明白需求,还要明白另外两个概念,需要和欲望,因为从需要到需求是一个由宏观到微观的过程…

if函数 字体自动标红_发喜糖!REPT函数和图表订婚了~~

小伙伴们早上好呀!今天为大家分享的是REPT函数的应用实例。案例1:基础用法左右:按照给定的次数重复显示文本用法:REPT(文本,重复次数)搭配:Wingdings字体家族的应用案例2:条形图⑴ 单元格D3输入…

用户体验五要素

用户体验: 用户在使用产品过程中建立起来的一种纯主观感受。 用户体验的重要性: 会失去客户:如果你没有良好的体验,用户不会使用你的产品,而且产品很难有二次机会接触用户。会增加获客成本:获客成本越来越高…

trackingmore快递查询平台_国际快递物流信息追踪查询

以下是快递公司常用查询物流信息追踪平台1. 17TRACK查询网址:www.17track.net/zh-cn (强烈推荐,国际件都能查询)2. EMS查询网址:www.ems.com.cn 客服电话:11833. DHL网址查询:www.cn.dhl.com …

竞品分析该怎么做

竞品分析: 作用: 知己知彼,百战不殆。为自身产品设计提供功能、可用性、关键技术等方面的参考。提高自身产品的差异化程度。为新立项的产品、拍脑袋想出来的,降低风险。 如何选择竞品: 行业内领先的产品,通…

饿了么超时20分钟_饿了么回应“多等5分钟”,网友气炸了

广告记编辑整理(ID:adgroup)昨天一篇题为《外卖骑手,困在系统里》的文章刷屏文章指出外卖骑手是被平台系统算法与数据支配的“工具人”在系统的压迫下骑手们每天都在违反交规、与死神赛跑外卖员成了高危职业引发网友热议今天凌晨饿了么官方发布了一篇《你…

java获取本周的开始时间和结束时间_创业板注册制开始时间/股票开户流程结束后,怎么炒股?...

股户流程刚走完,先别急着炒股,多研究股市行情。首选开户选好券商,没选好后患无穷,券商建议是富途、老虎,这两家美股港股都可以入,各有优势,富途的港股股票期权值得关注,老虎证券目前…