2017-06-03 1 views
2

J'ai donc démarré un projet qui implique des modules qui envoient et reçoivent des messages d'un serveur via des websockets. Cependant, je voulais un moyen simple d'interagir et d'envoyer des messages aux modules.Simple Message Client golang

Donc, j'ai le programme demander mon message dans un goroutine, quand j'appuie sur entrer, il envoie le message et m'invite à un autre. Dans le goroutine principal, il attendra jusqu'à ce qu'il reçoive un message et, le cas échéant, écrira sur la ligne en cours et remplacera ce qui était sur la ligne avant sur une nouvelle ligne.

Cependant, il n'y a qu'un seul problème. Il ne sait pas comment garder mes entrées à placer sur la nouvelle ligne. Dans mon test avec l'exemple suivant, il semble que os.Stdin.Read s'arrête jusqu'à ce qu'il reçoive un caractère de nouvelle ligne.

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
    "time" 
) 

func main() { 
    // Input Buffer 
    var msg string 

    scanner := bufio.NewScanner(os.Stdin) 
    scanner.Split(bufio.ScanBytes) 

    go func() { 
     for { 
      // Prompt the user for a message 
      fmt.Print("client1: ") 

      // Scan os.Stdin, splitting on bytes 
      for scanner.Scan() { 
       if scanner.Text() == "\n" { 
        break 
       } else { 
        // If the character is not \n, add to the input buffer 
        msg += scanner.Text() 
       } 
      } 

      // Do something with the input buffer then clear it 
      fmt.Println(msg) 
      msg = "" 
     } 
    }() 

    for { 
     select { 
     // Receive a message from a client 
     case <-time.After(5 * time.Second): 
      // Write the message over the current line 
      fmt.Println("\rclient2: Hello") 

      // Prompt the user again for their message 
      // proving the current input buffer 
      fmt.Print("client1: " + msg) 
     } 
    } 
} 

Un exemple de sortie:

client1: Hello! 
Hello! 
client2: Hello 
client1: Bye! 
Bye! 
client2: Hello 
client2: Hello // Was "client1: Good " before being overwritten 
client1: Bye! 
Good Bye! 

Toutes les idées sont grandement appréciés. Merci d'avance.

Répondre

0

Il semble que la condition de course IO. Votre goroutine n'est pas synchronisé avec le principal. Btw ScanLines fait la même chose pour vous. Considérez ceci:

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
) 

func main() { 
    scanner := bufio.NewScanner(os.Stdin) 
    msgQ := make(chan string) 

    defer close(msgQ) 

    go func() { 
     for { 
      // Prompt the user for a message 
      fmt.Print("client1: ") 
      msg, ok := <-msgQ 
      if !ok { 
       return 
      } 
      fmt.Println("\rclient1 said: " + msg) 
      // Write the message over the current line 
      fmt.Println("client2: Hello") 
     } 
    }() 


    // Scan os.Stdin, splitting on bytes 
    for scanner.Scan() { 
     msgQ <- scanner.Text() 
    } 

} 

EDIT: D'après les commentaires, ce code montre ce qui ne va pas avec cette idée. Lorsque vous écrivez quelque chose et que vous n'appuyez pas sur ENTER, le client2 écrase la ligne courante. Vous pouvez enregistrer (CTRL-U) et restaurer (CTRL-Y) la ligne courante mais je n'ai trouvé ni signature ANSI ni Signal pour l'appeler par programmation.

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
    "time" 
) 

func main() { 

    scanner := bufio.NewScanner(os.Stdin) 
    sendQ := make(chan struct{}) 

    defer close(sendQ) 

    //simulate local client1 console 
    go func() { 
     for { 
      fmt.Print("client1: ") 
      select { 
      case _, ok := <-sendQ: 
       if !ok { 
        return 
       } 
      case <-time.After(5 * time.Second): 
       fmt.Printf("\r\033[K") // delete current line from right 
       fmt.Println("client2: Hello") 
      } 
     } 
    }() 

    for scanner.Scan() { 
     sendQ <- struct{}{} 
    } 

} 
+0

Hmm ok. Impossible de le tester pour le moment mais il semble que ce client2 ne peut sortir que lorsque vous envoyez un message. Je vais jouer avec l'idée. –

+0

Je ne pense pas que terminal/console ne convient pas pour les opérations d'E/S asynchrones. La solution alternative est ncurses ou termbox .. – bigless

+0

Je pense comme dans ma situation, les messages sont beaucoup plus susceptibles d'être reçus que envoyés, je pourrais avoir un seul programme de terminal pour obtenir des messages, puis un autre programme pour les envoyer. Merci pour vos efforts. J'ai regardé termbox mais il semble que beaucoup d'efforts pour pas un gros problème. –