@lucifer-m
golang php js html css

Как отправить данные во все рутины?

Спасибо FireGM за то что помог мне исправить сделать отправку сообщений с термнала клиентам. По идее код должен отправить данные всем клиентам. Сейчас подключил два клиента, пишу первое сообщение оно приходит только первому клиенту, пишу второе сообщение оно приходит только второму клиенту, пишу третье смс оно приходит только первому и т.д.
52ece65a5177441b8f4a5c7f7c9c9521.png
Код сервера
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
)

var messages chan string

func main() {
	messages = make(chan string, 10)
	var port int = 3333
	listen, err := net.Listen("tcp4", ":"+strconv.Itoa(port))
	defer listen.Close()
	if err != nil {
		log.Fatalf("Прослушивание порта %d не удалось,\r\n\r\n %s", port, err)
		os.Exit(1)
	}

	go func() {

		log.Printf("Сервер слушает порт: %d", port)
		reader := bufio.NewReader(os.Stdin)
		for {
			fmt.Print("Enter text: ")
			text, _ := reader.ReadString('\n')
			log.Print(text)
			messages <- text
		}

	}()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatalln(err)
			continue
		}
		go handler(conn)
	}
}
func handler(conn net.Conn) {
	defer conn.Close()
	var (
		buf = make([]byte, 1024)
		r   = bufio.NewReader(conn)
		w   = bufio.NewWriter(conn)
	)
ILOOP:
	for {
		n, err := r.Read(buf)
		data := string(buf[:n])
		switch err {
		case io.EOF:
			break ILOOP
		case nil:
			//log.Println("Получил:", data)
			if isTransportOver(data) {
				break ILOOP
			}
		default:
			log.Fatalf("Ошибка при получении:%s", err)
			return
		}
	}
	//данные из канала
	msg := <-messages
	w.Write([]byte(msg))
	w.Flush()

}
func isTransportOver(data string) (over bool) {
	over = strings.HasSuffix(data, "\r\n\r\n")
	return
}

Почему так происходит? зарание спасибо
  • Вопрос задан
  • 488 просмотров
Решения вопроса 2
@FireGM
https://gist.github.com/drewolson/3950226 вот неплохой пример реализации пула клиентов. Просто вырезать лишнее и норм будет.

переделал тот пример, с удалением умерших коннекторов при отправке. Вырезал немного, работает только на отправку клиенту.

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
)

type Client struct {
	writer *bufio.Writer
}

func (client *Client) Write(data string) error {
	fmt.Println("client write")
	_, err := client.writer.WriteString(data)
	err = client.writer.Flush()
	return err
}

func NewClient(connection net.Conn) *Client {
	writer := bufio.NewWriter(connection)
	client := &Client{
		writer: writer,
	}
	return client
}

type ChatRoom struct {
	clients []*Client
}

func (chatRoom *ChatRoom) Broadcast(data string) {
	deleted := 0
	for i := range chatRoom.clients {
		j := i - deleted
		if err := chatRoom.clients[j].Write(data); err != nil {
			fmt.Println(err, "deleted error")
			chatRoom.clients = chatRoom.clients[:j+copy(chatRoom.clients[j:], chatRoom.clients[j+1:])]
			deleted++
		}
	}
}

func (chatRoom *ChatRoom) Join(connection net.Conn) {
	client := NewClient(connection)
	chatRoom.clients = append(chatRoom.clients, client)
}

func NewChatRoom() *ChatRoom {
	chatRoom := &ChatRoom{
		clients: make([]*Client, 0),
	}

	return chatRoom
}

func main() {
	chatRoom := NewChatRoom()

	listener, _ := net.Listen("tcp4", ":3333")
	go readAndSend(chatRoom)

	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		chatRoom.Join(conn)
	}
}

func readAndSend(chatRoom *ChatRoom) {

	reader := bufio.NewReader(os.Stdin)
	for {
		fmt.Print("Enter text: ")
		text, _ := reader.ReadString('\n')
		log.Print(text)
		chatRoom.Broadcast(text)
	}

}
Ответ написан
Вот пример с пулом клиентов и сохранением в map.
Клиентам рассылается то, что набрано на сервере, данные, пришедшие от клиентов обрабатываются.

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
)

var messages chan string

type Client struct {
	Id      uint64
	MsgChan chan (string)
}

type ClientPool struct {
	counter    uint64
	joins      chan (Client)
	lefts      chan (uint64)
	ids        chan (uint64)
	broadcasts chan (string)
	clients    map[uint64]Client
}

func NewClientPool() *ClientPool {
	pool := ClientPool{
		joins:      make(chan (Client)),
		lefts:      make(chan (uint64)),
		ids:        make(chan (uint64)),
		broadcasts: make(chan (string)),
		clients:    make(map[uint64]Client),
	}

	go func() {
		var id uint64
		for {
			id++
			pool.ids <- id
		}
	}()

	go func() {
		for {
			select {
			case newClient := <-pool.joins:
				pool.clients[newClient.Id] = newClient
			case idForDeletion := <-pool.lefts:
				delete(pool.clients, idForDeletion)
			case text := <-pool.broadcasts:
				for _, client := range pool.clients {
					client.MsgChan <- text
				}
			}
		}
	}()

	return &pool
}

func (this *ClientPool) NewClient() Client {
	client := Client{
		Id:      <-this.ids,
		MsgChan: make(chan (string)),
	}
	this.joins <- client
	return client
}

func (this *ClientPool) BroadcastMessage(text string) {
	this.broadcasts <- text
}

func (this *ClientPool) DeleteClient(client Client) {
	this.lefts <- client.Id
}

func main() {
	pool := NewClientPool()
	var port int = 3333
	listen, err := net.Listen("tcp4", ":"+strconv.Itoa(port))
	defer listen.Close()
	if err != nil {
		log.Fatalf("Прослушивание порта %d не удалось,\r\n\r\n %s", port, err)
		os.Exit(1)
	}

	go func() {

		log.Printf("Сервер слушает порт: %d", port)
		reader := bufio.NewReader(os.Stdin)
		for {
			fmt.Print("Enter text: ")
			text, _ := reader.ReadString('\n')
			log.Print(text)
			pool.BroadcastMessage(text)
		}

	}()

	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatalln(err)
			continue
		}
		go handler(conn, pool)
	}
}

func handler(conn net.Conn, pool *ClientPool) {
	client := pool.NewClient()
	defer pool.DeleteClient(client)
	defer conn.Close()
	defer log.Printf("Клиент с номером %d вышел\n", client.Id)

	log.Printf("Новый клиент присоединен, ему присвоен номер %d", client.Id)

	incomingClientMsg := make(chan string)

	go func() {
		reader := bufio.NewReader(conn)
		for {
			text, err := reader.ReadString('\n')
			if err != nil {
				close(incomingClientMsg)
				return
			}
			incomingClientMsg <- text
		}
	}()

	for {
		select {
		case text := <-incomingClientMsg:
			text = strings.Trim(text, "\r\n")
			if text == "/quit" {
				return
			}
			log.Printf("Клиент с номером %d написал: %s\n", client.Id, text)
		case text := <-client.MsgChan:
			_, err := conn.Write([]byte(text))
			if err != nil {
				return
			}
		}
	}
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы