Golang聊天室

紫若丹枫 · · 2079 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  • 前期准备
    • 需要 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退出聊天
    • 只使用一套代码,通过命令行参数启动服务器还是客户端
  • 主要知识点如下:

    1. 代码中包括了服务器和客户端的内容,如果是服务器,直接输入./chat server 9090即可,客户端也很简单,输入./chat client :9090就好;
    2. 如果是客户端,其实就包括了两部分内容,一部分是 chatSend 函数,接受用户的输入;另一部分是connect 到 server,接受相关信息;
    3. 如果是 server,稍微复杂一点,有三个部分组成。第一部分就是不停地 accept 各个客户端;第二个就是为每一个客户端创立 Handler 函数,接受客户端发来的信息;第三个就是 echoHandler 函数,它的作用就是将从某一用户接受过来的信息广播给其他所有的客户端,就是这么简单。
      [实现]

         package main
      
         import (
             "fmt"
             "net"
             "os"
         )
      
         ////////////////////////////////////////////////////////
         //
         //错误检查
         //
         ////////////////////////////////////////////////////////
         func checkError(err error, info string) (res bool) {
      
             if err != nil {
                 fmt.Println(info + "  " + err.Error())
                 return false
             }
             return true
         }
      
         ////////////////////////////////////////////////////////
         //
         //服务器端接收数据线程
         //参数:
         //      数据连接 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
                 }
                 //fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght]))
                 reciveStr := string(buf[0:lenght])
                 messages <- reciveStr
      
             }
      
         }
      
         ////////////////////////////////////////////////////////
         //
         //服务器发送数据的线程
         //
         //参数
         //      连接字典 conns
         //      数据通道 messages
         //
         ////////////////////////////////////////////////////////
         func echoHandler(conns *map[string]net.Conn, messages chan string) {
      
             for {
                 msg := <-messages
                 fmt.Println(msg)
      
                 for key, value := range *conns {
      
                     fmt.Println("connection is connected from ...", key)
                     _, err := value.Write([]byte(msg))
                     if err != nil {
                         fmt.Println(err.Error())
                         delete(*conns, key)
                     }
      
                 }
             }
      
         }
      
         ////////////////////////////////////////////////////////
         //
         //启动服务器
         //参数
         //  端口 port
         //
         ////////////////////////////////////////////////////////
         func StartServer(port string) {
             service := ":" + port //strconv.Itoa(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, "Accept")
                 fmt.Println("Accepting ...")
                 conns[conn.RemoteAddr().String()] = conn
                 //启动一个新线程
                 go Handler(conn, messages)
      
             }
      
         }
      
         ////////////////////////////////////////////////////////
         //
         //客户端发送线程
         //参数
         //      发送连接 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
                 }
      
             }
      
         }
      
         ////////////////////////////////////////////////////////
         //
         //客户端启动函数
         //参数
         //      远程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]))
      
             }
         }
      
         ////////////////////////////////////////////////////////
         //
         //主程序
         //
         //参数说明:
         //  启动服务器端:  Chat server [port]             eg: Chat server 9090
         //  启动客户端:    Chat client [Server Ip Addr]:[Server Port]    eg: Chat client 192.168.0.74:9090
         //
         ////////////////////////////////////////////////////////
         func main() {
      
             if len(os.Args) != 3 {
                 fmt.Println("Wrong pare")
                 os.Exit(0)
             }
      
             if os.Args[1] == "server" && len(os.Args) == 3 {
      
                 StartServer(os.Args[2])
             }
      
             if os.Args[1] == "client" && len(os.Args) == 3 {
      
                 StartClient(os.Args[2])
             }
      
         }

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:紫若丹枫

查看原文:Golang聊天室

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2079 次点击  
加入收藏 微博
上一篇:golang安装
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传