Golang implementation of the chat program server and client code sharing

  • 2020-05-10 18:20:34
  • OfStack

Implementation logic

1. Golang version   1.3

2. Implementation principle:

1. The main process establishes TCP listening service and initializes one variable talkChan := make(map[int]chan string).

2. When the main process ACCEPT connection request is made, go is used to start a coroutine A to maintain the connection with the client, and taokChan is brought into the coroutine

3. Establish a coroutine A to connect with the client, send a message to the client, and make it send its own user information.

After receiving the user information sent by the client, talkChan [uid] = make (chan string)

5. Co-program A starts another co-program A1 to read the message sent by the client, and to judge who the message is sent to, and then puts the message into the corresponding chan.

6. Co-program A starts another co-program A2 to read the pipe corresponding to this user. If there is any information in it, it will be taken out and sent to the client.

The implementation code

Server test code: server.go


package main import (
    "fmt"
    "log"
    "net"
    "strconv"
) func handleConnection(conn net.Conn, talkChan map[int]chan string) {
    //fmt.Printf("%p\n", talkChan)  // To check if the pointer is passed     /*
        Defines the current user's uid
    */
    var curUid int     var err error     /*
        Define a closed channel
    */
    var closed = make(chan bool)     defer func() {
        fmt.Println("defer do : conn closed")
        conn.Close()
        fmt.Printf("delete userid [%v] from talkChan", curUid)
        delete(talkChan, curUid)
    }()     /**
     * Users are prompted to set their own uid . If it is not set, it is not executed down
     */
    for {
        // The client is prompted to set the user id
        _, err = conn.Write([]byte(" Please set the user uid"))
        if err != nil {
            return
        }
        data := make([]byte, 1024)
        c, err := conn.Read(data)
        if err != nil {
            //closed <- true  // It will block | The back closed the for Loop, not executed.
            return
        }
        sUid := string(data[0:c])         // into int type
        uid, _ := strconv.Atoi(sUid)
        if uid < 1 {
            continue
        }
        curUid = uid
        talkChan[uid] = make(chan string)
        //fmt.Println(conn, "have set uid ", uid, "can talk")         _, err = conn.Write([]byte("have set uid "+sUid+" can talk"))
        if err != nil {
            return
        }
        break
    }     fmt.Println("err 3")     // All current connections
    fmt.Println(talkChan)     // Read the data sent by the client
    go func() {
        for {
            // Keep reading the data sent by the client
            data := make([]byte, 1024)
            c, err := conn.Read(data)
            if err != nil {
                fmt.Println("have no client write", err)
                closed <- true // You can use it here | Because it's used go New thread to process. |  Even if the chan Block, and the next one will be read closed this chan
            }             clientString := string(data[0:c])             // Write the data from the client to the corresponding chan In the
            if curUid == 3 {
                talkChan[4] <- clientString
            } else {
                talkChan[3] <- clientString
            }         }
    }()     /*
        from chan To read the data to the client Then write it to the client
    */
    go func() {
        for {
            talkString := <-talkChan[curUid]
            _, err = conn.Write([]byte(talkString))
            if err != nil {
                closed <- true
            }
        }
    }()     /*
       Check if the connection has been closed If closed, the thread is pushed out   To carry out defer statements
    */
    for {
        if <-closed {
            return
        }
    }
} func main() {     /**
    Set up a listening link
    */
    ln, err := net.Listen("tcp", "127.0.0.1:6010")
    if err != nil {
        panic(err)
    }     // create 1 A pipe     //talkChan := map[f]
    talkChan := make(map[int]chan string)     fmt.Printf("%p\n", talkChan)     /*
       Listen for client connection requests
    */
    for {
        fmt.Println("wait connect...")
        conn, err := ln.Accept()
        if err != nil {
            log.Fatal("get client connection error: ", err)
        }         go handleConnection(conn, talkChan)
    }
}

Client test code: client.go


package main import (
    "fmt"
    "math/rand"
    "net"
) func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:6010")
    if err != nil {
        panic(err)
    }     fmt.Fprintf(conn, "hello server\n")     defer conn.Close()
    go writeFromServer(conn)     for {
        var talkContent string
        fmt.Scanln(&talkContent)         if len(talkContent) > 0 {
            _, err = conn.Write([]byte(talkContent))
            if err != nil {
                fmt.Println("write to server error")
                return
            }
        }
    }
} func connect() {
    conn, err := net.Dial("tcp", "127.0.0.1:6010")
    if err != nil {
        panic(err)
    }     fmt.Fprintf(conn, "hello server\n")     defer conn.Close()
    go writeFromServer(conn)     for {
        var talkContent string
        fmt.Scanln(&talkContent)         if len(talkContent) > 0 {
            _, err = conn.Write([]byte(talkContent))
            if err != nil {
                fmt.Println("write to server error")
                return
            }
        }
    }
} func writeFromServer(conn net.Conn) {
    defer conn.Close()
    for {
        data := make([]byte, 1024)
        c, err := conn.Read(data)
        if err != nil {
            fmt.Println("rand", rand.Intn(10), "have no server write", err)
            return
        }
        fmt.Println(string(data[0:c]) + "\n ")
    }
}


Related articles: