一、前期准备

  • 前期准备
  • 需要 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 main

import (
"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) != {
fmt.Println("wrong params")
os.Exit()
}
if os.Args[] == "server" {
StartServer(os.Args[])
}
if os.Args[] == "client" {
StartClient(os.Args[])
}
} /**
启动服务器
参数: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, ) //启动服务器广播线程 :向所有客户端发送消息
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, )
for {
lenght,err := conn.Read(buf)
if checkError(err, "Connection") == false {
conn.Close()
break
}
if lenght > {
buf[lenght] =
}
reciveStr := string(buf[: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, )
for {
lenght,err := conn.Read(buf)
if checkError(err, "Connection") == false {
conn.Close()
fmt.Println("Server is dead ...ByeBye")
os.Exit()
}
fmt.Println(string(buf[: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()
}
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
}

Golang聊天室的更多相关文章

  1. websocket+golang聊天室

    原文地址: http://www.niu12.com/article/3 websocket+golang聊天室 main.go和index.html放在同一目录下 main.go package m ...

  2. golang 聊天室

    近期看了一些关于golang的资料.发现它的WEBSOCKT实现真起来真的非常easy.以下是代码 go.net/websocket是须要安装的,这个自己装上即可 package main impor ...

  3. Golang语言快速上手到综合实战高并发聊天室

    需要的联系我:QQ:1844912514 Go是Google开发的一种编译型,可并行化,并具有垃圾回收功能的编程语言.2015,Go迎来了全迸发的一年.时隔一年,回头再看,Go已跻身主流编程语言行列. ...

  4. golang简易版聊天室

    功能需求: 创建一个聊天室,实现群聊和单聊的功能,直接输入为群聊,@某人后输入为单聊 效果图: 群聊:   单聊: 服务端: package main import ( "fmt" ...

  5. go 聊天室简单版总结

    /* * 思路:在登录成功时将用户的id存进在线用户列表中的key value中链接的ws为空,并保存用户的信息. * 当跳转到聊天室时,将用户和聊天室链接的ws存进在线用户列表中的 * 问题:如何在 ...

  6. 网络编程-基于Websocket聊天室(IM)系统

    目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...

  7. 利用Node.js的Net模块实现一个命令行多人聊天室

    1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...

  8. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  9. 基于select的python聊天室程序

    python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...

随机推荐

  1. 操作XDocument讲解

    1.首先建立好XML .可以通选自定义EXCEL导出XML格式的数据:(如图) 2 读取XML 文件 具体的详细讲解 可以查看 改网址 :https://blog.csdn.net/dyllove98 ...

  2. django系列8.4--django中间件的可应用案例, 限制请求次数与时间

    应用案例 1.做IP访问频率限制 某些IP访问服务器的频率过高,进行拦截, 比如每分钟不能超过20次 2.URL访问过滤 如果用户访问的是login视图,就允许请求 如果访问其他视图, 需要检测是不是 ...

  3. Substrings(SPOJ8222) (sam(后缀自动机))

    You are given a string \(S\) which consists of 250000 lowercase latin letters at most. We define \(F ...

  4. 查看npm安装包版本

    npm list 版本号. eg: npm list socket.io

  5. Spring Boot启动过程(六):内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动

    看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...

  6. GraphQL 如何取代 Redux

    简评:使用 GraphQL 可以大大简化客户端状态管理部分的代码. ⚛️切换到React 故事背景:在 2016 年,Pathwright 的前端团队就开始将客户端的代码从 Backbone & ...

  7. 实验二 输出“Hello Word!”,测试主方法的输入参数和心得体会

    实验二 一.输出“Hello World!” 1.首先打开eclipse,如下图所示. 2.选择一个工作空间,如下图所示. 3.接下来,点击[Java项目]创建一个Java项目,如下图所示. 4.然后 ...

  8. 图解http 笔记

    一,了解web以及网络基础 1,使用http协议访问web web页面是由web浏览器根据地址栏中指定的url从web服务器获取文件资源等信息然后显示的页面. 像这种通过发送请求获取服务器资源的web ...

  9. selenium和appium启动的感悟

    阅读源码后整理记录如下: selenium : 1.若为webdriver.Chrome()方式启动:①子程序打开chromedriver.exe程序,程序打开后,监听9515端口作为remote_s ...

  10. po'j2559 Largest Rectangle in a Histogram 单调栈(递增)

    Largest Rectangle in a Histogram Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29498 ...