a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > Golang > 正文

go語言實現聊天服務器的示例代碼

2020-04-01 18:55:02
字體:
來源:轉載
供稿:網友

看了兩天 go 語言,是時候練練手了。

go 的 routine(例程) 和 chan(通道) 簡直是神器,實現多線程(在 go 里準確的來說是 多例程)簡直不要太輕松。

于是動手碼了一個傻瓜版的黑框聊天器。

server 端:

監聽 TCP 連接;支持自定義客戶端命令;支持消息分發;理論上支持廣播;...

package mainimport (  "fmt"  "net"  "io"  "strconv"  "time"  "strings")const (  NORMAL_MESSAGE = iota  LIST_MESSAGE)var clientSenders = make(map[string] chan string)func send (addr string, conn *net.Conn){  senderChan := clientSenders[addr]  for s := range senderChan{    (*conn).Write([]byte(s))  }}func sendUsersInfo(addr string){  senderChan := clientSenders[addr]  if nil != senderChan{    ls := strconv.Itoa(LIST_MESSAGE)    cs := strconv.Itoa(NORMAL_MESSAGE) + "已登錄客戶端列表:/n"    i := 1    for k := range clientSenders{      a := ""      if k == addr {        a = "(我)"      }      cs = cs + strconv.Itoa(i) + ")" + k + a + "/n"      ls += k + "/n"      i ++    }    cs += "發送消息,可使用 1<-這是給1號客戶端的消息/n(請使用英文以獲取最佳體驗)/n"    senderChan <- cs    time.Sleep(time.Millisecond * 300)    senderChan <- ls    // 發送格式化的列表    fmt.Println("已發送“登錄用戶信息”", addr)  } else{    fmt.Println("客戶端接受通道不存在", addr)  }}func serve (conn *net.Conn){  connect := *conn  addr := connect.RemoteAddr().String()  fmt.Println(addr, "接入服務")  senderChan := make(chan string, 3)  clientSenders[addr] = senderChan  // 啟動發送  go send(addr, conn)  // 發送當前用戶信息  go sendUsersInfo(addr)  buff := make([]byte, 10240)  for {    n, err := connect.Read(buff)    if err != nil {      if err == io.EOF {        fmt.Println("客戶端斷開鏈接,", addr)        delete(clientSenders, addr)        return      } else{        fmt.Println(err)      }    }    msg := string(buff[:n])    // 刷新客戶端列表    if msg == "ls/n" {      go sendUsersInfo(addr)      continue    }    // 提取數據    msgs := strings.Split(msg, "<-")    if len(msg) < 2{      senderChan <- string("數據格式不正確,請聯系開發者")      continue    }    aimAddr := msgs[0]    aimSender := clientSenders[aimAddr]    if aimSender == nil {      senderChan <- string("客戶端已下線,使用 ls 命令獲取最新的客戶端列表")      continue    }    aimSender <- strconv.Itoa(NORMAL_MESSAGE) + "[from:" + addr + "]:" + strings.Join(msgs[1:], "<-")  }}func main(){  addr := ":8080"  listener, err := net.Listen("tcp", addr)  if err != nil{    fmt.Println(err)    return  }  // 啟動消息調度器  defer listener.Close()  // 啟動連接監聽  for {    conn, err := listener.Accept()    if err != nil {      fmt.Println(err)      continue    }    go serve(&conn)  }}

客戶端:

支持斷線重連;支持給特定其他客戶端發信息

package mainimport (  "net"  "fmt"  "io"  "os"  "bufio"  "sync"  "time"  "strings"  "strconv")var conn *net.Connvar addrs []stringconst (  NORMAL_MESSAGE = iota  LIST_MESSAGE)func read(conn2 *net.Conn){  defer func() {    fmt.Println("嘗試重連")    go connectServer()  }()  connect := *conn2  buff := make([]byte, 20140)  for {    n, err := connect.Read(buff)    if err != nil {      if err == io.EOF{        fmt.Println("結束")        (*conn2).Close()        conn = nil        return      } else{        fmt.Println(err)      }    }    msg := string(buff[:n])    t, err := strconv.Atoi(string(msg[0]))    msg = msg[1:]    switch t {    case NORMAL_MESSAGE:      fmt.Print(msg)      break    case LIST_MESSAGE:      // 解析客戶端列表數據      addrs = strings.Split(msg, "/n")      fmt.Println("已接收客戶端列表。/n")      break    default:      fmt.Print(msg)      break    }  }}func connectServer(){  addr := "192.168.99.236:8080"  fmt.Println("等待服務器開啟中")  conn2, err := net.Dial("tcp", addr)  if err != nil {    fmt.Print(err)    fmt.Println("連接失敗,10s后嘗試")    time.Sleep(10 * time.Second)    go connectServer()    return  }  fmt.Println("已連接")  conn = &conn2  go read(&conn2)}func send (){  inputReader := bufio.NewReader(os.Stdout)  for {    input, err := inputReader.ReadString('/n')    if err != nil {      if err == io.EOF{        return      } else{        fmt.Println(err)      }    }    if input == "ls/n" {      (*conn).Write([]byte(input))      continue    }    msgs := strings.Split(input, "<-")    if len(msgs) < 2 {      fmt.Println("發送的姿勢不正確,應該像這樣 1<-給1號發送消息/n")      continue    }    index, err := strconv.Atoi(msgs[0])    if err != nil {      fmt.Println("發送的姿勢不正確,應該像這樣 1<-給1號發送消息/n")      continue    }    if len(addrs) <= index {      fmt.Println("不存在第" + strconv.Itoa(index) + "個客戶端/n")      continue    }    addr := addrs[index-1]    input = addr + "<-" + strings.Join(msgs[1:], "<-")    if nil != conn {      (*conn).Write([]byte(input))    }  }}func main (){  var wg sync.WaitGroup  wg.Add(2)  go connectServer()  go send()  wg.Wait()  defer func() {    if nil != conn {      (*conn).Close()    }  }()}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 欧美精品在线免费观看 | 99久久婷婷国产综合精品电影 | 国产在线看h| 青青草久久爱 | 午夜无码国产理论在线 | 成人一区二区三区视频 | 久久国产精品一区 | 羞羞网站在线 | 久久久久久亚洲精品中文字幕 | 国产精品日韩欧美一区二区三区 | 久久综合av | 一级黄色影视 | 一区二区手机在线 | 亚洲欧洲视频 | 久久线视频| 麻豆专区一区二区三区四区五区 | 9色网站| 中文字幕 在线观看 | 免费av一区二区三区 | 一级片手机免费看 | 免费一二区 | 日本福利视频 | 免费成人在线观看视频 | 九色欧美 | 国产精品久久久久久吹潮 | 青草青草久热精品视频在线观看 | 日韩精品一区二区三区中文在线 | 久热在线视频 | 欧美精品综合 | 亚洲 成人 av | 久久久精品高清 | 毛片在线看片 | 亚洲成人久久久 | 一级a性色生活片久久毛片明星 | 国产精品.xx视频.xxtv | 欧美a一级 | 亚洲国产精品久久久久久 | 久久瑟瑟 | 免费一级毛片 | 免费黄色特级片 | 免费观看一区二区三区毛片 |