首先,简单介绍一下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)
}
}
首先启动服务端进程,再启动客户端,效果图如下。
启动服务:
客户端接入:
群聊:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)