در این قسمت به طراحی و ساخت یک سرور 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) میتوانید استریم شدن بایت هارا بصورت چانک چانک در لاگ های سمت سرور ببینید.