Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //server
- package tcpl
- import (
- "encoding/json"
- "fmt"
- "log"
- "net"
- "os"
- "time"
- )
- type outgoingMessage struct {
- message *Message
- sender *Client
- }
- type Message struct {
- RoomID string `json:"roomID"`
- Username string `json:"username"`
- Text string `json:"text"`
- }
- type Server struct {
- clients map[string]map[*Client]struct{}
- connect chan *Client
- disconnect chan *Client
- outgoing chan *outgoingMessage
- }
- type Client struct {
- server *Server
- conn *net.TCPConn
- outgoing chan *Message
- roomID string
- }
- func NewServer() *Server {
- return &Server{
- clients: make(map[string]map[*Client]struct{}),
- connect: make(chan *Client),
- disconnect: make(chan *Client),
- outgoing: make(chan *outgoingMessage),
- }
- }
- func (s *Server) Run() {
- for {
- select {
- case c := <-s.connect:
- if s.clients[c.roomID] == nil {
- s.clients[c.roomID] = make(map[*Client]struct{})
- }
- s.clients[c.roomID][c] = struct{}{}
- case c := <-s.disconnect:
- if clients, ok := s.clients[c.roomID]; ok {
- close(c.outgoing)
- delete(clients, c)
- if len(clients) == 0 {
- delete(s.clients, c.roomID)
- }
- }
- case outgoing := <-s.outgoing:
- if clients, ok := s.clients[outgoing.message.RoomID]; ok {
- for client := range clients {
- if client == outgoing.sender {
- continue
- }
- select {
- case client.outgoing <- outgoing.message:
- default:
- }
- }
- }
- }
- }
- }
- func (c *Client) read() {
- defer func() {
- c.server.disconnect <- c
- c.conn.Close()
- }()
- var dec = json.NewDecoder(c.conn)
- for {
- var msg Message
- if err := dec.Decode(&msg); err != nil {
- log.Println("error reading message:", err)
- return
- }
- c.server.outgoing <- &outgoingMessage{message: &msg, sender: c}
- }
- }
- func (c *Client) write() {
- defer c.conn.Close()
- var enc = json.NewEncoder(c.conn)
- var ticker = time.NewTicker(30 * time.Second)
- defer ticker.Stop()
- for {
- select {
- case msg, ok := <-c.outgoing:
- if !ok {
- log.Println("channel closed")
- return
- }
- c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
- if err := enc.Encode(msg); err != nil {
- log.Println("error sending message:", err)
- return
- }
- case <-ticker.C:
- c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
- }
- }
- }
- func (s *Server) Start() {
- tcpAddr, err := net.ResolveTCPAddr("tcp", ":8000")
- if err != nil {
- log.Fatal(err)
- }
- listener, err := net.ListenTCP("tcp", tcpAddr)
- if err != nil {
- log.Fatal(err)
- }
- defer listener.Close()
- for {
- conn, err := listener.AcceptTCP()
- fmt.Println("new connection: ", conn.RemoteAddr().String())
- if err != nil {
- log.Println("failed to accept: ", err)
- continue
- }
- var initMsg Message
- var dec = json.NewDecoder(conn)
- if err := dec.Decode(&initMsg); err != nil {
- log.Println("failed to read init message: ", err)
- conn.Close()
- continue
- }
- var client = &Client{
- server: s,
- conn: conn,
- outgoing: make(chan *Message, 128),
- roomID: initMsg.RoomID,
- }
- s.connect <- client
- go client.read()
- go client.write()
- }
- }
- func ListenOrServe() {
- if len(os.Args) < 2 {
- println("Usage: server|client [args...]")
- return
- }
- switch os.Args[1] {
- case "server":
- var server = NewServer()
- go server.Run()
- server.Start()
- case "client":
- if len(os.Args) != 4 {
- println("Usage: client <roomID> <username>")
- return
- }
- var (
- room = os.Args[2]
- user = os.Args[3]
- )
- StartClient(room, user)
- }
- }
- //client.go
- package tcpl
- import (
- "bufio"
- "encoding/json"
- "fmt"
- "log"
- "net"
- "os"
- )
- func StartClient(roomID, username string) {
- conn, err := net.Dial("tcp", "localhost:8000")
- if err != nil {
- log.Fatal(err)
- }
- defer conn.Close()
- var initMsg = Message{
- RoomID: roomID,
- Username: username,
- }
- var enc = json.NewEncoder(conn)
- if err := enc.Encode(&initMsg); err != nil {
- log.Fatal("failed to send init message:", err)
- }
- go func() {
- var dec = json.NewDecoder(conn)
- for {
- var msg Message
- if err := dec.Decode(&msg); err != nil {
- log.Println("error reading:", err)
- return
- }
- fmt.Printf("<%s>: %s\n", msg.Username, msg.Text)
- }
- }()
- var scanner = bufio.NewScanner(os.Stdin)
- for {
- fmt.Print("> ")
- if !scanner.Scan() {
- break
- }
- var text = scanner.Text()
- var msg = Message{
- RoomID: roomID,
- Username: username,
- Text: text,
- }
- if err := enc.Encode(&msg); err != nil {
- log.Println("error sending:", err)
- return
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment