golang實現(xiàn)qq聊天之客戶端與服務(wù)器

一、用到的net方法
1 、客戶端:

    var buf [512]byte
    tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9090")
    //向服務(wù)器撥號
    conn, _ := net.DialTCP("tcp", nil, tcpAddr)
    //獲取遠程服務(wù)器地址
    rAddr := conn.RemoteAddr()
    //發(fā)送數(shù)據(jù)
    n, _ := conn.Write([]byte(""))
    //接收數(shù)據(jù)
    n, _ = conn.Read(buf[0:])

2、服務(wù)器

func ResolveTCPAddr(network, address string) (*TCPAddr, error)
ResolveTCPAddr返回TCP端點的地址。
網(wǎng)絡(luò)必須是TCP網(wǎng)絡(luò)名。
如果地址參數(shù)中的主機不是字面IP地址或者端口不是字面端口號,那么ResolveTCPAddr將地址解析為TCP端點的地址。
否則,它將地址解析為一對文字IP地址和端口號。
address參數(shù)可以使用主機名,但不建議這樣做,因為它將最多返回一個主機名的IP地址。
有關(guān)網(wǎng)絡(luò)和地址的描述,請參閱func Dial參數(shù)。

network : Tcp Tcp4 Tcp6         address : :9090  應(yīng)該是訪問地址
返回值:*TCPAddr 地址   第二個返回值:err 
 
監(jiān)聽:func ListenTCP(network string, laddr *TCPAddr) (*TCPListener, error)
ListenTCP在本地TCP地址laddr上聲明并返回一個*TCPListener,net參數(shù)必須是"tcp"、"tcp4"、"tcp6",如果laddr的端口字段為0,函數(shù)將選擇一個當前可用的端口,可以用Listener的Addr方法獲得該端口

第一個參數(shù):TCP   第二個參數(shù) *TCPAddr 地址   返回值 :

具體代碼實現(xiàn)
net.go

package main

import (
    "fmt"
    "log"
    "net"
    "os"
)

func main() {
tcpAddr, _ := net.ResolveTCPAddr("tcp", ":9090")
    //向服務(wù)器撥號
    conn, _ := net.DialTCP("tcp", nil, tcpAddr)
    go HandlerMessage(conn)
    //接受來自服務(wù)器的消息
    buf := make([]byte, 1024)
    for {
        length, err := conn.Read(buf)
        fmt.Println(length)
        if err != nil {
            log.Printf("recv server msg failed :%v\n", err)
            conn.Close()
            os.Exit(0)
            break
        }
        fmt.Println(string(buf[0:length]))
    }

}
func HandlerMessage(conn net.Conn) {
    //獲取用戶的地址
    username := conn.LocalAddr().String()
    for {
        var input string
        //獲取用戶發(fā)送的消息
        fmt.Scanln(&input)
        if len(input) > 0 {
            msg := username + " say " + input
            //
            _, err := conn.Write([]byte(msg))
            if err != nil {
                conn.Close()
                break
            }
        }
    }
}

server.go

package main

import (
    "fmt"
    "net"
    "os"
)

func main() {
    port := "9090"
    StartServer(port)
}
func StartServer(p string) {
    port := ":" + p
    //返回tcp地址
    tcpAddr, err := net.ResolveTCPAddr("tcp", port)
    fmt.Println(tcpAddr)
    if err != nil {
        os.Exit(0)
        return
    }
    //監(jiān)聽tcp地址
    listener, err := net.ListenTCP("tcp", tcpAddr)
    if err != nil {
        os.Exit(0)
        return
    }
    buf := make([]byte, 1024)
    conns := make(map[string]net.Conn)  //用戶池
    messages := make(chan string, 10)  //消息的通道
    go BroadCastMessage(conns, messages)  //
    //每有一個客戶進來就將其放入用戶池
    for {
        conn, err := listener.AcceptTCP()
        if err != nil {
            fmt.Println("Accept failed")
            continue
        }
        conns[conn.RemoteAddr().String()] = conn  //將新進來的用戶放進用戶池
        go HandlerMessage(conn, buf, conns, messages)  //開一個協(xié)程監(jiān)聽用戶是否發(fā)送消息
    }

}
//將收到的信息發(fā)送到每一個客戶端
func BroadCastMessage(cns map[string]net.Conn, messages chan string) {
    for {
        messtr := <-messages    //接受通道里的消息
        //將接收到的消息發(fā)送給用戶池里的每一個用戶
        for k, v := range cns {
            _, err := v.Write([]byte(messtr))  //發(fā)送消息
            if err != nil {
                delete(cns, k)  //如果出現(xiàn)錯誤 刪除用戶 結(jié)束本次循環(huán)
                v.Close()
                continue
            }
        }
    }
}
//接受用戶發(fā)送的消息
func HandlerMessage(conn net.Conn, buf []byte, cns map[string]net.Conn, messages chan string) {
    for {
        length, err := conn.Read(buf)
        if err != nil {
            conn.Close()
            delete(cns, conn.RemoteAddr().String())
            break
        }
        messages <- string(buf[0:length])  //將用戶的信息放到通道里
        // fmt.Println(string(buf[0:length]))
    }
}

OK!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,328評論 2 89
  • 計算機網(wǎng)絡(luò)概述 網(wǎng)絡(luò)編程的實質(zhì)就是兩個(或多個)設(shè)備(例如計算機)之間的數(shù)據(jù)傳輸。 按照計算機網(wǎng)絡(luò)的定義,通過一定...
    蛋炒飯_By閱讀 1,377評論 0 10
  • 王安石說過,世之奇?zhèn)ス骞址浅V^,常在于險遠,而人之所罕至焉,故非有志者不能至也。 所從事的工作缺乏創(chuàng)意和動力...
    毫無章法閱讀 2,420評論 0 0
  • 關(guān)于設(shè)計的意義,原研哉在《設(shè)計中的設(shè)計》一書中寫到:“理解一個東西不是能夠定義它或是描述它,而是把這個我們認為自己...
    喵小姐huan閱讀 472評論 0 2
  • 秋風涼-目錄(持續(xù)更新) 前情概要 小玲瓏因父親亡故而流落街頭,不得已在饑餓驅(qū)使下偷了包子。不料卻被伙計追趕,眼看...
    寸草945閱讀 681評論 4 6

友情鏈接更多精彩內(nèi)容