Go 语言 break 语句

Python022

Go 语言 break 语句,第1张

Go 语言中 break 语句用于以下三方面:

break 语法格式如下:

break 语句流程图如下:

在变量 a 大于 15 的时候跳出循环:

以上实例执行结果为:

以下实例有多重循环,演示了使用标记和不使用标记的区别:

以上实例的执行结果为:

break re 这句说明了一次性跳出到re标记,而不是只跳出当前局部循环.

channel一个类型管道,通过它可以在goroutine之间发送和接收消息。它是Golang在语言层面提供的goroutine间的通信方式。Go依赖于成为CSP的并发模型,通过Channel实现这种同步模式。Golang并发的核心哲学是不要通过共享内存进行通信。

下面Go通过channel来实现通信例子:

终端显示结果:

上面的例子只输出goRoutineA信息,没有执行goRoutineB说明channel仅允许被一个goroutine读写。

下面通过源码程序执行过程分析,如果对go并发和调度相关知识不了解,可以 预览这里

首先我们看下通道的结构hchan,源码再src/runtime/chan.go下

创建两种channel类型,一个带缓冲区和一个不带缓冲区的channel

创建通道后的缓冲通道结构

源码在$GOPATH/src/runtime/chan.go下:

创建一个带有buffer的channel,底层的数据结构模型如图:

向channel中写入数据

底层hchan数据流程下如图:

发送操作步骤:

执行流程图如下:

从channel中读取数据操作几乎和写入操作雷同

底层hchan数据流转如下图:

读数据操作如下:

大概流程如下:

recvq和sendq基本上是链表,基本如下:

select 就是用来监听和channel有关的IO操作,当前IO操作发生触发相关动作执行

如下例子:

多次执行后的结果如下:

select 语句会阻塞,知道监测到一个可执行的IO操作为止,goRoutineD和goRoutineE睡眠时间相同,都是3s,从输出可以看出,从channel中读取数据顺序是随机的。

可以持续冲channel中读取数据,一直到channel被关闭,当channel中没有数据是会阻塞当前goroutine,这里阻塞和读channel时阻塞处理机制一样。

例子如下:

运行结果如下:

死锁是指两个或者两个以上的协程在执行任务过程中,由于竞争资源或者彼此通信而造成的一种阻塞现象。在非缓冲信道如发生只流入不流出或者只流入出不流入就会发生死锁

死锁例子如下:

向非缓冲区通道读取数据会发生阻塞导致死锁,解决办法开启缓冲区,先向channel中写入数据

写入数据超过缓冲区数量也会发生死锁,解决办法将写入数据取走

向关闭的channel写入数据。解决办法别向关闭的channel写入数据。

可以参考更多死锁例子:

三次握手:

            1. 主动发起连接请求端(客户端),发送 SYN 标志位,携带数据包、包号

            2. 被动接收连接请求端(服务器),接收 SYN,回复 ACK,携带应答序列号。同时,发送SYN标志位,携带数据包、包号

            3. 主动发起连接请求端(客户端),接收SYN 标志位,回复 ACK。

                        被动端(服务器)接收 ACK —— 标志着 三次握手建立完成( Accept()/Dial() 返回 )

四次挥手:

            1. 主动请求断开连接端(客户端), 发送 FIN标志,携带数据包

            2. 被动接受断开连接端(服务器), 发送 ACK标志,携带应答序列号。 —— 半关闭完成。

            3. 被动接受断开连接端(服务器), 发送 FIN标志,携带数据包

            4. 主动请求断开连接端(客户端), 发送 最后一个 ACK标志,携带应答序列号。—— 发送完成,客户端不会直接退出,等 2MSL时长。

                        等 2MSL待目的:确保服务器 收到最后一个ACK

滑动窗口:

            通知对端本地存储数据的 缓冲区容量。—— write 函数在对端 缓冲区满时,有可能阻塞。

TCP状态转换:

            1. 主动发起连接请求端:

                        CLOSED ——>发送SYN ——>SYN_SENT(了解) ——>接收ACK、SYN,回发 ACK ——>ESTABLISHED (数据通信)

            2. 主动关闭连接请求端:

                        ESTABLISHED ——>发送FIN ——>FIN_WAIT_1 ——>接收ACK ——>FIN_WAIT_2 (半关闭、主动端)

                        ——>接收FIN、回复ACK ——>TIME_WAIT (主动端) ——>等 2MSL 时长 ——>CLOSED

            3. 被动建立连接请求端:

                        CLOSED ——>LISTEN ——>接收SYN、发送ACK、SYN ——>SYN_RCVD ——>接收 ACK ——>ESTABLISHED (数据通信)

            4. 被动断开连接请求端:

                        ESTABLISHED ——>接收 FIN、发送 ACK ——>CLOSE_WAIT ——>发送 FIN ——>LAST_ACK ——>接收ACK ——>CLOSED

windows下查看TCP状态转换:

            netstat -an | findstr  端口号

Linux下查看TCP状态转换:

            netstat -an | grep  端口号

TCP和UDP对比: 

            TCP: 面向连接的可靠的数据包传递。 针对不稳定的 网络层,完全弥补。ACK

            UDP:无连接不可靠的报文传输。 针对不稳定的 网络层,完全不弥补。还原网络真实状态。

                                    优点                                                            缺点

            TCP: 可靠、顺序、稳定                                      系统资源消耗大,程序实现繁复、速度慢

            UDP:系统资源消耗小,程序实现简单、速度快                          不可靠、无序、不稳定

使用场景:

            TCP:大文件、可靠数据传输。 对数据的 稳定性、准确性、一致性要求较高的场合。

            UDP:应用于对数据时效性要求较高的场合。 网络直播、电话会议、视频直播、网络游戏。

UDP-CS-Server实现流程:

            1.  创建 udp地址结构 ResolveUDPAddr(“协议”, “IP:port”) ——>udpAddr 本质 struct{IP、port}

            2.  创建用于 数据通信的 socket ListenUDP(“协议”, udpAddr ) ——>udpConn (socket)

            3.  从客户端读取数据,获取对端的地址 udpConn.ReadFromUDP() ——>返回:n,clientAddr, err

            4.  发送数据包给 客户端 udpConn.WriteToUDP("数据", clientAddr)

UDP-CS-Client实现流程:

            1.  创建用于通信的 socket。 net.Dial("udp", "服务器IP:port") ——>udpConn (socket)

            2.  以后流程参见 TCP客户端实现源码。

UDPserver默认就支持并发!

------------------------------------

命令行参数: 在main函数启动时,向整个程序传参。 【重点】

            语法: go run xxx.go   argv1 argv2  argv3  argv4 。。。

                        xxx.exe:  第 0 个参数。

                        argv1 :第 1 个参数。

                        argv2 :第 2 个参数。

                        argv3 :第 3 个参数。

                        argv4 :第 4 个参数。

            使用: list := os.Args  提取所有命令行参数。

获取文件属性函数:

            os.stat(文件访问绝对路径) ——>fileInfo 接口

            fileInfo 包含 两个接口。

                        Name() 获取文件名。 不带访问路径

                        Size() 获取文件大小。

网络文件传输 —— 发送端(客户端)

            1.  获取命令行参数,得到文件名(带路径)filePath list := os.Args

            2.  使用 os.stat() 获取 文件名(不带路径)fileName

            3.  创建 用于数据传输的 socket  net.Dial("tcp", “服务器IP+port”) —— conn

            4.  发送文件名(不带路径)  给接收端, conn.write()

            5.  读取 接收端回发“ok”,判断无误。封装函数 sendFile(filePath, conn) 发送文件内容

            6.  实现 sendFile(filePath,  conn)

                        1) 只读打开文件 os.Open(filePath)

                                    for {

                                    2) 从文件中读数据  f.Read(buf)

                                    3) 将读到的数据写到socket中  conn.write(buf[:n])

                                    4)判断读取文件的 结尾。 io.EOF. 跳出循环

                                    }

网络文件传输 —— 接收端(服务器)

            1. 创建用于监听的 socket net.Listen() —— listener

            2. 借助listener 创建用于 通信的 socket listener.Accpet()  —— conn

            3. 读取 conn.read() 发送端的 文件名, 保存至本地。

            4. 回发 “ok”应答 发送端。

            5. 封装函数,接收文件内容 recvFile(文件路径)

                        1) f = os.Create(带有路径的文件名)

                        for {

                        2)从 socket中读取发送端发送的 文件内容 。 conn.read(buf)

                        3)  将读到的数据 保存至本地文件 f.Write(buf[:n])

                        4)  判断 读取conn 结束, 代表文件传输完成。 n == 0  break

                        }