Go Socket

Golang之Socket

go创建socket很简单

package main

import (
    "fmt"
    "net"
)

func main() {
    //服务器监听地址
    fmt.Println("start server...")
    listen, err := net.Listen("tcp", "127.0.0.1:50000")
    if err != nil {
        fmt.Println("listen failed,err:", err)
        return
    }
    //接受客户端信息
    for {
        conn, err := listen.Accept()
        if err != nil {
            fmt.Println("accept failed,err:", err)
            continue
        }
        //用协程建立连接
        go process(conn)
    }
}

//读取数据
func process(conn net.Conn) {
    defer conn.Close()
    for {
        buf := make([]byte, 512)
        n, err := conn.Read(buf)
        if err != nil {
            fmt.Println("read err:", err)
            return
        }
        fmt.Printf(string(buf[0:n]))
    }
}
tcp_server.go

package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
)

func main() {
    conn, err := net.Dial("tcp", "localhost:50000")
    if err != nil {
        fmt.Println("Error dialing", err.Error())
        return
    }
    defer conn.Close()
    inputReader := bufio.NewReader(os.Stdin)
    for {
        input, _ := inputReader.ReadString('
')
        trimmedInput := strings.Trim(input, "
")
        if trimmedInput == "Q" {
            return
        }

        _, err = conn.Write([]byte(trimmedInput))
        if err != nil {
            return
        }
    }
}
tcp_cient

发送HTTP

package main

import (
    "fmt"
    "io"
    "net"
)

func main() {

    conn, err := net.Dial("tcp", "www.baidu.com:80")
    if err != nil {
        fmt.Println("Error dialing", err.Error())
        return
    }
    defer conn.Close()
    msg := "GET / HTTP/1.1
"
    msg += "Host:www.baidu.com
"
    msg += "Connection:keep-alive
"
    //msg += "User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
"
    msg += "

"

    //io.WriteString(os.Stdout, msg)
    n, err := io.WriteString(conn, msg)
    if err != nil {
        fmt.Println("write string failed, ", err)
        return
    }
    fmt.Println("send to baidu.com bytes:", n)
    buf := make([]byte, 4096)
    for {
        count, err := conn.Read(buf)
        fmt.Println("count:", count, "err:", err)
        if err != nil {
            break
        }
        fmt.Println(string(buf[0:count]))
    }
}
百度

Golang之并发篇

进程和线程

A。进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。

B。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

C。一个进程可以创建和撤销多个线程;同一进程中的多个线程之间可以并发执行。

并发和并行
并发:多线程程序在一个核的cpu上运行
并行:多线程程序在多个核的cpu上运行
举例。。一个妈给一个碗给多个小孩喂饭,,是并发
    一个妈给每个小孩一人一个碗,就是并行

并发                       并行

协程和线程
协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级协程,这些用户级线程的调度也是自己实现的。
线程:一个线程上可以跑多个协程,协程是轻量级的线程。

例子

package main

import (
    "fmt"
    "time"
)

func test() {
    var i int
    for {
        fmt.Println(i)
        time.Sleep(time.Second)
        i++
    }
}
func main() {
    go test() //起一个协程执行test()
    for {
        fmt.Println("i : runnging in main")
        time.Sleep(time.Second )
    }
}

-

--

设置Golang运行的cpu核数。

1.8版本以上,默认跑多个核

package main

import (
    "fmt"
    "runtime"
)

func main() {
    num := runtime.NumCPU()
    runtime.GOMAXPROCS(num)
    fmt.Println(num)
}

并发计算

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    m    = make(map[int]uint64)
    lock sync.Mutex
)

type task struct {
    n int
}

func calc(t *task) {
    var sum uint64
    sum = 1
    for i := 1; i < t.n; i++ {
        sum *= uint64(i)
    }
    fmt.Println(t.n, sum)
    lock.Lock()
    m[t.n] = sum
    lock.Unlock()

}

func main() {
    for i := 0; i < 16; i++ {
        t := &task{n: i}
        go calc(t)//并发执行,谁快谁先出 
    }
    time.Sleep(10 * time.Second)
    //lock.Lock()
    //for k, v := range m {
    //    fmt.Printf("%d!=%v
", k, v)
    //}
    //lock.Unlock()
}
并发计算

 Channel

channel概念
a。类似unix中的管道(pipe)
b.先进先出
c。线程安全,多个goroutine同时访问,不需要枷锁
d。channel是有类型的,一个整数的channel只能存整数

 channel声明

var name chan string
var age chan int
var mapchan chan map[string]string
var test chan student
var test1 chan *student

channel初始化

使用make进行初始化
var test chan int
test = make(chan int,10)

var test chan string
test=make(chan string,10)

channel基本操作

从channel读取数据
var
testChan chan int testChan = make(chan int, 10) var a int a = <-testChan

-从channel写入数据

var testChan chan int
testChan = make(chan int, 10)
var a int = 10
testChan <- a

第一个例子

package main

import "fmt"

type student struct {
    name string
}

func main() {
    var stuChan chan *student
    stuChan = make(chan *student, 10)

    stu := student{name: "stu001"}

    stuChan <- &stu

    var stu01 interface{}
    stu01 = <-stuChan

    var stu02 *student
    stu02, ok := stu01.(*student)
    if !ok {
        fmt.Println("can not convert")
        return
    }
    fmt.Println(stu02)
}

goroutine与channel

package main

import (
    "fmt"
    "time"
)

//起一个读的协程
func write(ch chan int) {
    for i := 0; i < 1000; i++ {
        ch <- i
    }
}

func read(ch chan int) {
    for {
        var b int
        b = <-ch
        fmt.Println(b)
    }
}

func main() {
    intChan := make(chan int, 10)
    go write(intChan)
    go read(intChan)
    time.Sleep(10 * time.Second)
}

读,取,字符串

package main

import (
    "fmt"
    "time"
)

func sendData(ch chan string) {
    ch <- "Washington"
    ch <- "Tripoli"
    ch <- "London"
    ch <- "Beijing"
    ch <- "Tokio"
}

func getData(ch chan string) {
    var input string
    for {
        input = <-ch
        fmt.Println(input)
    }
}

func main() {
    ch := make(chan string)
    go sendData(ch)
    go getData(ch)
    time.Sleep(3 * time.Second)
}
读取字符串

 Channel缓冲区

只能放一个元素的testChan
var testChan chan int
testChan = make(chan int)
var a int
a = <-testChan

-

testChan是带缓冲区的chan,一次可以放10个元素
var
testChan chan int testChan = make(chan int, 10) var a int = 10 testChan <- a

 -

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    m    = make(map[int]uint64)
    lock sync.Mutex
)

type task struct {
    n int
}

func calc(t *task) {
    var sum uint64
    sum = 1
    for i := 1; i < t.n; i++ {
        sum *= uint64(i)

    }
    fmt.Println(t.n, sum)
    lock.Lock()
    m[t.n] = sum
    lock.Unlock()
}

func main() {
    for i := 0; i < 16; i++ {
        t := &task{n: i}
        go calc(t)
    }
    time.Sleep(10 * time.Second)
    lock.Lock()
    for k, v := range m {
        fmt.Printf("%d!=%v
", k, v)

    }
    lock.Unlock()
}
goroutine_lock
package main

import (
    "fmt"
)

func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
    for v := range taskChan {
        flag := true
        for i := 2; i < v; i++ {
            if v%i == 0 {
                flag = false
                break
            }
        }
        if flag {
            resChan <- v
        }
    }
    fmt.Println("exit")
    exitChan <- true
}
func main() {
    intChan := make(chan int, 1000)
    resultChan := make(chan int, 1000)
    exitChan := make(chan bool, 8)
    go func() {
        for i := 0; i < 10000; i++ {
            intChan <- i
        }
        close(intChan)
    }()
    for i := 0; i < 8; i++ {
        go calc(intChan, resultChan, exitChan)
    }

    //等待所有计算的goroutine全部退出
    go func() {
        for i := 0; i < 8; i++ {
            <-exitChan
            fmt.Println("wait goroute", i, "exited")
        }
        close(resultChan)
    }()
    for v := range resultChan {
        fmt.Println(v)
    }

}
goroutine_sync
package main

import "fmt"

func send(ch chan int, exitChan chan struct{}) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
    var a struct{}
    exitChan <- a
}
func recv(ch chan int, exitChan chan struct{}) {
    for {
        v, ok := <-ch
        if !ok {
            break
        }
        fmt.Println(v)
    }
    var a struct{}
    exitChan <- a
}
func main() {
    var ch chan int
    ch = make(chan int, 10)
    exitChan := make(chan struct{}, 2)

    go send(ch, exitChan)
    go recv(ch, exitChan)
    var total = 0
    for _ = range exitChan {
        total++
        if total == 2 {
            break
        }
    }
}
goroutine_sync2

检测管道是否关闭

package main

import "fmt"

func main() {
    var ch chan int
    ch = make(chan int, 10)
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
    for {
        var b int
        b, ok := <-ch
        //检测管道是否关闭
        if ok == false {
            fmt.Println("chan is close")
            break
        }
        fmt.Println(b)
    }
}
检测管道是否关闭

 如何关闭chan

1. 使用内置函数close进行关闭,chan关闭之后,for range遍历chan中
已经存在的元素后结束
2. 使用内置函数close进行关闭,chan关闭之后,没有使用for range的写法
需要使用,v, ok := <- ch进行判断chan是否关闭

chan的只读和只写

只读的声明
Var 变量的名字 <-chan int
Var readChan <- chan int

只写的声明
Var 变量的名字 chan<- int
Var writeChan chan<- int
package main

import "fmt"

//只写chan
func send(ch chan<- int, exitChan chan struct{}) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
    var a struct{}
    exitChan <- a
}

//只读chan
func recv(ch <-chan int, exitChan chan struct{}) {
    for {
        v, ok := <-ch
        if !ok {
            break
        }
        fmt.Println(v)
    }
    var a struct{}
    exitChan <- a
}

func main() {
    var ch chan int
    ch = make(chan int, 10) //初始化chan
    exitChan := make(chan struct{}, 2)

    go send(ch, exitChan)
    go recv(ch, exitChan)

    var total = 0
    for _ = range exitChan {
        total++
        if total == 2 {
            break
        }
    }

}
只读只写示例chan

不阻塞

package main

import "fmt"
import "time"

func main() {
    var ch chan int
    ch = make(chan int, 10)
    ch2 := make(chan int, 10)
    go func() {
        var i int
        for {
            ch <- i
            time.Sleep(time.Second)
            ch2 <- i * i
            time.Sleep(time.Second)
            i++
        }
    }()
    for {
        select {
        case v := <-ch:
            fmt.Println(v)
        case v := <-ch2:
            fmt.Println(v)
        case <-time.After(time.Second):
            fmt.Println("get data timeout")
            time.Sleep(time.Second)
        }
    }
}
chan不阻塞

Golang之定时器,recover

滴答滴答……定时器的使用

package main

import (
    "fmt"
    "time"
)
//定时器的使用
func main() {
    t := time.NewTicker(time.Second)
    //t.C是个channel,背后是个goroutine
    for v := range t.C {
        fmt.Println("hello,", v)
    }
}

一次定时器

package main

import (
    "fmt"
    "time"
)

//定时器的使用
func main() {
    select {
    //5秒之后触发
    case <-time.After(5*time.Second):
        fmt.Println("after")
    }
}

超时控制

package main

import (
    "fmt"
    "time"
)

func queryDb(ch chan int) {
    time.Sleep(time.Second)
    ch <- 100
}
func main() {
    ch := make(chan int)
    go queryDb(ch)
    t := time.NewTicker(time.Second)
    select {
    case v := <-ch:
        fmt.Println("result", v)
    case <-t.C:
        fmt.Println("timeout")
    }
}

 goroutine中使用recover

应用场景,如果某个goroutine panic了,而且这个goroutine里面没有捕获(recover),
那么整个进程就会挂掉。所以好的习惯是每当go产生一个goroutine,就需要写下recover

捕获goroutine的错误

package main

import (
    "fmt"
    "runtime"
    "time"
)

func test() {

    defer func() {
        if err := recover(); err != nil {
            fmt.Println("panic:", err)
        }
    }()

    var m map[string]int
    m["stu"] = 100
}

func calc() {
    for {
        fmt.Println("i'm calc")
        time.Sleep(time.Second)
    }
}

func main() {
    num := runtime.NumCPU()
    runtime.GOMAXPROCS(num - 1)
    go test()
    for i := 0; i < 2; i++ {
        go calc()
    }

    time.Sleep(time.Second * 10000)
}

Golang之单元测试

文件名必须以_test.go结尾
使用go test 执行单元测试

package main

func add(a, b int) int {
    return a + b
}
func sub(a, b int) int {
    return a - b
}
calc.go
package main

import (
    "testing"
)

func TestAdd(t *testing.T) {
    r := add(2, 4)
    if r != 6 {
        t.Fatalf("add(2,4) error,expect:%d,actual:%d", 6, r)

    }
    t.Logf("test add succ")
}
func TestSub(t *testing.T) {
    r := sub(2, 4)
    if r != -2 {
        t.Fatalf("sub(2,4) error,expect:%d,actual:%d", 6, r)
    }
    t.Logf("test sub succ")
}
calc_test.go
package main
main.go

运行:

E:projectsrcgo_devday8	est>go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
        calc_test.go:13: test add succ
=== RUN   TestSub
--- PASS: TestSub (0.00s)
        calc_test.go:20: test sub succ
PASS
ok      go_dev/day8/test        0.142s

Golang之定义错误(errors)

基本示例:

package main
//定义错误
//error 也是个接口
import (
    "errors"
    "fmt"
)

var errNotFound error = errors.New("Not found error")

func main() {
    fmt.Printf("error:%v", errNotFound)
}

错误处理:

package main

import (
    "fmt"
    "os"
    "time"
)

type PathError struct {
    path       string
    op         string
    createTime string
    message    string
}

func (p *PathError) Error() string {
    return fmt.Sprintf("path=%s op=%s createTime=%s message=%s",
        p.path, p.op, p.createTime, p.message)
}
func Open(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return &PathError{
            path:       filename,
            op:         "read",
            message:    err.Error(),
            createTime: fmt.Sprintf("%v", time.Now()),
        }
    }
    defer file.Close()
    return nil
}
func main() {
    err := Open("D:/project/src/go_dev/day7/example10/123.txt")
    switch v := err.(type) {
    case *PathError:
        fmt.Println("get path error,", v)
    default:

    }
}
错误处理

练习

package main

import "fmt"

func badCall() {
    panic("bad end")
}
func test() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("Panicking%s
", e)
        }
    }()
    badCall()
    fmt.Printf("After bad call
")
}
func main() {
    fmt.Printf("Calling test
")
    test()
}
原文地址:https://www.cnblogs.com/bubu99/p/12521702.html