go socket 实现聊天室功能

go socket 实现聊天室功能,第1张

首先,简单介绍一下socket:

Socket是BSD UNIX的进程通信机制,通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。Socket可以理解为TCP/IP网络的API,它定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。电脑上运行的应用程序通常通过”套接字”向网络发出请求或者应答网络请求。

TCP服务端处理流程主要为:

1.监听端口
2.接收客户端请求建立链接
3.创建goroutine处理链接。

下面使用go+socket

服务器端:

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

//创建结构体存储用户名称、信息和时间
type chatMsg struct {
	name string
	msg  string
	t    string
}

var (
	msg      = make(chan string)  //用于新用户加入时广播信息
	chatMsgs = make(chan chatMsg) //发送聊天信息
	exit     = make(chan chatMsg) //离开信息
)

func main() {
	conn, err := net.Listen("tcp", "127.0.0.1:9090") //监听本机9090端口
	if err != nil {
		log.Fatal(err)
	}
	clients := make(map[string]net.Conn) //定义一个map,使用用户名作为key,value该用户的链接
	go func() {                          //开启一个线程,不断地从通道中读取数据
		for {
			select {
			case chat := <-chatMsgs: //有用户发送消息
				for name, accept := range clients {
					if name == chat.name { //当发送者是本人
						fmt.Fprintln(accept, chat.t+" 你说:"+chat.msg)
					} else {
						fmt.Fprintln(accept, chat.t+" "+chat.name+" 说:"+chat.msg)
					}

				}
			case exitMsg := <-exit: //有用户离开了
				for name, accept := range clients {
					if name == exitMsg.name {
						accept.Write([]byte("exit"))
					} else {
						fmt.Fprintln(accept, "<"+exitMsg.msg+">")
					}
				}
				delete(clients, exitMsg.name)
			case m := <-msg: //上线
				for _, accept := range clients {
					fmt.Fprintln(accept, m)
				}
			}
		}
	}()

	for { //循环读取客户端接入
		accept, err := conn.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go func() {
			client := accept.RemoteAddr().String()                                        //客户端地址
			name := "无名小辈" + client[strings.LastIndex(client, ":")+1:len([]rune(client))] //使用端口号作为名称后缀
			clients[name] = accept                                                        //将用户存入map
			msg <- "<" + name + "已经加入群英荟" + ">"
			input := bufio.NewScanner(accept)
			for input.Scan() { //循环读取客户端控制台输入内容
				text := input.Text()
				if text == "exit" { //客户端输入"exit"消息时,退出聊天室
					exit <- chatMsg{name, "退出会场,青山不改绿水长流,各位有缘再见!", ""}
					break //跳出循环读取
				} else {
					t := time.Now()                                                    //获取当前时间
					chat := chatMsg{name, input.Text(), t.Format("02 Jan 2006 15:04")} //格式化时间
					chatMsgs <- chat
				}

			}
		}()
	}
}

客户端:

package main

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

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:9090") //建立网络连接
	if err != nil {
		log.Fatal(err)
	}

	defer conn.Close()
	//获取服务端消息
	go ioCopy(os.Stdout, conn)
	go func() { //开启一个线程,不断读取服务端传递的信息
		for {
			buf := make([]byte, 1024)
			n, _ := conn.Read(buf)
			if n > 0 {
				if strings.Count(string(buf[0:n]), "exit") == 1{
					fmt.Print("告辞")
					conn.Close()
					os.Exit(0) //退出
				} else {
					fmt.Print(string(buf[0:n]))
				}
			}
		}
	}()
	//将用户输入的文本消息发送到到服务端
	ioCopy(conn, os.Stdin)
}

func ioCopy(w io.Writer, r io.Reader) {
	if _, err := io.Copy(w, r); err != nil {
		log.Fatal(err)
	}
}

首先启动服务端进程,再启动客户端,效果图如下。

启动服务:

 客户端接入:

 群聊:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/995692.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存