package chat
import (
"fmt"
"io"
"log"
"net"
"strings"
"time"
)
var serverList map [ string ] net. Conn = make ( map [ string ] net. Conn)
func Server ( host string ) {
log. Printf ( "启动【柠檬】程序\n" )
log. Printf ( "server info:%s\n" , host)
server, err := net. Listen ( "tcp" , host)
if err != nil {
log. Fatalf ( "启动聊天室服务失败:%v\n" , err)
return
}
for {
conn, err := server. Accept ( )
if err != nil {
log. Fatalf ( "获取客户端连接失败:%v\n" , err)
continue
}
memberName := register ( conn)
if memberName != "" {
go process ( memberName)
}
}
}
func process ( memberName string ) {
broadcastMsg ( "sys" , "【" + memberName+ "】上线了" )
for {
read ( memberName)
}
}
func broadcastMsg ( memberName string , msg string ) {
for key, conn := range serverList{
if key != memberName{
go send ( conn, memberName, msg)
}
}
}
func send ( conn net. Conn, key string , msg string ) {
if msg != "" {
_ , err := io. WriteString ( conn, key+ "(" + time. Now ( ) . Format ( "06/01/02 15:04:05" ) + "): " + msg)
if err != nil {
fmt. Printf ( "向客户【%s】端广播消息失败:%v\n" , key, err)
delete ( serverList, key)
conn. Close ( )
}
}
}
func onlineList ( memberName string ) {
var onlines string
for key, _ := range serverList{
onlines += key
onlines += "\n"
}
if onlines == "" {
onlines = memberName+ "\n"
}
conn, ok := serverList[ memberName]
if ok {
_ , err := io. WriteString ( conn, "sys(" + time. Now ( ) . Format ( "06/01/02 15:04:05" ) + "): \n" + onlines)
if err != nil {
fmt. Printf ( "向客户【%s】发送消息失败:%v\n" , memberName, err)
delete ( serverList, memberName)
conn. Close ( )
}
}
}
func read ( memberName string ) {
var dataBuf [ 1024 ] byte
conn, ok := serverList[ memberName]
if ok {
n, err := conn. Read ( dataBuf[ : ] )
if err != nil && err != io. EOF {
log. Fatalf ( "From %s failed:%v\n" , err, conn. RemoteAddr ( ) . String ( ) )
delete ( serverList, memberName)
} else {
msg := string ( dataBuf[ : n] )
if msg == "#quit" {
log. Printf ( "%s 退出了聊天室\n" , memberName)
broadcastMsg ( "sys" , "【" + memberName+ "】退出了聊天室" )
conn. Close ( )
delete ( serverList, memberName)
return
} else if msg == "#list" {
onlineList ( memberName)
}
if msg != "" {
broadcastMsg ( memberName, msg)
log. Printf ( "【%s】from %s >> %s\n" , memberName, conn. RemoteAddr ( ) . String ( ) , msg)
}
}
}
}
func register ( conn net. Conn) string {
var memberName string
var buf [ 1024 ] byte
count, err := conn. Read ( buf[ : ] )
if err != nil {
log. Fatalf ( "获取客户端注册失败:%v\n" , err)
conn. Close ( )
return ""
}
memberName = strings. TrimSpace ( string ( buf[ : count] ) )
if memberName != "" {
_ , ok := serverList[ memberName]
if ! ok {
log. Printf ( "注册成功信息【%s】%s\n" , memberName, conn. RemoteAddr ( ) . String ( ) )
serverList[ memberName] = conn
_ , _ = io. WriteString ( conn, "1" )
} else {
log. Printf ( "注册信息已经存在【%s】%s\n" , memberName, conn. RemoteAddr ( ) . String ( ) )
_ , _ = io. WriteString ( conn, "2" )
}
}
return memberName
}
package chat
import (
"bufio"
"fmt"
"io"
"log"
"net"
"os"
"strings"
"sync"
"time"
)
var wg sync. WaitGroup
var registerName string
func sendRegister ( reader * bufio. Reader, client net. Conn) bool {
fmt. Print ( "注册名: " )
name, err := reader. ReadString ( '\n' )
registerName = name
registerName = strings. Replace ( registerName, "\n" , "" , - 1 )
if err != nil {
log. Fatalf ( "获取注册名失败:%v,请重新登录注册" , err)
return false
}
_ , _ = io. WriteString ( client, strings. TrimSpace ( registerName) )
var buf [ 256 ] byte
n, err := client. Read ( buf[ : ] )
if err != nil {
log. Fatalf ( "获取服务器注册返回状态失败:%v\n" , err)
return false
}
codeStr := string ( buf[ : n] )
if codeStr == "1" {
fmt. Printf ( "【%s】注册成功\n" , registerName)
return true
} else if codeStr == "2" {
fmt. Printf ( "【%s】注册信息已经存在,请重新选择一个名称来注册\n" , registerName)
return false
}
return false
}
func receiveMsg ( conn net. Conn) {
defer wg. Done ( )
for {
var buf [ 512 ] byte
n, err := conn. Read ( buf[ : ] )
if err != nil && io. EOF != err {
log. Fatalf ( "从服务器读取消息失败:%v\n" , err)
conn. Close ( )
wg. Done ( )
}
msg := string ( buf[ : n] )
if msg != "" {
fmt. Printf ( "\n%s\n" , msg)
fmt. Printf ( "%s: " , registerName)
}
}
}
func inputMsg ( client net. Conn, reader * bufio. Reader) {
defer wg. Done ( )
for {
consMsg, err := reader. ReadString ( '\n' )
consMsg = strings. Replace ( consMsg, "\n" , "" , - 1 )
_ , err = io. WriteString ( client, consMsg)
if err != nil {
wg. Done ( )
log. Fatalf ( "向服务器发送消息失败:%v\n" , err)
} else {
fmt. Printf ( "%s: " , registerName)
}
if consMsg == "#quit" {
fmt. Println ( "退出聊室" )
client. Close ( )
}
}
}
func Client ( host string ) {
log. Printf ( "与【柠檬】聊天室建立连接" )
log. Printf ( "服务器信息:%s\n" , host)
client, err := net. Dial ( "tcp" , host)
if err != nil {
log. Fatalf ( "与服务器建立连接失败:%v\n" , err)
client. Close ( )
return
}
wg. Add ( 2 )
reader := bufio. NewReader ( os. Stdin)
if ! sendRegister ( reader, client) {
return
}
time. Sleep ( 5 * time. Second)
time. Sleep ( 500 * time. Millisecond)
fmt. Printf ( "%s: " , registerName)
go inputMsg ( client, reader)
time. Sleep ( 500 * time. Millisecond)
go receiveMsg ( client)
wg. Wait ( )
}
测试结果
go run ServerMain. go
2020 / 04 / 22 14 : 54 : 34 启动【柠檬】程序
2020 / 04 / 22 14 : 54 : 34 server info: 0.0 .0 .0 : 60007
2020 / 04 / 22 14 : 56 : 47 注册成功信息【tom】127.0 .0 .1 : 49745
2020 / 04 / 22 14 : 57 : 59 注册成功信息【lisa】127.0 .0 .1 : 49758
2020 / 04 / 22 14 : 58 : 56 注册成功信息【yu】127.0 .0 .1 : 49769
2020 / 04 / 22 14 : 56 : 32 与【柠檬】聊天室建立连接
2020 / 04 / 22 14 : 56 : 32 服务器信息: 127.0 .0 .1 : 60007
注册名: tom
【tom】注册成功
tom:
sys ( 20 / 04 / 22 14 : 56 : 47 ) : 【tom】上线了
tom:
sys ( 20 / 04 / 22 14 : 57 : 59 ) : 【lisa】上线了
tom:
sys ( 20 / 04 / 22 14 : 58 : 56 ) : 【yu】上线了
tom
Jackm1688sMacBook- Air: chatMain JackMeng$ go run ClientMain. go
2020 / 04 / 22 14 : 57 : 50 与【柠檬】聊天室建立连接
2020 / 04 / 22 14 : 57 : 50 服务器信息: 127.0 .0 .1 : 60007
注册名: lisa
【lisa】注册成功
lisa:
sys ( 20 / 04 / 22 14 : 57 : 59 ) : 【lisa】上线了
lisa:
sys ( 20 / 04 / 22 14 : 58 : 56 ) : 【yu】上线了
lisa: #list
lisa:
sys ( 20 / 04 / 22 15 : 05 : 14 ) :
tom
lisa
yu
lisa: