This is a creation in Article, where the information may have evolved or changed.
Beginner go less than two weeks, in line with the goal of familiar with the language to write this small program, a lot of loopholes, the implementation of the written also some slag, welcome to read the guidance.
Download Address: Https://github.com/yinxin630/gochat
Simple idea Description:
0, the service side listens to the client request, completes the session to forward the task
1, the service side uses the heartbeat package to maintain the user online status
2, the client notifies the service side of its own listening address, create server-client information channel
Service side:
Package Mainimport ("FMT", "net", "OS" "StrConv" "Time")//user information type username struct {userName string useraddr *net. Udpaddr Userlistenconn *net. Udpconn Chattoconn *net. udpconn}//Server listener Port Const LISTENPORT = 1616//Buffer Const BUFFSIZE = 1024var buff = make ([]byte, Buffsize)//online user var onlineuser = Make ([]user, 0)//Online status judgment buffer var onlinecheckaddr = make ([]*net. UDPADDR, 0)//error handling Func HandleError (err error) {if err! = Nil {fmt. Println (Err. Error ()) OS. Exit (2)}}//Message processing func handlemessage (Udplistener *net. Udpconn) {n, addr, err: = UDPLISTENER.READFROMUDP (Buff) HandleError (err) if n > 0 {msg: = Analyzemessage (buff, n) switch m Sg[0] {//connection information case "Connect"://Get nickname + Port username: = Msg[1]userlistenport: = msg[2]//Get user ipip: = analyzemessage ([]byte ( Addr. String ()), Len (addr. String ())//Display login information FMT. Println ("nickname:", UserName, "Address:", ip[0], "User listening port:", Userlistenport, "Login successful!" ")//Create a connection to the user for message forwarding useraddr, err: = Net. RESOLVEUDPADDR ("UDP4", Ip[0] + ":" + userlistenport) HandleError (err) userconn, err: = Net. DIALUDP ("UDP4", Nil, useraddr) HAndleerror (ERR)//Because the connection is to be used continuously, the connection cannot be closed here//defer userconn.close ()//Add to Online User Onlineuser = append (Onlineuser, User{username , addr, userconn, nil}) case "online"://Received heartbeat packet onlinecheckaddr = append (onlinecheckaddr, addr) case "outline"://Exit message, not implemented C ASE "chat"://Session request//Find Request Object Index: = -1for I: = 0; I < Len (onlineuser); i++ {if onlineuser[i].username = = msg[1] {index = i}}//adds the connection of the requested object to the requestor if index! =-1 {nowuser, _: = Finduser (addr) Onlineu Ser[nowuser].chattoconn = Onlineuser[index].userlistenconn}case "get"://Return online user information to the requestor index, _: = Finduser (addr) Online User[index].userlistenconn.write ([]byte ("Current Total" + StrConv. Itoa (Len (onlineuser)) + "bit user online")) for I, V: = Range Onlineuser {onlineuser[index].userlistenconn.write ([]byte ("" + StrConv. Itoa (i + 1) + ":" + v.username))}default://message forwarding//Get current User index, _: = Finduser (addr)//Get time nowtime: = times. Now () Nowhour: = StrConv. Itoa (Nowtime.hour ()) Nowminute: = StrConv. Itoa (Nowtime.minute ()) Nowsecond: = StrConv. Itoa (Nowtime.second ())//Request Session object for presence if Onlineuser[index].chattoconn = = Nil {onlineuser[index].userlistenconn.write ([]byte ("The other is not online")} else {Onlineuser[index]. Chattoconn.write ([]byte (Onlineuser[index].username + "+ nowhour +": "+ Nowminute +": "+ Nowsecond +" \ n "+ Msg[0])}} }}//message parsing, []byte, []stringfunc analyzemessage (Buff []byte, Len Int) ([]string) {analmsg: = make ([]string, 0) Strnow: = "For I: = 0; i < Len; i++ {if string (buff[i:i + 1]) = = ":" {analmsg = append (analmsg, strnow) Strnow = "} else {Strnow + = string (buff[i:i + 1])} }analmsg = Append (analmsg, Strnow) return analmsg}//look for the user, return (location, presence) func Finduser (addr *net. UDPADDR) (int, bool) {alreadyhave: = Falseindex: = -1for I: = 0; i < len (onlineuser); i++ {if onlineuser[i].useraddr.st Ring () = = addr. String () {alreadyhave = Trueindex = Ibreak}}return Index, alreadyhave}//handles the user's online information (temporarily only for deletion of the user) Func handleonlinemessage ( Addr *net. UDPADDR, state bool) {index, Alreadyhave: = Finduser (addr) if state = = False {if Alreadyhave {onlineuser = append (onlineuse R[:index], Onlineuser[index + 1:len (Onlineuser)] ...) }}}//online judgment, heartbeat packet processing, every 5s view once all online user status Func Onlinecheck () {for {onlinecheckaddr = make ([]*net. UDPADDR, 0) Sleeptimer: = time. Newtimer (time. Second * 5) <-sleeptimer.cfor I: = 0; I < Len (onlineuser); i++ {haved: = falseforin:for J: = 0; J < Len (onlinecheckaddr); J + + {if onlineuser[i].useraddr.string () = = Onlinecheckad DR[J]. String () {haved = Truebreak forin}}if!haved {fmt. Println (onlineuser[i].useraddr.string () + "Exit! ") Handleonlinemessage (Onlineuser[i].useraddr, False) I--}}}}func main () {//Listener address udpaddr, err: = Net. RESOLVEUDPADDR ("Udp4", "127.0.0.1:" + StrConv. Itoa (Listenport)) HandleError (ERR)//Listener connection Udplistener, err: = Net. LISTENUDP ("UDP4", udpaddr) HandleError (ERR) defer udplistener.close () fmt. PRINTLN ("Start monitoring:")//Online Status judgment Go Onlinecheck () for {//Message processing handlemessage (Udplistener)}}
Client:
Package Mainimport ("FMT" "OS" "StrConv" "Net" "Bufio" "Math/rand" "Time")//header, identifying data contents var reflectstring = map[string] string {"Connection": "Connect:", "online": "Line:", "chat": "Chat:", "Online user": "Get:",}//server port const CLIENTPORT = 1616//Data Slow Flush Zone Const BUFFSIZE = 1024var buff = make ([]byte, Buffsize)//error message handling func HandleError (err error) {if err! = Nil {fmt. Println (Err. Error ()) OS. Exit (2)}}//sends the message func SendMessage (Udpconn *net. Udpconn) {scaner: = Bufio. Newscanner (OS. Stdin) for Scaner. Scan () {if Scaner. Text () = = "Exit" {Return}udpconn.write ([]byte (Scaner. Text ()))}}//receives the message func handlemessage (Udplistener *net. Udpconn) {for {n, _, Err: = UDPLISTENER.READFROMUDP (Buff) HandleError (err) if n > 0 {fmt. Println (String (Buff[:n]))}}}/*func analyzemessage (Buff []byte, Len Int) ([]string) {analmsg: = make ([]string, 0) St Rnow: = "" For I: = 0; i < Len; i++ {if string (buff[i:i + 1]) = = ":" {analmsg = append (analmsg, strnow) Strnow = "" } else {Strnow + = StriNg (buff[i:i + 1])}} analmsg = Append (analmsg, strnow) return analmsg}*///send Heartbeat packet func sendonlinemessage (UDP Conn *net. Udpconn) {for {//per interval 1s sends an online message to the server Udpconn.write ([]byte (reflectstring["online])) Sleeptimer: = time. Newtimer (time. Second) <-Sleeptimer.c}}func Main () {//judgment command line arguments, the parameters should be server Ipif len (OS). Args)! = 2 {fmt. PRINTLN ("program command line parameter Error! ") OS. Exit (2)}//get iphost: = OS. ARGS[1]//UDP address udpaddr, err: = Net. RESOLVEUDPADDR ("UDP4", Host + ":" + StrConv. Itoa (ClientPort)) HandleError (ERR)//UDP connection udpconn, err: = Net. DIALUDP ("UDP4", Nil, udpaddr) HandleError (ERR)//local listener port newseed: = Rand. Newsource (Int64 (time. Now (). Second ())) Newrand: = Rand. New (newseed) Randport: = Newrand.intn (30000) + 10000//local listener UDP address udplocaladdr, err: = Net. RESOLVEUDPADDR ("Udp4", "127.0.0.1:" + StrConv. Itoa (Randport)) HandleError (ERR)//local listener UDP connection Udplistener, err: = Net. LISTENUDP ("UDP4", udplocaladdr) HandleError (err)//fmt. Println ("Listening", Randport, "port")//user nickname Username: = "" FMT. Printf ("Please enter a nickname:") fmt. SCANF ("%s", &username)//Send connection information to the server (Nickname + Local listener Port) udpconn.write ([]byte (reflectstring["Connection"] + userName + ":" + StrConv. Itoa (Randport))//Close Port defer udpconn.close () defer udplistener.close ()//Send heartbeat packet Go sendonlinemessage (udpconn)//Receive Message Go Handlemessage (udplistener) Command: = "" For {//Get command FMT. SCANF ("%s", &command) switch command {case "chat":p eople: = ""//fmt. Printf ("Please enter the nickname:") fmt. SCANF ("%s", &people)//Send Chat object information to the server Udpconn.write ([]byte (reflectstring["chat"] + people)//Enter session SendMessage ( Udpconn)//exit session FMT. Println ("Exit with" + people + "session") Case "get"://Request Online situation information Udpconn.write ([]byte (reflectstring["online user"])}}}
Operating Environment: Local multi-terminal simulation operation
Operation diagram:
Service side:
Client:
User one:
User two:
User three: