当前位置: 首页 > 工具软件 > blueCat > 使用案例 >

golang 实现聊天室 bluecat‘s chat

施德运
2023-12-01

 目前字符串无法加入空格,如果想添加的话,在客户端把空格处理成特殊字符处理。

文件名为chat.go ,测试方法见注释。

参考:https://blog.csdn.net/ygrx/article/details/11773151

package main

import (
	"fmt"
	"net"
	"os"
)

//客户端连接信息
type client struct {
	name string //客户端昵称
	connect net.Conn//accept返回值
}

//服务器接收的客户端信息 包括收到的字符串和客户端昵称
type rec_ser struct{
	mes string
	name string
}

//异常处理
func checkError(err error) {
	if err!=nil{
		fmt.Fprintf(os.Stderr,"错误:%s",err.Error())
		os.Exit(0)
	}
}

//从客户端接受一个name信息
func receiveName(conn net.Conn)string{
	buf:=make([]byte,1024)
	length,err:=conn.Read(buf)
	checkError(err)
	if length > 0{
		buf[length]=0
	}
	str:=string(buf[0:length])
	return str

}


//服务器实现广播 用指针 需要修改
func broadcastMes(clients *map[string]client,message chan rec_ser){
	for{
		//通过管道通信 获取是否
		mes:=<-message
		//name:=<-names
		fmt.Println(mes.name+":"+mes.mes)
		if len(*clients)==1{
			fmt.Println("there is only one connect in bluecat's chat.")
			for _,v:=range *clients{
				_,err:=v.connect.Write([]byte("there is only one connect in bluecat's chat."))
				checkError(err)
			}
			continue
		}
		for k,v:=range *clients{
			if(v.name!=mes.name){
				fmt.Println("connection is connected from ...",v.name)
				_,err :=v.connect.Write([]byte(mes.name+":"+mes.mes))
				//checkError(err)
				if err!=nil{
					delete(*clients,k)
				}

			}
		}
	}
}

//处理每一个客户端连接任务 循环从客户端连接中获取发来的信息
func handler(user client, message chan rec_ser){
	fmt.Println("connection is connected from ...",user.name)
	buf:=make([]byte,1024)
	for{
		length,err:=user.connect.Read(buf)
		//checkError(err)
		if err!=nil{
			user.connect.Close()
			break
		}
		if length>0{
			buf[length]=0
		}
		str:=string(buf[0:length])
		//通过channel 发送给广播协程
		mes:=rec_ser{
			mes:  str,
			name: user.name,
		}
		message<-mes
		//name<-user.name
	}
}

//启动服务器端
func startServer(port string)  {
	strTCP:="127.0.0.1:"+port
	tcpAddr,err:=net.ResolveTCPAddr("tcp",strTCP)//将字符串解析成tcpaddr 端口和ip
	checkError(err)
	listen,err:=net.ListenTCP("tcp",tcpAddr)//监听有无客户端发起连接
	checkError(err)
	clients:=make(map[string]client)//用map存储客户端集合 key值是客户端连接信息的accept的返回值 value是
	//name:=make(chan string)//告诉广播协程是哪个客户端发的信息 不重复发给自己
	mes:=make(chan rec_ser,10)//通过管道实现广播协程和连接客户端协程的消息交互
	go broadcastMes(&clients,mes)
	for{
		fmt.Println("listening:......")
		con,err:=listen.Accept()
		checkError(err)
		//创建连接信息客户端kv
		clients[con.RemoteAddr().String()]=client{
			name:receiveName(con),
			connect:con,
		}
		go handler(clients[con.RemoteAddr().String()],mes)
	}

}

//向服务器端发送客户端名称
func nameSend(user client){
	_,err:=user.connect.Write([]byte(user.name))
	checkError(err)
}

//在群聊中说话
func say(user client){
	var input string
	//username:=user.name
	for{
		fmt.Scanln(&input)
		if input=="quit"{
			fmt.Println("ByeBye..")
			user.connect.Close()
			os.Exit(0);
		}
		_,err:=user.connect.Write([]byte(input))
		checkError(err)
	}
}

//启动客户端协程
func startClient(tcpaddr string)  {
	tcpAddr,err:=net.ResolveTCPAddr("tcp",tcpaddr)
	checkError(err)
	conn,err:=net.DialTCP("tcp",nil,tcpAddr)
	checkError(err)
	//首先发送姓名到服务端
	var name string
	fmt.Printf("please input your Bluecat Chat's ID:")
   	fmt.Scanln(&name)
	user:=client{
		name:name,
		connect: conn,
	}
	nameSend(user)
	//启动协程向服务端不断发送数据
	go say(user)
	//内存保存他人发送信息
	buf:=make([]byte,1024)
	//从服务端接收数据
	for{
		length,err:=user.connect.Read(buf)
		checkError(err)
		fmt.Println(string(buf[0:length]))
	}
}

//客户端 服务端在一个程序中 通过参数决定具体执行哪个程序
/*
客户端:go run chat.go server 9090
服务器端:go run chat.go client 127.0.0.1:9090
*/
func main(){
	if len(os.Args)!=3{
		fmt.Println("Wrong input")
		os.Exit(0)
	}
	if len(os.Args)==3&&os.Args[1]=="server"{
		startServer(os.Args[2])
	}
	if len(os.Args)==3&&os.Args[1]=="client"{
		startClient(os.Args[2])
	}
}

 

 

 类似资料: