国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

go語言實現(xiàn)聊天服務(wù)器的示例代碼

2020-04-01 18:55:02
字體:
供稿:網(wǎng)友

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

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

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

server 端:

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

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 += "發(fā)送消息,可使用 1<-這是給1號客戶端的消息/n(請使用英文以獲取最佳體驗)/n"    senderChan <- cs    time.Sleep(time.Millisecond * 300)    senderChan <- ls    // 發(fā)送格式化的列表    fmt.Println("已發(fā)送“登錄用戶信息”", addr)  } else{    fmt.Println("客戶端接受通道不存在", addr)  }}func serve (conn *net.Conn){  connect := *conn  addr := connect.RemoteAddr().String()  fmt.Println(addr, "接入服務(wù)")  senderChan := make(chan string, 3)  clientSenders[addr] = senderChan  // 啟動發(fā)送  go send(addr, conn)  // 發(fā)送當(dāng)前用戶信息  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    }    // 提取數(shù)據(jù)    msgs := strings.Split(msg, "<-")    if len(msg) < 2{      senderChan <- string("數(shù)據(jù)格式不正確,請聯(lián)系開發(fā)者")      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  }  // 啟動消息調(diào)度器  defer listener.Close()  // 啟動連接監(jiān)聽  for {    conn, err := listener.Accept()    if err != nil {      fmt.Println(err)      continue    }    go serve(&conn)  }}

客戶端:

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

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("結(jié)束")        (*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:      // 解析客戶端列表數(shù)據(jù)      addrs = strings.Split(msg, "/n")      fmt.Println("已接收客戶端列表。/n")      break    default:      fmt.Print(msg)      break    }  }}func connectServer(){  addr := "192.168.99.236:8080"  fmt.Println("等待服務(wù)器開啟中")  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("發(fā)送的姿勢不正確,應(yīng)該像這樣 1<-給1號發(fā)送消息/n")      continue    }    index, err := strconv.Atoi(msgs[0])    if err != nil {      fmt.Println("發(fā)送的姿勢不正確,應(yīng)該像這樣 1<-給1號發(fā)送消息/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()    }  }()}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 黎川县| 鹤庆县| 随州市| 开鲁县| 东宁县| 子洲县| 皮山县| 南澳县| 蒲江县| 南投市| 远安县| 镇安县| 环江| 平定县| 太原市| 柳林县| 平果县| 沈丘县| 遂川县| 翁源县| 公主岭市| 龙泉市| 松溪县| 隆林| 公主岭市| 韶山市| 安新县| 陆河县| 周至县| 开鲁县| 仙游县| 新丰县| 文昌市| 固始县| 甘孜县| 宜章县| 凉山| 邵东县| 洪泽县| 西畴县| 兴业县|