5.3 سرور tcp پیشرفته

5.3 سرور tcp پیشرفته

در این قسمت به طراحی و ساخت یک سرور tcp بصورت پیشرفته میپردازیم. در قسمت قبل بعد از ایجاد سرور TCP ساده با استفاده از کلاینت telnet به آن متصل شدیم و دیتایی را انتقال دادیم.

در این قسمت یک سرور tcp را با هدف انتقال فایل های حجیم بصورت جریان ایجاد میکنم.

قبل از شروع ایجاد سرور خود به دلیل اینکه چرا فایل های حجیم را استریم میکنیم و یا اصلا استریم چیست میپردازیم. زمانی که شما فایل های کم حجم را مستقیما انتقال میدهید با تاخیر کم و بصورت مطلوب انجام میشود. اما روایت برای فایل های سنگین تر متفاوت است، اگر این عمل بصورت مستقیم و یکجا انجام شود باعث ایجاد تاخیر و مصرف منابع بیش از حد روی سرور میشود. اما ما با استفاده از روش استریم، داده و فایل خود را بصورت قطعه های کم حجم و پشت سر هم ارسال میکنیم.

در ادامه به پیاده سازی سرور خود با استفاده از پروتکل tcp میپردازیم:

  1package main
  2
  3import (
  4	"bytes"
  5	"crypto/rand"
  6	"encoding/binary"
  7	"fmt"
  8	"io"
  9	"log"
 10	"net"
 11	"time"
 12)
 13
 14
 15type FileServer struct { }
 16
 17
 18func (fs *FileServer) start() {
 19	ln, err := net.Listen("tcp", "0.0.0.0:3000")
 20	if err != nil {
 21		panic(err)
 22	}
 23
 24	for {
 25		conn, err := ln.Accept()
 26
 27		if err != nil {
 28			log.Fatal(err)
 29			continue
 30		}
 31
 32		fmt.Printf("new connection: %s\n", conn.RemoteAddr().String())
 33
 34		// read data from accepted connections
 35		go fs.readLoop(conn)
 36	}
 37}
 38
 39func (fs *FileServer) readLoop(conn net.Conn) {
 40
 41	// make a new buffer
 42	buf := new(bytes.Buffer)
 43
 44	for {
 45 
 46		var size int64
 47  
 48		// get the size from connection
 49		binary.Read(conn, binary.LittleEndian, &size)
 50
 51		// copy from connection until the end of file
 52		n, err := io.CopyN(buf, conn, size)
 53		if err != nil {
 54			log.Fatal(err)
 55			continue
 56		}
 57
 58		fmt.Println(buf.Bytes())
 59		fmt.Printf("received %d bytes over the network\n", n)
 60	}
 61}
 62
 63func main() {
 64
 65	go func ()  {
 66 
 67		time.Sleep(4 * time.Second)
 68  
 69    // set your file szie
 70		sendFile(2000000)
 71	}()
 72
 73	s := &FileServer{}
 74	s.start()
 75}
 76
 77// client example that send a large file to server!
 78func sendFile(size int) error {
 79
 80	file := make([]byte, size)
 81
 82	// make a random file from the size provided
 83	_, err := io.ReadFull(rand.Reader, file)
 84	if err != nil {
 85		return err
 86	}
 87
 88	// dial with the tcp server (you can do this is an other file)
 89	conn, err := net.Dial("tcp", ":3000")
 90	if err != nil {
 91		return err
 92	}
 93
 94	// send the size of file
 95	binary.Write(conn, binary.LittleEndian, int64(size))
 96
 97	// copy file over the network until the end of file
 98	n, err := io.CopyN(conn, bytes.NewReader(file), int64(size))
 99	if err != nil {
100		return err
101	}
102
103	fmt.Printf("written %d byte over the network\n", n)
104	return nil
105}

بعد از پایان نوشتن کد شما میتوانید با اجرا کردن کد خود (ترجیحا انتخاب یک عدد بزرگ برای حجم فایل یا همان ورودی تابع sendFile) میتوانید استریم شدن بایت هارا بصورت چانک چانک در لاگ های سمت سرور ببینید.