5.2 سرور tcp مقدماتی

5.2 سرور tcp مقدماتی

ما میتوانیم در گو با استفاده از کتابخانه net یک سرور tcp ایجاد کنیم بعد از تکمیل شدن سرور با استفاده از دستور telnet به آن متصل میشویم

در قطعه کد زیر با تابع acceptLoop() درخواست های اتصال را مپذیریم و با تابع readLoop() پیام های اتصال را میخوانیم

  1package main
  2
  3import (
  4	"fmt"
  5	"log"
  6	"net"
  7)
  8
  9// ساختار هر پیام در سرور
 10type Message struct {
 11	// ادرس ip ارسال کننده پیام
 12	from    string
 13	// متن و محتوای پیام
 14	payload []byte
 15}
 16
 17// ساختار سرور
 18type Server struct {
 19	// ادرس و یا پورت سرور
 20	listenAddr string
 21	// listener
 22	ln         net.Listener
 23	// چنل پیام برای انتقال پیام های دریافتی از اتصال ها بین گوروتین ها
 24	msgch      chan Message
 25}
 26
 27// ایجاد یک سرور جدید
 28func newServer(listenAddr string) *Server {
 29	return &Server{
 30		listenAddr: listenAddr,
 31		msgch:      make(chan Message, 10),
 32	}
 33}
 34
 35// شروع سرور و دریافت اتصال های جدید
 36func (s *Server) start() error {
 37	// شروع سرور
 38	ln, err := net.Listen("tcp", s.listenAddr)
 39	if err != nil {
 40		return err
 41	}
 42	// مقدار دهی listener
 43	s.ln = ln
 44	// با تابع acceptLoop اتصال های جدید به سرور را مدیریت میکنیم
 45	// با استفاده از go هر اتصال را روی یک گوروتین مجزا مدیریت میکنیم
 46	go s.acceptLoop()
 47
 48	return nil
 49}
 50
 51// اینجا برای استاپ کردن سرور یک متد جدید تعریف میکنیم
 52func (s *Server) stop() {
 53	if s.ln != nil {
 54		s.ln.Close()
 55	}
 56}
 57
 58func (s *Server) acceptLoop() {
 59	for {
 60		// اتصال های موجود را تایید میکنیم متغییر conn را با اتصال مورد نظر مقدار دهی میکنیم
 61		conn, err := s.ln.Accept()
 62		if err != nil {
 63			fmt.Println("accept error:", err)
 64			continue
 65		}
 66		// با استفاده از این تابع مقادیر ارسال شده توسط اتصال را به چنل message میدهیم
 67		go s.readLoop(conn)
 68	}
 69}
 70
 71func (s *Server) readLoop(conn net.Conn) {
 72	defer conn.Close()
 73	buf := make([]byte, 2048)
 74
 75	for {
 76		// پیام ارسال شده توسط هر اتصال را به متغییر buf میدهیم
 77		n, err := conn.Read(buf)
 78		if err != nil {
 79			fmt.Println("read error:", err)
 80			continue
 81		}
 82
 83		s.msgch <- Message{
 84			// ادرس ip ارسال کننده پیام از نوع net.IP
 85			from:    conn.RemoteAddr().String(),
 86			// متن پیام
 87			payload: buf[:n],
 88		}
 89
 90		// بعد از دریافت هر پیام یک پیام به عنوان پاسخ ارسال میکنیم
 91		conn.Write([]byte("your message recived!\n"))
 92	}
 93}
 94
 95func main() {
 96	// ساخت سرور
 97	server := newServer(":3000")
 98	
 99	//start the server
100	if err := server.start(); err != nil {
101		log.Fetal(err)
102	}
103
104	go func() {
105		// در ازای هر پیام مقادیر آن را چاپ میکنیم
106		for msg := range server.msgch {
107			fmt.Printf("recived new from connection(%s): %s\n", msg.from, msg.payload)
108		}
109	}()
110
111	// Run an infinite loop to keep the program running
112	select {}
113
114}

بعد از پایان پیاده سازی سرور tcp با دستور زیر سرور خود را اجرا میکنیم: go run main.go

و با دستور زیر در یک ترمینال مجزا به سرور متصل میشویم: telnet localhost 3000

حال با نوشتن پیام و ارسال آن در ترمینال telnet متن پیام و ادرس اتصال در ترمینال سرور قابل مشاهده است.

توجه داشته باشید که دستور ‍telnet در ویندوز نیاز به فعال سازی دارد.