自学内容网 自学内容网

go并发编程以及socket通信的理解

go并发编程以及socket通信的理解

一、管道的简单使用

" golang不是通过共享内存来通信,而是通过通信来共享内存 "

1、go简单初始化

// golang不是通过共享内存来通信,而是通过通信来共享内存
func a1() {
// 声明初始化 channel
var ch chan string = make(chan string) // deadlock 会造成死锁,因为我们的管道是没有缓冲的
// 内置的make函数有什么作用?
// make 初始化内存,并且返回引用类型本身
// new 只是将内存清零,返回的是指向类型的指针
ch <- "hello" //阻塞写
str := <-ch   //阻塞读
fmt.Println(str)
// 单向channel
var ch1 chan<- string // 只能写
var ch2 <-chan string // 只能读
// 关闭channel
close(ch1)
x, ok := <-ch2
if ok {
fmt.Println(x)
} else {
fmt.Println("channel is closed")
}
}

2、用 select 做一个简单的超时管理

// Go语言直接引入select关键字,用于处理异步问题
var ch1, ch2 chan string
select {
case x := <-ch1: // 如果从ch1读取数据,那么执行此语句
fmt.Println(x)
case y := <-ch2: // 如果从ch2读取数据,那么执行此语句
fmt.Println(y)
default:
fmt.Println("default")
}

超时管理:

func download(ch chan string) {
for i := 1; i < 10; i++ {
fmt.Println(i)
time.Sleep(time.Second * 1)
}
ch <- "ok"
}
func a2() {
// 超时处理
timeout := make(chan int, 1)
go func() {
time.Sleep(time.Second * 3)
timeout <- 1 // 用来标记超时,可以是任何非0值
}()
ch := make(chan string, 6) // 用于从download中接受数据
go download(ch)
select {
case <-ch:
fmt.Println("从ch中读取数据,执行正常业务处理") // 如果从ch中读取到数据那么正常处理业务
case <-timeout:
fmt.Println("3秒内没有从ch中读取数据,执行超时处理")// 如果从timeout中读取到数据,那么download执行超时
}
}

3、编程体:通过go协程输出100个以内的任意两个数之和,减少等待。

func add(i, x, y int) {
fmt.Printf("%d + %d = %d\n", x, y, x+y)
}
func a3() {
for i := 1; i <= 100; i++ {
x := rand.Intn(100)
time.Sleep(time.Millisecond)
y := rand.Intn(100)
go add(i, x, y)
}
}

二、go中的socket实现通信

知识速记

// 共享数据机制-sync
func s1() {
// sync.Mutex
//mutex := sync.Mutex{}

}

// 上下文机制 - Context

// socket 原理
/*
互联网TCP/IP四层模型
四层:数据层(帧)、网络层(IP)、传输层(TCP/UDP)、应用层(HTTP)
通信:封包和解包
抽象:应用程序到应用程序、进程到进程、主机到主机、设备到设备

*/

1、代码示例clinet.go和server.go

clinet.go

package main
import (
"bufio"
"fmt"
"net"
"time"
)
func main() {
// 与服务端建立连接
conn, err := net.DialTimeout("tcp", "127.0.0.1:8899", time.Second)
if err != nil {
fmt.Printf("dial failed, err:%v\n", err)
return
}
defer conn.Close()
// 要发送的数据
msg := []string{"hello world!", "golang", "c++", "python"}
//  通过bufio方式发送
writer := bufio.NewWriter(conn)
for i, v := range msg {
n, err := writer.Write([]byte(v))
writer.Flush()
if err != nil {
fmt.Printf("write failed, err:%v\n", err)
return
}
fmt.Printf("%d: write %d,bytes, data:%s\n", i, n, v)
time.Sleep(time.Second)
}
}

server.go

// go 基于 socket 的 tcp 编程
func HandleConn(conn net.Conn) {
fmt.Println("accepted a new connection!")
defer conn.Close()
for {
// 负责缓存接受的数据
buf := make([]byte, 32)
n, err := conn.Read(buf) //表面上是 阻塞读
if err != nil {
fmt.Println("read err:", err)
break
}
if n == 0 {
continue
}
// 打印客户端发送的数据
fmt.Printf("recv client data: %s\n", string(buf[:n]))
// 发送数据给客户端
conn.Write([]byte("hello client"))
}
}
func main() {
// 开始监听 8899 端口
listen, err := net.Listen("tcp", ":8899")
if err != nil {
fmt.Println("listen err:", err)
return
}
// 循环接受连接
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept err:", err)
break
}
// 处理连接
go HandleConn(conn)
}
}

2、go基于 socket 的 tcp 编程详细解析


原文地址:https://blog.csdn.net/m0_73337964/article/details/137754596

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!