最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

300行代碼實現(xiàn)go語言即時通訊聊天室

 更新時間:2022年05月13日 11:56:41   作者:Ego12138  
本文主要介紹了300行代碼實現(xiàn)go語言即時通訊聊天室,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

學了2年Java,因為工作原因需要轉(zhuǎn)Golang,3天時間學習了下go的基本語法,做這樣一個聊天室小項目來鞏固串聯(lián)一下語法。

實現(xiàn)的功能:公聊,私聊,修改用戶名

只用到了四個類:

  • main.go:用來啟動服務(wù)器
  • server.go:服務(wù)器相關(guān)代碼
  • client.go:客戶端相關(guān)代碼,用戶可以直接操作的可視化界面
  • user.go:用戶類,用來封裝用戶的業(yè)務(wù)邏輯

架構(gòu)圖

完整代碼

server.go

package main

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Server struct {
	Ip   string
	Port int
	//在線用戶列表
	OnlineMap map[string]*User
	mapLock   sync.RWMutex
	//消息廣播的Channel
	Message chan string
}

func NewServer(ip string, port int) *Server {
	server := &Server{
		Ip:        ip,
		Port:      port,
		OnlineMap: make(map[string]*User),
		Message:   make(chan string),
	}
	return server
}

func (s *Server) Handler(conn net.Conn) {
	//業(yè)務(wù)邏輯
	//fmt.Println("鏈接建立成功")
	user := NewUser(conn, s)

	user.Online()

	//監(jiān)聽用戶是否活躍
	isLive := make(chan bool)

	go func() {
		buf := make([]byte, 4096)
		for {
			n, error := conn.Read(buf)
			if n == 0 {
				user.Offline()
				return
			}
			if error != nil && error != io.EOF {
				fmt.Println("read error")
			}
			msg := string(buf[:n-1])

			user.DoMessage(msg)

			//表示用戶活躍
			isLive <- true
		}
	}()

	for {
		select {
		case <-isLive:
			//當前用戶活躍,不做任何時,激活select,重置定時器

		case <-time.After(time.Second * 300):
			//超時,將user強制關(guān)閉
			user.SendMsg("你被踢了")
			close(user.C)
			conn.Close()
			return
		}
	}
}

func (s *Server) ListenMessager() {
	for {
		msg := <-s.Message

		s.mapLock.Lock()
		for _, user := range s.OnlineMap {
			user.C <- msg
		}
		s.mapLock.Unlock()
	}
}

func (s *Server) BroadCast(user *User, msg string) {
	sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
	s.Message <- sendMsg
}

func (s *Server) Start() {
	listener, error := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))
	if error != nil {
		fmt.Println("listener error...")
		return
	}
	defer listener.Close()

	go s.ListenMessager()
	for {
		conn, error := listener.Accept()
		if error != nil {
			fmt.Println("accept error...")
			continue
		}
		go s.Handler(conn)
	}

}

client.go

package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"os"
)

type Client struct {
	ServerIp   string
	ServerPort int
	Name       string
	conn       net.Conn
	flag       int
}

func NewClient(serverIp string, serverPort int) *Client {
	client := &Client{
		ServerIp:   serverIp,
		ServerPort: serverPort,
		flag:       9999,
	}
	conn, error := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIp, serverPort))
	if error != nil {
		fmt.Println("net dial error...")
		return nil
	}
	client.conn = conn
	return client
}

func (c *Client) menu() bool {
	var flag int

	fmt.Println("1.公聊模式")
	fmt.Println("2.私聊模式")
	fmt.Println("3.修改用戶名")
	fmt.Println("0.退出")

	fmt.Scanln(&flag)
	if flag >= 0 && flag <= 3 {
		c.flag = flag
		return true
	} else {
		fmt.Println(">>>>請輸入合法數(shù)字<<<<")
		return false
	}
}

//修改用戶名
func (c *Client) UpdateName() bool {
	fmt.Println(">>>>請輸入用戶名")
	fmt.Scanln(&c.Name)

	sendMsg := "rename|" + c.Name + "\n"
	_, error := c.conn.Write([]byte(sendMsg))
	if error != nil {
		fmt.Println("conn.write error...")
		return false
	}
	return true
}

//公聊
func (c *Client) PublicChat() {
	var chatMsg string
	fmt.Println(">>>>請輸入聊天內(nèi)容,輸入exit退出")
	fmt.Scanln(&chatMsg)

	for chatMsg != "exit" {
		if len(chatMsg) != 0 {
			msg := chatMsg + "\n"
			_, error := c.conn.Write([]byte(msg))
			if error != nil {
				fmt.Println("conn.Write error....")
				break
			}
		}

		chatMsg = ""
		fmt.Println(">>>>請輸入聊天內(nèi)容,輸入exit退出")
		fmt.Scanln(&chatMsg)
	}
}

//私聊
func (c *Client) PrivateChat() {
	var remoteUser string
	var chatMsg string

	c.SelectUsers()

	fmt.Println(">>>>請輸入聊天對象的用戶名,輸入exit退出")
	fmt.Scanln(&remoteUser)
	for remoteUser != "exit" {

		fmt.Println(">>>>請輸入聊天內(nèi)容,輸入exit退出")
		fmt.Scanln(&chatMsg)

		for chatMsg != "exit" {
			if len(chatMsg) != 0 {
				msg := "to|" + remoteUser + "|" + chatMsg + "\n\n"
				_, error := c.conn.Write([]byte(msg))
				if error != nil {
					fmt.Println("conn.Write error....")
					break
				}
			}

			chatMsg = ""
			fmt.Println(">>>>請輸入聊天內(nèi)容,輸入exit退出")
			fmt.Scanln(&chatMsg)
		}

		c.SelectUsers()
		remoteUser = ""
		fmt.Println(">>>>請輸入聊天對象的用戶名,輸入exit退出")
		fmt.Scanln(&remoteUser)
	}

}

//查詢在線用戶
func (c *Client) SelectUsers() {
	sendMsg := "who\n"
	_, error := c.conn.Write([]byte(sendMsg))
	if error != nil {
		fmt.Println("conn.Write error....")
		return
	}
}

//處理server返回的消息
func (c *Client) DealResponse() {
	io.Copy(os.Stdout, c.conn)
}
func (c *Client) Run() {
	for c.flag != 0 {
		for c.menu() != true {

		}
		switch c.flag {
		case 1:
			//公聊
			c.PublicChat()
		case 2:
			//私聊
			c.PrivateChat()
		case 3:
			//修改用戶名
			c.UpdateName()
		}
	}
}

var serverIp string
var serverPort int

func init() {
	flag.StringVar(&serverIp, "ip", "127.0.0.1", "設(shè)置服務(wù)器IP地址(默認為127.0.0.1)")
	flag.IntVar(&serverPort, "port", 8888, "設(shè)置服務(wù)器端口(默認為8888)")
}
func main() {
	flag.Parse()
	client := NewClient(serverIp, serverPort)
	if client == nil {
		fmt.Println(">>>>鏈接服務(wù)器失敗")
		return
	}

	go client.DealResponse()

	fmt.Println(">>>>鏈接服務(wù)器成功")
	client.Run()
}

user.go

package main

import (
	"net"
	"strings"
)

type User struct {
	Name   string
	Addr   string
	C      chan string
	conn   net.Conn
	server *Server
}

func NewUser(conn net.Conn, server *Server) *User {
	userAddr := conn.RemoteAddr().String()
	user := &User{
		Name:   userAddr,
		Addr:   userAddr,
		C:      make(chan string),
		conn:   conn,
		server: server,
	}
	go user.ListenMessage()
	return user
}

//用戶上線
func (u *User) Online() {
	u.server.mapLock.Lock()
	u.server.OnlineMap[u.Name] = u
	u.server.mapLock.Unlock()

	u.server.BroadCast(u, "上線")
}

//用戶下線
func (u *User) Offline() {
	u.server.mapLock.Lock()
	delete(u.server.OnlineMap, u.Name)
	u.server.mapLock.Unlock()

	u.server.BroadCast(u, "下線")
}

//給當前user的客戶端發(fā)送消息
func (u *User) SendMsg(msg string) {
	u.conn.Write([]byte(msg))
}

//處理消息
func (u *User) DoMessage(msg string) {

	if msg == "who" {
		//查詢當前在線用戶
		u.server.mapLock.Lock()
		for _, user := range u.server.OnlineMap {
			onlineMsg := "[" + user.Addr + "]" + user.Name + ":在線...\n"
			u.SendMsg(onlineMsg)
		}
		u.server.mapLock.Unlock()

	} else if len(msg) > 7 && msg[:7] == "rename|" {
		//修改用戶名 rename|xxx
		newName := strings.Split(msg, "|")[1]
		//判斷名字是否已經(jīng)存在
		_, ok := u.server.OnlineMap[newName]
		if ok {
			u.SendMsg("用戶名已存在\n")
		} else {

			u.server.mapLock.Lock()
			delete(u.server.OnlineMap, u.Name)
			u.server.OnlineMap[newName] = u
			u.server.mapLock.Unlock()

			u.Name = newName
			u.SendMsg("用戶名成功修改為:" + newName + "\n")
		}

	} else if len(msg) > 4 && msg[:3] == "to|" {
		//私聊  to|zhangsan|你好

		//獲取對方用戶名
		remoteName := strings.Split(msg, "|")[1]
		if remoteName == "" {
			u.SendMsg("用戶名格式不對\n")
			return
		}
		//獲取對方user
		remoteUser, ok := u.server.OnlineMap[remoteName]
		if !ok {
			u.SendMsg("用戶不存在\n")
			return
		}
		//獲取消息
		msg := strings.Split(msg, "|")[2]
		if msg == "" {
			u.SendMsg("無消息內(nèi)容,重新發(fā)送\n")
		}
		//發(fā)送消息
		remoteUser.SendMsg(u.Name + "對您說:" + msg)

	} else {
		u.server.BroadCast(u, msg)
	}
}

func (u *User) ListenMessage() {
	for {
		msg := <-u.C
		u.conn.Write([]byte(msg + "\n"))
	}
}

main.go

package main

func main() {
	server := NewServer("127.0.0.1", 8888)
	server.Start()
}

到此這篇關(guān)于300行代碼實現(xiàn)go語言即時通訊聊天室的文章就介紹到這了,更多相關(guān)go語言即時通訊聊天室內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言入門之基礎(chǔ)語法和常用特性解析

    Go語言入門之基礎(chǔ)語法和常用特性解析

    這篇文章主要給大家講解了Go語言的基礎(chǔ)語法和常用特性解析,比較適合入門小白,文中通過代碼示例介紹的非常詳細,對我們學習Go語言有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • Go中time.RFC3339 時間格式化的實現(xiàn)

    Go中time.RFC3339 時間格式化的實現(xiàn)

    這篇文章主要介紹了Go中time.RFC3339 時間格式化的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • golang網(wǎng)絡(luò)socket粘包問題的解決方法

    golang網(wǎng)絡(luò)socket粘包問題的解決方法

    這篇文章主要介紹了golang網(wǎng)絡(luò)socket粘包問題的解決方法,簡單講述了socket粘包的定義并結(jié)合實例形式分析了Go語言解決粘包問題的方法,需要的朋友可以參考下
    2016-07-07
  • 在Go語言開發(fā)中實現(xiàn)高性能的分布式日志收集的方法

    在Go語言開發(fā)中實現(xiàn)高性能的分布式日志收集的方法

    本文介紹了在Go語言開發(fā)中實現(xiàn)高性能分布式日志收集的關(guān)鍵步驟和考慮因素,包括日志生成與采集、日志傳輸、日志收集器的高性能網(wǎng)絡(luò)I/O、日志存儲與分析、監(jiān)控與告警系統(tǒng)、擴展性與可維護性等方面,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-01-01
  • Go語言變量初始化的實現(xiàn)示例

    Go語言變量初始化的實現(xiàn)示例

    在Go語言中,變量的初始化是編寫程序時經(jīng)常遇到的重要操作之一,本文主要介紹了Go語言變量初始化的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • Go信號處理如何優(yōu)雅地關(guān)閉你的應(yīng)用

    Go信號處理如何優(yōu)雅地關(guān)閉你的應(yīng)用

    Go?中的優(yōu)雅關(guān)閉機制使得在應(yīng)用程序接收到終止信號時,能夠進行平滑的資源清理,通過使用?context?來管理?goroutine?的生命周期,結(jié)合?signal?包捕獲系統(tǒng)信號,你可以在?Go?應(yīng)用中實現(xiàn)一個健壯且優(yōu)雅的關(guān)閉過程,對Go關(guān)閉應(yīng)用相關(guān)操作感興趣的朋友一起看看吧
    2025-01-01
  • Golang中的錯誤處理的示例詳解

    Golang中的錯誤處理的示例詳解

    這篇文章主要為大家詳細介紹了Golang中的錯誤處理的相關(guān)資料,文章中的示例代碼講解詳細,對我們學習Golang有一定幫助,需要的可以參考一下
    2022-11-11
  • Go語言web框架Gin響應(yīng)客戶端的方式

    Go語言web框架Gin響應(yīng)客戶端的方式

    Gin是一個用Go語言編寫的web框架,它是一個類似于martini但擁有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍,本文給大家介紹了Go語言web框架Gin響應(yīng)客戶端有哪些方式,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下
    2024-10-10
  • 詳解Golang互斥鎖內(nèi)部實現(xiàn)

    詳解Golang互斥鎖內(nèi)部實現(xiàn)

    本篇文章主要介紹了詳解Golang互斥鎖內(nèi)部實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • go json轉(zhuǎn)換實踐中遇到的坑

    go json轉(zhuǎn)換實踐中遇到的坑

    在使用 go 語言開發(fā)過程中,經(jīng)常需要使用到 json 包來進行 json 和 struct 的互相轉(zhuǎn)換,這篇文章主要介紹了go json轉(zhuǎn)換實踐中遇到的坑,非常具有實用價值,需要的朋友可以參考下
    2018-12-12

最新評論

汨罗市| 宜宾市| 马公市| 龙口市| 大新县| 苍南县| 共和县| 中西区| 九江市| 虹口区| 西昌市| 汪清县| 陆丰市| 蓬安县| 大城县| 望城县| 昌江| 富平县| 湘西| 达州市| 武夷山市| 长阳| 宿州市| 墨脱县| 确山县| 西乌| 泰来县| 徐闻县| 昌宁县| 镇沅| 乐安县| 旺苍县| 罗江县| 唐河县| 镇雄县| 乡城县| 商丘市| 城步| 平利县| 武穴市| 铜山县|