Chatten Sie eins zu eins mit Golang Socket

王林
Freigeben: 2024-02-08 20:45:04
nach vorne
323 Leute haben es durchsucht

与 golang 套接字一对一聊天

Frageninhalt

Ich habe eine Shopping-App, in der Benutzer Verfügbarkeiten posten können und andere Benutzer sie finden und ihre Verfügbarkeit hinzufügen können.

Ich habe jetzt einen Chat-Dienst, hauptsächlich zum Chatten. Das heißt, Kunden können mit dem Käufer chatten, um Details oder andere Dinge zu bestätigen. Dieser Chat sollte ein Einzelgespräch sein. Es können also fünf Kunden sein, die nach einem Einkaufsbeitrag fragen, und ich möchte, dass der Chat einzigartig ist, da der Chat von Kunde A über den Kauf vom Chat von Kunde B über denselben Kauf getrennt sein sollte. Käufer sollten den Chat sehen und antworten können.

Das ist es, was ich derzeit habe, aber dies scheint eine Botschaft an alle in der Referenz zu senden. Ich möchte, dass Käufer nur Nachrichten von einem bestimmten Absender erhalten, ohne dass andere Zugriff auf den Chat haben.

"client.go"

type client struct { conn *websocket.conn chatrepository chat.chatrepository message chan *message id string `json:"id"` reference string `json:"reference"` username string `json:"username"` sender string `json:"sender"` recipient string `json:"recipient"` } type message struct { content string `json:"content"` reference string `json:"reference"` // username string `json:"username"` sender string `json:"sender"` } func (c *client) writemessage() { defer func() { c.conn.close() }() for { message, ok := <-c.message if !ok { return } uuid, err := uuid.newv4() if err != nil { log.fatalf("failed to generate uuid: %v", err) } chatmessage := chat.chatmessage{ id: uuid.string(), sender: message.sender, // recipient: recipient, timestamp: time.now(), content: message.content, } if c.sender == message.sender { _, errx := c.chatrepository.addmessage(message.reference, chatmessage) if err != nil { log.fatalf("failed to generate uuid: %v", errx) } } c.conn.writejson(chatmessage) } } func (c *client) readmessage(hub *hub) { defer func() { hub.unregister <- c c.conn.close() }() for { _, m, err := c.conn.readmessage() if err != nil { if websocket.isunexpectedcloseerror(err, websocket.closegoingaway, websocket.closeabnormalclosure) { log.printf("error: %v", err) } break } msg := &message{ content: string(m), reference: c.reference, sender: c.sender, // username: c.username, } hub.broadcast <- msg } }
Nach dem Login kopieren

"hub.go"

type room struct { id string `json:"id"` name string `json:"name"` clients map[string]*client `json:"clients"` } type hub struct { rooms map[string]*room register chan *client unregister chan *client broadcast chan *message emmiter events.emitter } func newhub(emmiter events.emitter) *hub { return &hub{ rooms: make(map[string]*room), register: make(chan *client), unregister: make(chan *client), broadcast: make(chan *message, 5), emmiter: emmiter, } } func (h *hub) run() { for { select { case cl := <-h.register: if _, ok := h.rooms[cl.reference]; ok { r := h.rooms[cl.reference] if _, ok := r.clients[cl.id]; !ok { r.clients[cl.id] = cl } } case cl := <-h.unregister: if _, ok := h.rooms[cl.reference]; ok { if _, ok := h.rooms[cl.reference].clients[cl.id]; ok { // if len(h.rooms[cl.reference].clients) != 0 { // h.broadcast <- &message{ // content: "user left the chat", // reference: cl.reference, // username: cl.username, // } // } delete(h.rooms[cl.reference].clients, cl.id) close(cl.message) } } case m := <-h.broadcast: if _, ok := h.rooms[m.reference]; ok { for _, cl := range h.rooms[m.reference].clients { cl.message <- m if m.sender != cl.recipient { notifications.sendpush(h.emmiter, cl.recipient, fmt.sprintf("new message from %v", cl.username), m.content) } } } } } }
Nach dem Login kopieren

"handler.go"

type handler struct { hub *hub chatrepository chat.chatrepository } func newhandler(h *hub, chatrepository chat.chatrepository) *handler { return &handler{ hub: h, chatrepository: chatrepository, } } var upgrader = websocket.upgrader{ readbuffersize: 1024, writebuffersize: 1024, checkorigin: func(r *http.request) bool { return true }, } func (h *handler) joinroom(c *gin.context) { conn, err := upgrader.upgrade(c.writer, c.request, nil) if err != nil { utils.handleerror(c, nil, "error creating chat connection", http.statusbadgateway) return } reference := c.param("reference") sender := c.query("sender") username := c.query("username") recipient := c.query("recipient") if reference == "" || sender == "" || username == "" || recipient == "" { utils.handleerror(c, nil, "required parameters missing", http.statusbadgateway) return } if _, ok := h.hub.rooms[reference]; !ok { // room doesn't exist, handle accordingly _, err1 := h.chatrepository.getchathistory(reference) if err1 != nil { log.printf("failed to retrieve chat history: %s", err1) errx := h.chatrepository.createchat(reference) if errx != nil { utils.handleerror(c, nil, "error storing connection", http.statusbadgateway) return } } h.hub.rooms[reference] = &room{ id: reference, name: sender, clients: make(map[string]*client), } } cl := &client{ conn: conn, chatrepository: h.chatrepository, message: make(chan *message, 10), id: sender, reference: reference, sender: sender, username: username, recipient: recipient, } h.hub.register <- cl go cl.writemessage() cl.readmessage(h.hub) }
Nach dem Login kopieren

"route.go"

hub := ws.newhub(events.neweventemitter(conn)) wshandler := ws.newhandler(hub, pr.newchatrepository(db, client)) go hub.run() v1.get("/chat/ws/:reference", g.guard([]string{"user", "admin", "dispatcher"}, nil), wshandler.joinroom)
Nach dem Login kopieren
"chat.model.go" type Chat struct { ID string `json:"id,omitempty" bson:"_id,omitempty"` Reference string `json:"reference" bson:"reference"` Messages []ChatMessage `json:"messages" bson:"messages"` } type ChatMessage struct { ID string `json:"id,omitempty" bson:"_id,omitempty"` Sender string `json:"sender" bson:"sender,omitempty"` Timestamp time.Time `json:"timestamp" bson:"timestamp,omitempty"` Content string `json:"content" bson:"content,omitempty"` }
Nach dem Login kopieren


Richtige Antwort


Der Hauptgrund, warum Ihr Code eine Nachricht mit derselben Referenz an alle im Raum sendet, ist, dass Sie es in derhubbroadcast频道中处理消息的方式。在当前的实现中,当发送消息时,它会被转发到同一房间中的每个客户端(即具有相同的引用)。这是在hubrun-Methode tun:

case m := <-h.broadcast: if _, ok := h.rooms[m.reference]; ok { for _, cl := range h.rooms[m.reference].clients { cl.message <- m ...
Nach dem Login kopieren

Ich hoffe, dass es 1:1 steht. Das Zitat ist gepostet

WennreferencepostidSie eine persönliche Kommunikation zwischen dem Käufer (der Person, die den Verfügbarkeitsbeitrag veröffentlicht) und jedem Kunden wünschen, müssen Sie sicherstellen, dass jeder Chat eindeutig identifizierbar ist.

Der eindeutige Schlüssel für jede Chat-Sitzung sollte eine Kombination auspostid(reference) 和客户 id (sendersein. Dadurch wird sichergestellt, dass jeder Kunde in jedem Beitrag eine einzigartige Chat-Sitzung mit dem Käufer hat.

Sie können dann die Kombination vonclient结构,使其具有chatid,它是referencesenderaktualisieren.

type client struct { ... chatid string `json:"chat_id"` }
Nach dem Login kopieren

Sie können dashub来管理聊天会话地图(由chatid-Logo anstelle des Raums aktualisieren.

type hub struct { chats map[string]*chat ... }
Nach dem Login kopieren

Die Struktur jedeschatist wie folgt:

type chat struct { shopper *client customer *client }
Nach dem Login kopieren

Um Nachrichten zu verarbeiten: Wenn ein Kunde eine Nachricht sendet, wird die Nachricht an den Käufer gesendet, und wenn der Käufer antwortet, wird die Nachricht an den Kunden gesendet. Das Routing kann mitchatiderfolgen.

Zum Beispiel in deinerbroadcastLogik:

case m := <-h.broadcast: chat, ok := h.chats[m.chatid] if ok { if m.sender == chat.customer.id { // message is from customer to shopper chat.shopper.message <- m } else if m.sender == chat.shopper.id { // message is from shopper to customer chat.customer.message <- m } }
Nach dem Login kopieren
Die Variable

mist vom Typ*messageund hat keinm变量的类型为*message,它没有chatid-Feld.
Um dieses Problem zu lösen, sollten Sie erwägen, daschatid字段添加到message-Feld zur

-Struktur hinzuzufügen.

messageZuerst modifizieren wir die

Struktur:

type message struct { content string `json:"content"` chatid string `json:"chat_id"` sender string `json:"sender"` }
Nach dem Login kopieren
clientreadmessage方法中构造一个新的 messageDann, wenn Sie ein neues

in der readmessage-Methode des Clientserstellen:

msg := &message{ content: string(m), chatid: c.chatid, sender: c.sender, }
Nach dem Login kopieren

Beim Initialisieren des Chats:

chatID := reference + "_" + sender cl := &Client{ ... ChatID: chatID, } // If the chat session does not exist, create it. if _, ok := h.hub.Chats[chatID]; !ok { h.hub.Chats[chatID] = &Chat{ Customer: cl, Shopper: nil, // That will be set when the shopper joins. } } else { // That assumes only the customer or the shopper can join, not both at the same time. if h.hub.Chats[chatID].Shopper == nil { h.hub.Chats[chatID].Shopper = cl } else { h.hub.Chats[chatID].Customer = cl } }
Nach dem Login kopieren
Warnung: Dies ist nur ein Grundgerüst der Funktion, berücksichtigt jedoch keine zusätzlichen Komplexitäten, wie z. B. die Handhabung von Situationen, in denen Kunden oder Käufer möglicherweise mehrere Geräte haben, die Gewährleistung einer robusten Fehlerbehandlung und mehr.

Das obige ist der detaillierte Inhalt vonChatten Sie eins zu eins mit Golang Socket. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!