arekkusu6

tcp chat server and client code

Sep 17th, 2025
755
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 5.06 KB | Source Code | 0 0
  1. //server
  2. package tcpl
  3.  
  4. import (
  5.     "encoding/json"
  6.     "fmt"
  7.     "log"
  8.     "net"
  9.     "os"
  10.     "time"
  11. )
  12.  
  13.  
  14. type outgoingMessage struct {
  15.     message         *Message
  16.     sender          *Client
  17. }
  18.  
  19.  
  20. type Message struct {
  21.     RoomID          string      `json:"roomID"`
  22.     Username        string      `json:"username"`
  23.     Text            string      `json:"text"`
  24. }
  25.  
  26.  
  27. type Server struct {
  28.     clients         map[string]map[*Client]struct{}
  29.     connect         chan *Client
  30.     disconnect      chan *Client
  31.     outgoing        chan *outgoingMessage
  32. }
  33.  
  34.  
  35. type Client struct {
  36.     server          *Server
  37.     conn            *net.TCPConn
  38.     outgoing        chan *Message
  39.     roomID          string
  40. }
  41.  
  42.  
  43. func NewServer() *Server {
  44.     return &Server{
  45.         clients:    make(map[string]map[*Client]struct{}),
  46.         connect:    make(chan *Client),
  47.         disconnect: make(chan *Client),
  48.         outgoing:   make(chan *outgoingMessage),
  49.     }
  50. }
  51.  
  52.  
  53. func (s *Server) Run() {
  54.     for {
  55.         select {
  56.             case c := <-s.connect:
  57.                 if s.clients[c.roomID] == nil {
  58.                     s.clients[c.roomID] = make(map[*Client]struct{})
  59.                 }
  60.  
  61.                 s.clients[c.roomID][c] = struct{}{}
  62.  
  63.             case c := <-s.disconnect:
  64.                 if clients, ok := s.clients[c.roomID]; ok {
  65.                     close(c.outgoing)
  66.                     delete(clients, c)
  67.                    
  68.                     if len(clients) == 0 {
  69.                         delete(s.clients, c.roomID)
  70.                     }
  71.                 }
  72.  
  73.             case outgoing := <-s.outgoing:
  74.                 if clients, ok := s.clients[outgoing.message.RoomID]; ok {
  75.                     for client := range clients {
  76.                         if client == outgoing.sender {
  77.                             continue
  78.                         }
  79.  
  80.                         select {
  81.                             case client.outgoing <- outgoing.message:
  82.                             default:
  83.                         }
  84.                     }
  85.             }
  86.         }
  87.     }
  88. }
  89.  
  90. func (c *Client) read() {
  91.     defer func() {
  92.         c.server.disconnect <- c
  93.         c.conn.Close()
  94.     }()
  95.  
  96.     var dec = json.NewDecoder(c.conn)
  97.  
  98.     for {
  99.         var msg Message
  100.  
  101.         if err := dec.Decode(&msg); err != nil {
  102.             log.Println("error reading message:", err)
  103.             return
  104.         }
  105.  
  106.         c.server.outgoing <- &outgoingMessage{message: &msg, sender: c}
  107.     }
  108. }
  109.  
  110. func (c *Client) write() {
  111.     defer c.conn.Close()
  112.  
  113.     var enc = json.NewEncoder(c.conn)
  114.  
  115.     var ticker = time.NewTicker(30 * time.Second)
  116.     defer ticker.Stop()
  117.  
  118.     for {
  119.         select {
  120.             case msg, ok := <-c.outgoing:
  121.                 if !ok {
  122.                     log.Println("channel closed")
  123.                     return
  124.                 }
  125.  
  126.                 c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
  127.  
  128.                 if err := enc.Encode(msg); err != nil {
  129.                     log.Println("error sending message:", err)
  130.                     return
  131.                 }
  132.  
  133.             case <-ticker.C:
  134.                 c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
  135.         }
  136.     }
  137. }
  138.  
  139. func (s *Server) Start() {
  140.     tcpAddr, err := net.ResolveTCPAddr("tcp", ":8000")
  141.  
  142.     if err != nil {
  143.         log.Fatal(err)
  144.     }
  145.  
  146.     listener, err := net.ListenTCP("tcp", tcpAddr)
  147.  
  148.     if err != nil {
  149.         log.Fatal(err)
  150.     }
  151.  
  152.     defer listener.Close()
  153.  
  154.     for {
  155.         conn, err := listener.AcceptTCP()
  156.  
  157.         fmt.Println("new connection: ", conn.RemoteAddr().String())
  158.  
  159.         if err != nil {
  160.             log.Println("failed to accept: ", err)
  161.             continue
  162.         }
  163.  
  164.         var initMsg Message
  165.  
  166.         var dec = json.NewDecoder(conn)
  167.  
  168.         if err := dec.Decode(&initMsg); err != nil {
  169.             log.Println("failed to read init message: ", err)
  170.             conn.Close()
  171.             continue
  172.         }
  173.  
  174.         var client = &Client{
  175.             server:   s,
  176.             conn:     conn,
  177.             outgoing: make(chan *Message, 128),
  178.             roomID:   initMsg.RoomID,
  179.         }
  180.  
  181.         s.connect <- client
  182.  
  183.         go client.read()
  184.         go client.write()
  185.     }
  186. }
  187.  
  188.  
  189. func ListenOrServe() {
  190.     if len(os.Args) < 2 {
  191.         println("Usage: server|client [args...]")
  192.         return
  193.     }
  194.  
  195.     switch os.Args[1] {
  196.         case "server":
  197.             var server = NewServer()
  198.  
  199.             go server.Run()
  200.            
  201.             server.Start()
  202.        
  203.         case "client":
  204.             if len(os.Args) != 4 {
  205.                 println("Usage: client <roomID> <username>")
  206.                 return
  207.             }
  208.  
  209.             var (
  210.                 room = os.Args[2]
  211.                 user = os.Args[3]
  212.             )
  213.  
  214.         StartClient(room, user)
  215.     }
  216. }
  217.  
  218. //client.go
  219. package tcpl
  220.  
  221. import (
  222.     "bufio"
  223.     "encoding/json"
  224.     "fmt"
  225.     "log"
  226.     "net"
  227.     "os"
  228. )
  229.  
  230. func StartClient(roomID, username string) {
  231.     conn, err := net.Dial("tcp", "localhost:8000")
  232.    
  233.     if err != nil {
  234.         log.Fatal(err)
  235.     }
  236.  
  237.     defer conn.Close()
  238.  
  239.     var initMsg = Message{
  240.         RoomID:   roomID,
  241.         Username: username,
  242.     }
  243.  
  244.     var enc = json.NewEncoder(conn)
  245.  
  246.     if err := enc.Encode(&initMsg); err != nil {
  247.         log.Fatal("failed to send init message:", err)
  248.     }
  249.  
  250.     go func() {
  251.         var dec = json.NewDecoder(conn)
  252.  
  253.         for {
  254.             var msg Message
  255.            
  256.             if err := dec.Decode(&msg); err != nil {
  257.                 log.Println("error reading:", err)
  258.                 return
  259.             }
  260.            
  261.             fmt.Printf("<%s>: %s\n", msg.Username, msg.Text)
  262.         }
  263.     }()
  264.  
  265.  
  266.     var scanner = bufio.NewScanner(os.Stdin)
  267.  
  268.     for {
  269.         fmt.Print("> ")
  270.  
  271.         if !scanner.Scan() {
  272.             break
  273.         }
  274.  
  275.         var text = scanner.Text()
  276.        
  277.         var msg = Message{
  278.             RoomID:   roomID,
  279.             Username: username,
  280.             Text:     text,
  281.         }
  282.  
  283.         if err := enc.Encode(&msg); err != nil {
  284.             log.Println("error sending:", err)
  285.             return
  286.         }
  287.     }
  288. }
  289.  
Advertisement
Add Comment
Please, Sign In to add comment