zoukankan      html  css  js  c++  java
  • 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()
    }
  • 相关阅读:
    QPushbutton样式
    qt调动DLL
    QLabel设置行间距
    Qt 5.2.1 applications (32 bit) in CentOS (64 bit with gcc 4.8.2)
    qt设置阴影效果
    ubuntu命令
    How to configure NFS on Linux
    gsoap生成onvif c++源码
    QUrl乱码问题
    QTableWidget自适应标题(铺满、可调节)
  • 原文地址:https://www.cnblogs.com/bubu99/p/12521702.html
Copyright © 2011-2022 走看看