这个是自己做了一点修改,如果是原版的方法,客户端在字符串中添加空格的时候,那个方法scanln会自动分割空格两端的字符串,从而错乱,所以改了这个版本(就是客户端在想服务端的通道出入数据的时候的一点修改),初学炸到,不喜勿喷
package main
import (
"bufio"
"fmt"
"net"
"os"
)
/**
主程序 启动客户端和服务端
参数说明:
启动服务器端: go run main.go server [port] eg: go run main.go server 9090
启动客户端: go run main.go [Server Ip Addr]:[Server Port] eg: go run main.go client :9090
*/
func main() {
if len(os.Args) != 3 {
fmt.Println("wrong params")
os.Exit(0)
}
if os.Args[1] == "server" {
StartServer(os.Args[2])
}
if os.Args[1] == "client" {
StartClient(os.Args[2])
}
}
/**
启动服务器
参数:port 端口号
*/
func StartServer(port string) {
service := ":" + port
tcpAddr,err := net.ResolveTCPAddr("tcp4", service)
checkError(err, "ResolveTCPAddr")
l,err := net.ListenTCP("tcp", tcpAddr)
checkError(err ,"ListenTCP")
conns := make(map[string]net.Conn)
messages := make(chan string, 10)
//启动服务器广播线程 :向所有客户端发送消息
go echoHandler(&conns, messages)
for {
fmt.Println("Listening ...")
conn,err := l.Accept()//返回一个新的连接
checkError(err , "l.Accept")
fmt.Println("Accepting ...")
conns[conn.RemoteAddr().String()] = conn
//启动一个接受客户端发送消息的线程
go Handler(conn, messages)
}
}
/**
服务器发送数据的线程:向所有客户端发送消息
参数
连接字典 conns
数据通道 messages
*/
func echoHandler(conns *map[string]net.Conn, messages chan string) {
for {
//向通道中传入数据
msg := <-messages
fmt.Println(msg)
for key,con := range *conns {
fmt.Println("connection is connected from ...", key)
_,err := con.Write([]byte(msg))
if err != nil {
fmt.Println(err)
delete(*conns, key)
}
}
}
}
/**
服务器端接收客户端数据线程
参数:
据连接 conn
通讯通道 messages
*/
func Handler(conn net.Conn, messages chan string) {
fmt.Println("connection is connected from ...", conn.RemoteAddr().String())
buf := make([]byte, 1024)
for {
lenght,err := conn.Read(buf)
if checkError(err, "Connection") == false {
conn.Close()
break
}
if lenght >0 {
buf[lenght] = 0
}
reciveStr := string(buf[0:lenght])
messages <- reciveStr
}
}
/**
客户端启动函数
参数:
程ip地址和端口 tcpaddr
*/
func StartClient(tcpaddr string) {
tcpAddr,err := net.ResolveTCPAddr("tcp4", tcpaddr)
checkError(err, "ResolveTCPAddr")
conn,err := net.DialTCP("tcp",nil,tcpAddr)
checkError(err, "DialTCP")
//启动客户端发送数据线程
go chatSend(conn)
//接收服务端发送来的消息
buf := make([]byte, 1024)
for {
lenght,err := conn.Read(buf)
if checkError(err, "Connection") == false {
conn.Close()
fmt.Println("Server is dead ...ByeBye")
os.Exit(0)
}
fmt.Println(string(buf[0:lenght]))
}
}
/**
客户端发送数据线程
参数:
发送连接 conn
*/
func chatSend(conn net.Conn) {
//var input string
username := conn.LocalAddr().String()
inputReader := bufio.NewReader(os.Stdin)
index := 0
for {
//fmt.Scanln(&input)
//这个地方改为回车结束判断,利用上面的输入检测,会有问题(不知道如何表述,就是会出现错乱)
input, err := inputReader.ReadString('\n')
//fmt.Fscan(stdin, &input)
if input == "/quit" {
fmt.Println("ByeBye..")
conn.Close()
os.Exit(0)
}
lens,err := conn.Write([]byte(username + "say ::: " + input))
//这个地方lens不能缺省,不知道为什么
if lens == 0 {
//
}
if err != nil {
fmt.Println(err.Error())
conn.Close()
}
index++
}
}
//错误信息
func checkError(err error, info string) (res bool) {
if err != nil {
fmt.Println(info + ",err:" + err.Error())
return false
}
return true
}
这个是自己做了一点修改,如果是原版的方法,客户端在字符串中添加空格的时候,那个方法scanln会自动分割空格两端的字符串,从而错乱,所以改了这个版本(就是客户端在想服务端的通道出入数据的时候的一点修改),初学炸到,不喜勿喷