目前字符串无法加入空格,如果想添加的话,在客户端把空格处理成特殊字符处理。
文件名为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])
}
}