服务端:
//聊天服务端
/******************乞丐版思路(非channel通信)**********************/
// 1.记录每个客户端连接
// 2.返回给每个客户端对应的信息
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
)
var (
clients []net.Conn
)
func main() {
//监控端口
listener, err := net.Listen("tcp", "localhost:8000") //0-1023 系统占用
if err != nil {
log.Fatal(err) //打印监听错误
}
for {
//客户端新链接
conn, err := listener.Accept() //阻塞
if err != nil {
log.Fatal(err)
}
go handleConn(conn) //开启专门协程进行处理,多客户端同时处理
}
}
//处理客户端连接
func handleConn(conn net.Conn) {
//获取当前连接信息
connIP := conn.RemoteAddr().String()
loginInfo := "Your IP:" + connIP + "\n"
yourLoginInofForOther := connIP + " has arrived" + "\n"
fmt.Println(connIP, "login")
logOutInfo := connIP + " has left" + "\n"
//1.记录每个客户端连接,因为后续聊天室要给所有非当前客户端发送消息
clients = append(clients, conn)
//2.返回当前客户端的连接信息 IP,并给所有其他客户端发送当前客户登录名
for _, connOth := range clients {
if connOth != conn {
clientWrite(connOth, yourLoginInofForOther)
}
}
clientWrite(conn, loginInfo)
//3.当前客户端断开连接时,提醒其他客户端信息
//4.监控所有客户端的输入信息,并返回给所有客户端
input := bufio.NewScanner(conn) //此处定义一个扫描器
for input.Scan() { //Scan()方法类似于一个迭代器的next(),只要有连接就会一直返回true
clientInput := connIP + ": " + input.Text() + "\n" //获取客户端连接的输入内容
for _, connOth := range clients {
if connOth != conn {
clientWrite(connOth, clientInput)
}
}
}
//客户端退出连接
clients = clients[0 : len(clients)-1]
for _, connOth := range clients {
clientWrite(connOth, logOutInfo)
}
conn.Close()
}
//写入连接信息
func clientWrite(conn net.Conn, msg string) {
_, err := io.WriteString(conn, msg)
if err != nil {
log.Fatal(err)
}
}
客户端:
package main
import (
"io"
"log"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
//gorountine出口
done := make(chan struct{})
//开启goroutine获取服务端返回信息,并处理
go func() {
mustCopy(os.Stdout, conn)
log.Println("done")
done <- struct{}{}
}()
//客户端的输入,发送到服务端
mustCopy(conn, os.Stdin)
conn.Close()
<-done //阻塞等待 gorountine完成任务
}
//这个程序会从连接中读取数据,并将读到的内容写到标准输出中,直到遇到end of file的条件
// 或者发生错误
func mustCopy(dst io.Writer, src io.Reader) {
if _, err := io.Copy(dst, src); err != nil {
log.Fatal(err)
}
}
这种方式旨在了解最简单的s-c模式的交互通信,遵循循序渐进的原则,管道通信版的聊天室可查看相关博文:多人聊天室【channel通信】