1聊天室服務(wù)器端
專注于為中小企業(yè)提供做網(wǎng)站、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)南昌免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
package?main import?( ????"fmt" ????"net" ????"strings" ????"time" ) //定義的此結(jié)構(gòu)體為全局map的value值,包括每一個(gè)用戶的姓名,ip地址和私人管道 type?client?struct?{ ????name?string ????addr?string ????C????chan?string } /*這個(gè)函數(shù)是將私人管道中的內(nèi)容發(fā)送給用戶,配合全局管道Message使用可以實(shí)現(xiàn)廣播的功能, 單獨(dú)使用可以實(shí)現(xiàn)私聊的功能*/ func?writemsg2client(clinet?client,?conn?net.Conn)?{ ????for?m?:=?range?clinet.C?{ ????????conn.Write([]byte(m?+?"\n")) ????} } //這只是一個(gè)封裝好用來(lái)統(tǒng)一(發(fā)送信息格式)的小函數(shù),不用在意 func?makemsg(name?string,?addr?string,?s?string)?string?{ ????return?"["?+?addr?+?"]"?+?name?+?":"?+?s } //每一個(gè)進(jìn)入聊天室的用戶都將啟動(dòng)一個(gè)handleconn的go程來(lái)處理事件 func?handleconn(conn?net.Conn)?{ ????defer?conn.Close() ????/*用戶連接進(jìn)來(lái)以后要初始化全局map,把自己的信息加入到字典里,相當(dāng)于進(jìn)到聊天室里之前要登 ??????記一下個(gè)人信息,注意姓名初始為ip地址。*/ ????addr?:=?conn.RemoteAddr().String() ????fmt.Printf("用戶%s進(jìn)入了房間\n",?addr) ????client?:=?client{addr,?addr,?make(chan?string)} ????//在這里啟動(dòng)子go程,功能上面已經(jīng)提及,具體就是會(huì)寫信息給自己連接的客戶端 ????go?writemsg2client(client,?conn) ????onlinemap[addr]?=?client ????//登錄進(jìn)來(lái)一切準(zhǔn)備就緒后就給所有人廣播上線信息啦 ????Message?<-?makemsg(client.name,?addr,?"login") ????//下面這三個(gè)變量服務(wù)于下面一些小功能 ????var?haschat?=?make(chan?bool) ????var?ifquit?=?make(chan?bool) ????var?flag?bool ????//從這單獨(dú)開啟一個(gè)go程來(lái)讀取用戶輸入的信息 ????go?func()?{ ????????buf?:=?make([]byte,?4096) ????????for?{ ????????????n,?_?:=?conn.Read(buf) ????????????if?n?==?0?{ ????????????????fmt.Printf("%s離開了房間\n",?client.name) ????????????????ifquit?<-?true ????????????????return ????????????} ????????????//改名功能的實(shí)現(xiàn) ????????????if?string(buf[:7])?==?"Rename|"?{ ????????????????client.name?=?strings.Split(string(buf[:n]),?"|")[1] ????????????????onlinemap[addr]?=?client ????????????????conn.Write([]byte("rename?success\n")) ????????????}?else?if?string(buf[:n-1])?==?"/who"?{ ????????????????//查詢?cè)诰€用戶信息的功能 ????????????????for?_,?s?:=?range?onlinemap?{ ????????????????????conn.Write([]byte(s.name?+?"online\n")) ????????????????} ????????????}?else?if?string(buf[:2])?==?"m|"?&&?strings.Count(string(buf[:n]),?"|")?==?2?{ ????????????????/*私聊功能的實(shí)現(xiàn),其實(shí)私聊功能就是跳過(guò)了往全局Message里傳輸信息, ??????????????????改為直接向私人管道里傳輸信息*/ ????????????????flag?=?true ????????????????slice?:=?strings.Split(string(buf[:n]),?"|") ????????????????fmt.Println(slice[1]) ????????????????for?_,?a?:=?range?onlinemap?{ ????????????????????//遍歷所有在線用戶,向指定的用戶管道中發(fā)送信息 ????????????????????if?a.name?==?slice[1]?{ ????????????????????????flag?=?false ????????????????????????a.C?<-?makemsg(client.name,?addr,?slice[2]) ????????????????????????conn.Write([]byte("send?success")) ????????????????????} ????????????????} ????????????????if?flag?{ ????????????????????conn.Write([]byte("no?such?man?or?not?online")) ????????????????} ????????????}?else?{ ????????????????Message?<-?makemsg(client.name,?addr,?string(buf[:n])) ????????????} ????????????haschat?<-?true ????????} ????}() ????for?{ ????????select?{ ????????case?<-haschat: ????????//超時(shí)強(qiáng)踢 ????????case?<-time.After(time.Minute?*?100): ????????????delete(onlinemap,?addr) ????????????Message?<-?makemsg(client.name,?addr,?"out?time?to?leave") ????????????close(client.C) ????????????return ????????case?<-ifquit: ????????????//退出處理 ????????????delete(onlinemap,?addr) ????????????Message?<-?makemsg(client.name,?addr,?"out?time?to?leave") ????????????close(client.C) ????????????return ????????} ????} } //這個(gè)函數(shù)用來(lái)將全局Message中的內(nèi)容全部塞到私人管道C里,實(shí)現(xiàn)上下線廣播和群聊的功能 func?Manager()?{ ????for?{ ????????msg?:=?<-Message ????????for?_,?s?:=?range?onlinemap?{ ????????????s.C?<-?msg ????????} ????} } var?Message?=?make(chan?string) var?onlinemap?map[string]client?=?make(map[string]client) //主函數(shù) func?main()?{ ????listener,?_?:=?net.Listen("tcp",?"127.0.0.1:9876") ????defer?listener.Close() ????//提前開啟全局Message的go程,防止被阻塞 ????go?Manager() ????for?{ ????????conn,?err?:=?listener.Accept() ????????if?err?!=?nil?{ ????????????fmt.Println("accept?err",?err) ????????????continue ????????} ????????//每一個(gè)連接進(jìn)來(lái)的用戶都會(huì)被分配進(jìn)入一個(gè)子go程,用來(lái)處理上面我們提到的各種功能 ????????go?handleconn(conn) ????} } /*備注 1、??listener,?_?:=?net.Listen("tcp",?"127.0.0.1:9876") 監(jiān)聽(tīng)啟動(dòng) 2、??go?Manager()開啟全局Message的go程,防止被阻塞,沒(méi)有消息便被阻塞,有消息便會(huì)被喚起, 消息發(fā)送完畢后重新等待消息,有消息變發(fā)送沒(méi)消息便阻塞等待(Message?是一個(gè)字符串channel?)。 接收到消息后,遍歷所有在線人員,并把消息發(fā)送給client的私人通道。 func?Manager()?{ ????for?{ ????????msg?:=?<-Message ????????for?_,?s?:=?range?onlinemap?{ ????????????s.C?<-?msg ????????} ????} } 3、私人通道消息處理 這個(gè)函數(shù)是將私人管道中的內(nèi)容發(fā)送給用戶,配合全局管道Message使用可以實(shí)現(xiàn)廣播的功能。 單獨(dú)使用可以實(shí)現(xiàn)私聊的功能(m|客戶端連接ip加端口|發(fā)送消息)(m|127.0.0.1:59700|hello)。 這個(gè)函數(shù)也是等待消息,收到消息后被喚醒執(zhí)行,消息執(zhí)行完畢后等待新消息,沒(méi)有阻塞,有就處理 func?writemsg2client(clinet?client,?conn?net.Conn)?{ ????for?m?:=?range?clinet.C?{ ????????conn.Write([]byte(m?+?"\n")) ????} } */
2、聊天室客戶端
package?main import?( ????"bufio" ????"fmt" ????"net" ????"os" ????"strings" ) func?readFromServer(conn?net.Conn)?{ ????buf?:=?make([]byte,?4096) ????for?{ ????????n,?err?:=?conn.Read(buf) ????????if?err?!=?nil?{ ????????????fmt.Println(err) ????????????os.Exit(1) ????????} ????????defer?conn.Close() ????????fmt.Println("接收到消息:",?string(buf[:n])) ????????fmt.Println("請(qǐng)輸入要發(fā)送的消息:") ????} } func?main()?{ ????conn,?err?:=?net.Dial("tcp",?"127.0.0.1:9876") ????if?err?!=?nil?{ ????????fmt.Println(err) ????????return ????} ????defer?conn.Close() ????go?readFromServer(conn) ????//fmt.Println("請(qǐng)輸入要發(fā)送的消息:") ????for?{ ????????//strs?:="" ????????//?fmt.Scanln(&strs)?空格有問(wèn)題 ????????//strs?:=?make([]byte,?4096) ????????//n,?err?:=?os.Stdin.Read(strs) ????????str,?err?:=?bufio.NewReader(os.Stdin).ReadString('\n') ????????if?err?!=?nil?{ ????????????fmt.Println(err) ????????} ????????str?=?strings.TrimSpace(str) ????????//fmt.Println("發(fā)送前",?,?"展示") ????????//fmt.Println("a",?str,?"b") ????????if?str?==?"Q"?{ ????????????fmt.Println("接收到退出命令,退出客戶端") ????????????break ????????} ????????conn.Write([]byte(str)) ????} }