Golang聊天室

來源:互聯網
上載者:User

一、前期準備

  • 前期準備
  • 需要 import "net"包
  • IP 類型,其中一個重要的方法是 IP.ParseIP(ipaddr string)來判斷是否是合法的 IP 位址
  • TCP Client
  • func (c *TCPConn) Write(b []byte) (n int, err os.Error)用於發送資料,返回傳送的資料長度或者返回錯誤,是TCPConn的方法
  • func (c *TCPConn) Read(b []byte) (n int, err os.Error)用於接收資料,返回接收的長度或者返回錯誤,是 TCPConn 的方法
  • TCPAddr 類型,儲存 TCP 的地址資訊,包括地址和連接埠
 type TCPAddr struct {      IP IP      Port int  }
  • func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)擷取一個 TCPAddr,參數都是 string 類型,net 是個 const string,包括 tcp4,tcp6,tcp 一般使用 tcp,相容 v4 和 v6,addr 表示 ip 地址,包括連接埠號碼,如www.google.com:80之類的
  • func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)用來串連(connect)到遠程伺服器上,net 表示協議方式,tcp,tcp4 或者 tcp6,laddr 表示本機地址,一般為 nil,raddr 表示遠程地址,這裡的 laddr 和 raddr 都是 TCPAddr 類型的,一般是上一個函數的傳回值。
  • 作為一個 TCP 的用戶端,基本的操作流程如下:
service="www.google.com:80"  tcpAddr, err := net.ResolveTCPAddr("tcp4", service)  conn, err := net.DialTCP("tcp", nil, tcpAddr)  _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))  _, err = conn.Read(b) / result, err := ioutil.ReadAll(conn)
  • TCP Server
  • func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)用來監聽連接埠,net 表示協議類型,laddr 表示本機地址,是 TCPAddr 類型,注意,此處的 laddr 包括連接埠,返回一個*TCPListener類型或者錯誤
  • func (l *TCPListener) Accept() (c Conn, err os.Error)用來返回一個新的串連,進行後續操作,這是 TCPListener 的方法,一般 TCPListener 從上一個函數返回得來。
  • 伺服器的基本操作流程為:
service:=":9090"  tcpAddr, err := net.ResolveTCPAddr("tcp4", service)  l,err := net.ListenTCP("tcp",tcpAddr)  conn,err := l.Accept()  go Handler(conn) //此處使用go關鍵字建立線程處理串連,實現並發

 

二、聊天室需求

實現一個公用聊天伺服器。

  • 伺服器接收用戶端的資訊
  • 接收完以後將用戶端的資訊發送到所有的用戶端上
  • 用戶端使用/quit退出聊天
  • 只使用一套代碼,通過命令列參數啟動伺服器還是用戶端

 

主要知識點如下:

  • 代碼中包括了伺服器和用戶端的內容,如果是伺服器,直接輸入go run main.go server 9090即可,用戶端也很簡單,輸入go run main.go client :9090就好;

  • 如果是用戶端,其實就包括了兩部分內容,一部分是 chatSend 函數,接受使用者的輸入;另一部分是connect 到 server,接受相關資訊;

  • 如果是 server,稍微複雜一點,有三個部分組成。第一部分就是不停地 accept 各個用戶端;第二個就是為每一個用戶端創立 Handler 函數,接受用戶端發來的資訊;第三個就是 echoHandler 函數,它的作用就是將從某一使用者接受過來的資訊廣播給其他所有的用戶端,就是這麼簡單。

代碼實現:
package mainimport (    "os"    "fmt"    "net")/**主程式  啟動用戶端和服務端參數說明:  啟動伺服器端:  go run main.go server [port]             eg: go run main.go server 9090  啟動用戶端:   go run main.go [Server Ip Addr]:[Server Port]    eg: go run main.go client :9090 */func main()  {    if len(os.Args) != 3 {        fmt.Println("wrong params")        os.Exit(0)    }    if os.Args[1] == "server" {        StartServer(os.Args[2])    }    if os.Args[1] == "client" {        StartClient(os.Args[2])    }}/**啟動伺服器參數:port 連接埠號碼 */func StartServer(port string)  {    service := ":" + port    tcpAddr,err := net.ResolveTCPAddr("tcp4", service)    checkError(err, "ResolveTCPAddr")    l,err := net.ListenTCP("tcp", tcpAddr)    checkError(err ,"ListenTCP")    conns := make(map[string]net.Conn)    messages := make(chan string, 10)    //啟動伺服器廣播線程 :向所有用戶端發送訊息    go echoHandler(&conns, messages)    for {        fmt.Println("Listening ...")        conn,err := l.Accept()//返回一個新的串連        checkError(err , "l.Accept")        fmt.Println("Accepting ...")        conns[conn.RemoteAddr().String()] = conn        //啟動一個接受用戶端發送訊息的線程        go Handler(conn, messages)    }}/**伺服器發送資料的線程:向所有用戶端發送訊息參數   串連字典 conns   資料通道 messages */func echoHandler(conns *map[string]net.Conn, messages chan string)  {    for {        msg := <-messages        fmt.Println(msg)        for key,con := range *conns {            fmt.Println("connection is connected from ...", key)            _,err := con.Write([]byte(msg))            if err != nil {                fmt.Println(err)                delete(*conns, key)            }        }    }}/**伺服器端接收用戶端資料線程參數:    據串連 conn    通訊通道 messages */func Handler(conn net.Conn, messages chan string)  {    fmt.Println("connection is connected from ...", conn.RemoteAddr().String())    buf := make([]byte, 1024)    for {        lenght,err := conn.Read(buf)        if checkError(err, "Connection") == false {            conn.Close()            break        }        if lenght >0 {            buf[lenght] = 0        }        reciveStr := string(buf[0:lenght])        messages <- reciveStr    }}/**用戶端啟動函數參數:    程ip地址和連接埠 tcpaddr */func StartClient(tcpaddr string)  {    tcpAddr,err := net.ResolveTCPAddr("tcp4", tcpaddr)    checkError(err, "ResolveTCPAddr")    conn,err := net.DialTCP("tcp",nil,tcpAddr)    checkError(err, "DialTCP")    //啟動用戶端發送資料線程    go chatSend(conn)    //接收服務端發送來的訊息    buf := make([]byte, 1024)    for {        lenght,err := conn.Read(buf)        if checkError(err, "Connection") == false {            conn.Close()            fmt.Println("Server is dead ...ByeBye")            os.Exit(0)        }        fmt.Println(string(buf[0:lenght]))    }}/**用戶端發送資料線程參數:     發送串連 conn */func chatSend(conn net.Conn)  {    var input string    username := conn.LocalAddr().String()    for {        fmt.Scanln(&input)        if input == "/quit" {            fmt.Println("ByeBye..")            conn.Close()            os.Exit(0)        }        lens,err := conn.Write([]byte(username + "say ::: " + input))        fmt.Println(lens)        if err != nil {            fmt.Println(err.Error())            conn.Close()            break        }    }}//錯誤資訊func checkError(err error, info string)  (res bool) {    if err != nil {        fmt.Println(info + ",err:" + err.Error())        return false    }    return true}

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.