版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33781658/article/details/84574813
go并发聊天室
我们先来写简单的listen和conn
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("监听器创建失败...")
return
}
defer listener.Close()
fmt.Println("监听器创建成功...")
go boardcaster()
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("连接失败...")
continue
}
defer conn.Close()
go handler(conn)
}
}
func handler(conn net.Conn) {
addr := conn.RemoteAddr()
fmt.Println(addr, "连接成功...")
}
func boardcaster() {
fmt.Println("广播器正在运行...")
}
这是我们的聊天室的基本架构
然后我们完善一下broadcaster()方法
和handler()方法
func main() {
//创建监听器
listener, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("创建监听器失败...")
return
}
defer listener.Close()
fmt.Println("创建监听器成功...")
//启动广播
go broadcaster()
//循环创建连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("连接失败...")
continue
}
defer conn.Close()
//处理conn连接
handler(conn)
}
}
func handler(conn net.Conn) {
//获取addr
addr := conn.RemoteAddr().String()
fmt.Println(addr, "连接...")
//创建client对象
channel := make(chan string)
cli := Client{addr, addr, channel}
//输出msg
go clientWriter(conn, cli.channel)
//显示连接,发送消息,加入map
cli.channel <- addr + " welcome"
messages <- addr + " has arrived"
entering <- cli
//创建channel控制时间
hasData := make(chan struct{})
go func() {
for {
select {
case <-hasData:
case <-time.After(20 * time.Second):
conn.Close()
}
}
}()
//循环输入
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
//发送时间channel消息
hasData <- struct{}{}
//扫描输入
text := scanner.Text()
if text == "#list" {
list <- cli
} else if len(text) > 8 && text[0:8] == "#rename|" {
cli.name = text[8:]
rename <- cli
} else {
messages <- cli.name + " : " + text
}
}
//断开连接
leaving <- cli
messages <- cli.name + "has left"
}
//输出msg
func clientWriter(conn net.Conn, channel chan string) {
for msg := range channel {
fmt.Fprintln(conn, msg)
}
}
//启动广播
func broadcaster() {
//创建map
clients := make(map[string]Client)
//select监听
for {
select {
case cli := <-entering:
clients[cli.addr] = cli
case cli := <-leaving:
delete(clients, cli.addr)
case msg := <-messages:
for _, cli := range clients {
cli.channel <- msg
}
case cli := <-list:
for _, v := range clients {
cli.channel <- v.name
}
case cli := <-rename:
clients[cli.addr] = cli
}
}
}
//Client结构体
type Client struct {
name string
addr string
channel chan string
}
//创建channel通道
var entering = make(chan Client)
var leaving = make(chan Client)
var messages = make(chan string)
var list = make(chan Client)
var rename = make(chan Client)