go语言学习笔记3.19-3.23

并发编程

并发包含以下几种主流的实现模型

多进程,多进程是在操作系统层面进行并发的基本模式

多线程,多线程在大部分操作系统上都属于系统层面的并发模式

基于回调的非阻塞/异步IO,使用多线程模式会很快耗尽服务器的内存和CPU资源

协程,协程本质上是一种用户态线程,不需要操作系统来进行抢占式调度,且在真正的实现中寄存于线程中

Channel

声明

var channamechan elementtype

例 var  ch chan int

   var m map[string] chan bool  map中的元素是bool类型的chan

定义

Ch :=make(chanint)

将一个数据写入到channel

Ch<-value

从channel读取数据

Value :=<-ch

单向channel声明:

Var ch1chan int  ch1是一个正常的channel不是单向的

Var ch2chan <-float64 ch2是单向channel,只用于写float64的值

Var ch3<-chan int ch3是单向channel,只用于读int类型、

关闭channel: close(ch)

如何判断channel被关闭

X,ok:=<-ch 第二个值为false,则关闭

网络编程

无论我们期望使用什么类型的协议建立什么形式的链接,都只需调用net.Dail即可

Tcp

Conn,err:=net.Dail(“tcp”,”192.168.1.1:10086”)

Udp

Conn,err:=net.Dail(“udp”,”127.0.0.1:8080”)

ICMP

Conn,err:=net.Dial(“”ip4 :1”,1001.10.4.1;456””)

 

net.ResolveTCPAddr()用于解析地址和端口号

net.DialTcp()用于建立链接

HTTP 编程

http.Get()

要请求一个资源,只需调用http.Get()方法,示例代码如下:

Resp,err:=http.Get(“http://example.com/”)

Iferr!=nil{

       //处理错误

       return

}

deferresp.Body.close()

io.copy(os.stdout,resp.Body)

http函数,只需调用http.Post()方法依次传递下面的格式选要传递

http.PostForm()

posyfrom方法实现了标准编码格式、

http.Head

http中的head请求方式表明请求目标的URL信息

HTTP客户端

net/http包的client类型提供了如下几个方法,让我们可以用最简洁的方式实现HTTP请求

http.Get(),要请求一个资源,只需调用http.Get()方法

http.Get(“http://example.com/”)

http.Post(),要以POST方式发送数据,也很简单,只需要调用http.Post()方法并依次传递下面几个参数即可:

请求的目标URL

将要POST数据的资源类型(MIMEType)

数据的比特流([]byte流式)

http.Post(http://example.com/upload,”image/jpeg”,&imageDataBuf)

http.PostForm(),实现了标准编码格式为application/x-www-form-urlencoded的表单提交。

http.PostForm(http://example.com/posts,url.Value{“title”:{“article title”},”content”:{“article body”}})
http.Head() 只返回HTTPhead不返回HTTP body

http.Head(“http://example.com/”)

网络通信net包

Net包对于I/O提供了便携式接口,包括TCP/IP/UDP,域名解析以及Unix Socket.尽管net包提供了大量访问底层的接口,但是大多数情况下,客户端仅仅只需要最基本的接口,例如Dail .Listen,Accepte以及分配的conn连接和listener接口。crypto/tls包使用相同的接口以及类似的Dail和listen函数。

funcInterfaceAddrs() 返回该系统的网络接口的地址列表

funcInterface() 返回该系统的网络接口列表

funcJoinHostPost() 将host和post合并为一个网络地址。一般格式为“host:post“;如果host含有冒号或百分号,格式为”[host]:port“

funcLookupCHAME(name string) 返回给定名字规范的DNS主机名称,如果调用者不关心name是否规范,可以直接调用LookupHost或者LookupIP,这两个函数都会在查询时考虑到name的规范性

funcLookupHost(hoststring) 通过利用本地解析器查找host进行查找,返回主机地址的数组

func LookupIP(hoststring) 通过利用本地解析器查找host,返回主机ipv4和ipv6地址的一个数组

测试代码

packagemain

import (

"fmt"

"net"

)

funcmain(){

 

       Addr ,_ :=net.InterfaceAddrs()

       fmt.Println(Addr)

       interfaces,_ :=net.Interfaces()

       fmt.Println(interfaces)

       hp :=net.JoinHostPort("127.0.0.1","8080")

       fmt.Println(hp)

       la ,_:=net.LookupAddr("127.0.0.1")

       fmt.Println(la)

       cname,_:=net.LookupCNAME("www.baidu.com")

       fmt.Println(cname)

       host,_:=net.LookupHost("www.baidu.com")

       fmt.Println(host)

       ip,_:=net.LookupIP("www.baidu.com")

       fmt.Println(ip)

}

得出结果

[127.0.0.1/8192.168.247.128/24 ::1/128 fe80::20c:29ff:fe6d:c1c/64]

[{116436 lo  up|loopback} {2 1500 eth000:0c:29:6d:0c:1c up|broadcast|multicast}]

127.0.0.1:8080

[localhostlocalhost.localdomain. localhost4 localhost4.localdomain4.]

www.a.shifen.com.

[14.215.177.3814.215.177.39]

[14.215.177.3914.215.177.38]

 

net 包中存在的error

func (e*AddrError) Error() string 错误

func (e*AddrError) Temporary() bool 该错误是否是一个临时错误

func (e*AddrError) Timeout()  bool  该错误是否是超时错误

 

typeAddr 网络终端地址

typeAddr interface{

       Network() string //网络名称

       String() string //地址字符串表示

}

TypeConn //conn是一个通用的面向流的网络连接,多个goroutine可以调用conn中的方法

 

 

typeConn interface{

       Read(b []byte)(n int,err error)

Read 从连接中读取数据,read的方法会在超过某个固定时间限制后返回一个表示超时的错误,该错误的Timeout()==True

Write (b[]byte)(n int,err error)

Write  从连接中读取数据,write的方法也会在超过某个固定时间限制后返回一个表示超时的错误,该错误的Timeout()==True

Close()error

Close方法关闭该连接,同时任何阻塞的read或write方法将不再阻塞,并返回错误

 

LocalAddr() Addr

返回本机网络地址

RemoteAddr() Addr

返回远端网络地址

}

Dial()函数

funcDial(net,addr  string) (Conn,error)

其中net是网络协议的名字,addr参数是IP地址或域名,而端口号以”:”的形式随在地址或域名的后面,端口号可选。如果连接成功,返回连接对象,否则返回error

Tcp 连接

conn,err :=net.Dial(“tcp”,”192.168.0.125:1231”)

udp 连接

conn,err :=net.Dial(“udp”,”192.168.0.125:1231”)

ICMP链接(使用协议名称)

conn,err :=net.Dial(“ip4:icmp”,”www.baidu.com”)

ICMP链接(使用协议编号)

conn,err :=net.Dial(“ip4:1”,”10.0.0.3”)

在成功建立连接后,我们就可以进行数据的发送和接收。发送数据时,使用conn的Write()成员方法,接收数据时使用Read()方法

Typeinterface interface表示一个在网络接口名和索引之间的映射,它也包含网络接口设备信息

 

funcInterfaceByIndex(index int) (*Interface, error)    //通过指定的索引index返回相应的接口

funcInterfaceByName(name string) (*Interface, error) //通过指定的名字Name返回相应的接口

func(ifi *Interface) Addrs() ([]Addr, error)          //返回指定接口的address

func(ifi *Interface) MulticastAddrs() ([]Addr, error)   //MulticastAddrs返回网络接口ifi加入的多播组地址。

typeListener //Listern是一个用于面向流的网络协议的公用的网络监听器接口。多个线程可能会同时调用一个Listern的方法

typeListener interface{

       Accept() (c Conn,err error) //等待并返回下一个连接到该连接的连接

       Close() error //关闭listerner ,关闭后,任何阻塞accept的操作都不在阻塞,并且返回error

       Addr() Addr //返回该接口的网络地址

}

funcListen(net, laddr string) (Listener, error)  //返回在一个本地网络地址laddr上监听的Listener。网络类型参数net必须是面向流的网络:"tcp"、"tcp4"、"tcp6"、"unix"或"unixpacket"。具体参见Dial函数获取laddr的语法。

 

JSON处理

Go语言内建对JSON的支持。使用Go语言内置的encoding/json标准库,开发者可以轻松使用Go语言生成和解析JSON格式的数据

使用json.Marshal()函数可以对一组数据进行JSON格式的编码。

例如有如下的一个book实例

Type Bookstruct{

       Title string

       Author []string

       Publisher string

       IsPublished bool

       Price float

}

Gobook:=Book{

       “go语言编程”,

       [“aaaa”,”ccc”],

       “www.baidu.com”,

       true,

9.99

}

可以使用json.Marshal()函数将gobook实例生成一段json格式的文本

b,err:=json.Marshal(gobook)

b==[]byte(`{      

       “Title”:“go语言编程”,

       “Author”:[“aaaa”,”ccc”],

       “Publisher”:“www.baidu.com”,

       “Ispublished”:true,

“Price”:9.99

 

}`)

解码JSON数据

可以使用json.Unmarshal()函数将JSON格式的文本解码为Go预期的数据结构

var bookBook

err :=json.Unmarshal(b,&book)

 

解码后

book:=Book{

       “go语言编程”,

       [“aaaa”,”ccc”],

       “www.baidu.com”,

       true,

9.99

}

简单的网站程序

packagemain

 

import(

    "io"

    "log"

    "net/http"

)

 

funchelloHandler(whttp.ResponseWriter,r*http.Request){

    io.WriteString(w,"hello,world!")

}

funcmain(){

    http.HandleFunc("/hello",helloHandler)

    err:=http.ListenAndServe(":8080",nil)

    iferr!=nil{

        log.Fatal("ListenAndServe:",err.Error())

    }

}

工程管理

Go 命令行工具

常用的功能:

goversion查看go的版本

go buildx.go 创建x的可执行文件

go fmtx.go 对x.go进行格式调整(调整成标准格式)

go runx.go直接执行x.go

 

 

进阶

反射:

基本概念:对所有接口进行反射,都可以得到一个包含Type和value的信息结构,type主要表达的是被反射的这个变量本身的类型信息,而value则为该变量实例本身的信息。

基本用法:

packagemain

 

import (

       "fmt"

       "reflect"

)

 

funcmain() {

       var x float64 = 3.4

       fmt.Println("type:",reflect.TypeOf(x))

       v :=reflect.ValueOf(x)

       fmt.Println("type:",v.Type())

       fmt.Println("kind isfloat64:",v.Kind()==reflect.Float64)

       fmt.Println("value",v.Float())

       p :=reflect.ValueOf(&x)

       fmt.Println("type ofp:",p.Type())

       fmt.Println("settability ofp:",p.CanSet())

       w :=p.Elem()

       fmt.Println("settability ofw:",w.CanSet())

       w.SetFloat(7.1)

       fmt.Println(w.Interface())

       fmt.Println(x)

      

 

}

打印出

type:float64

type: float64

kind isfloat64: true

value3.4

type ofp: *float64

settabilityof p: false

settabilityof w: true

7.1

7.1

 

语言交互性

Go 提供了与C语言进行交互的功能,称之为Cgo

package main

import"fmt"

//#include<stdio.h>

//#include<stdlib.h>

import"C"

func Random() int{

 

       returnint(C.random())

}

func Seed(i int){

 

       C.srandom(C.uint(i))

}

func main(){

 

       Seed(100)

       fmt.Println("Random",Random())

}

事实上根本就不存一个名为C的包,这个import事实上只是一个信号,告诉Cgo需要工作了,然后对应这个import前面注释的C源代码自动生成包装性质的Go代码。上面的注释可以为块注释也可以是行注释。

对于C语言的原生类型,Cgo都会将其映射为go语言中的类型,C语言中的void* 指针类型在go语言中则用特殊的unsafe.Pointer类型来应对(但是需要导入import“unsafe”包)。

字符串的映射

Cgo提供了一系列函数来提供支持:C.CStringC.GoString和C.GoStringN,为防止使用完未释放C.Cstring所产生的垃圾进而导致的内存泄露,需要使用defer语句

 

C程序

其实在import“C”的前面的注释块中,可以写任意的C程序,Cgo都会将其处理为合法的go代码

例如:

package main

 

/*

#include<stdio.h>

Int add(int x,int y){

       returnx+y;

}

*/

Import “C”

Import “fmt”

func main(){

       fmt.Println(C.add(3,4))

}

输出结果为7

 

如果这里的C代码需要以来第三方库,Cgo提供了#cgo 这样的伪C文法,让开发者有机会指定依赖的第三方库和编译选项

第一种写法:

//#cgo CFLAGS :-DPNG_DEBUG=1

//#cgo linux CFLAGS :-DLINUX=1

//#cgo LDFLAGS :lpng

//#include<png.h>

Import “C”

使用CFLAGS来传入编译选项,使用LDFLAGS来传入连接选项。

第二种写法:

/#cgo pkg-config: png cairo

//#include<png.h>

Import “C”

groutine机理

协程:轻量级线程

1.    能够在单一的系统线程中模拟多个任务的并发执行

2.    在一个特定的时间内,只有一个任务在执行,即并非真正的并发

3.    被动的任务调动方式,即任务没有主动抢占时间片的说法。当一个任务正在执行时,外部没有办法终止它。要进行任务切换,只能通过由该任务自身调用field()来主动让出CPU使用权

4.    每个协程都有自己的堆栈和局部变量

每个协程都包含三种状态:挂起,运行和停止停止通常表示该协程已经执行完成,挂起表示该协程尚未完成,但是让出了时间片

 

Blog:

学习笔记总3.19-3.23https://blog.csdn.net/shangguan_1234/article/details/79671079

学习笔记并发https://blog.csdn.net/shangguan_1234/article/details/79638930

学习笔记网络编程https://blog.csdn.net/shangguan_1234/article/details/79639040

实现多人聊天室https://blog.csdn.net/shangguan_1234/article/details/79640856

实现一个简单的网络爬虫https://blog.csdn.net/shangguan_1234/article/details/79667651

 

 

3.24计划,修改多人聊天室存在的一些小bug,尝试修改爬虫能做下载图片功能,继续联系常用包中函数的调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值