Skip to content

Commit f1645f6

Browse files
authored
Merge pull request #394 from amirhasanpour/network-programming
Update network programming season
2 parents f535e38 + 4013389 commit f1645f6

File tree

7 files changed

+159
-109
lines changed

7 files changed

+159
-109
lines changed

content/chapter 5/5.10-quic-server.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,19 @@ func main() {
6161

6262
// this function start our echo server
6363
func echoServer() error {
64-
// make a new listner with quic
64+
// make a new listner with quic
6565
listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil)
6666
if err != nil {
6767
return err
6868
}
6969

70-
// accept incoming connections
70+
// accept incoming connections
7171
conn, err := listener.Accept(context.Background())
7272
if err != nil {
7373
return err
7474
}
7575

76-
// accept incoming streams
76+
// accept incoming streams
7777
stream, err := conn.AcceptStream(context.Background())
7878
if err != nil {
7979
panic(err)
@@ -84,33 +84,34 @@ func echoServer() error {
8484
return err
8585
}
8686

87-
// client function thah send the message to our server
87+
// client function that send the message to our server
8888
func clientMain() error {
89-
// set up a tls config
89+
// set up a tls config
9090
tlsConf := &tls.Config{
9191
InsecureSkipVerify: true,
9292
NextProtos: []string{"quic-echo-example"},
9393
}
94-
// dial with our udp server
94+
95+
// dial with our udp server
9596
conn, err := quic.DialAddr(context.Background(), addr, tlsConf, nil)
9697
if err != nil {
9798
return err
9899
}
99100

100-
// opening a new stream from our connection
101+
// opening a new stream from our connection
101102
stream, err := conn.OpenStreamSync(context.Background())
102103
if err != nil {
103104
return err
104105
}
105106

106-
// write the message over the stream
107+
// write the message over the stream
107108
fmt.Printf("Client: Sending '%s'\n", message)
108109
_, err = stream.Write([]byte(message))
109110
if err != nil {
110111
return err
111112
}
112113

113-
// read and print incoming answer from server
114+
// read and print incoming answer from server
114115
buf := make([]byte, len(message))
115116
_, err = io.ReadFull(stream, buf)
116117
if err != nil {
@@ -135,18 +136,21 @@ func generateTLSConfig() *tls.Config {
135136
if err != nil {
136137
panic(err)
137138
}
139+
138140
template := x509.Certificate{SerialNumber: big.NewInt(1)}
139141
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
140142
if err != nil {
141143
panic(err)
142144
}
145+
143146
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
144147
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
145148

146149
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
147150
if err != nil {
148151
panic(err)
149152
}
153+
150154
return &tls.Config{
151155
Certificates: []tls.Certificate{tlsCert},
152156
NextProtos: []string{"quic-echo-example"},

content/chapter 5/5.2-tcp-server-begginer.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
// ساختار هر پیام در سرور
2525
type Message struct {
2626
// ادرس ip ارسال کننده پیام
27-
from string
27+
from string
2828
// متن و محتوای پیام
2929
payload []byte
3030
}
@@ -34,9 +34,9 @@ type Server struct {
3434
// ادرس و یا پورت سرور
3535
listenAddr string
3636
// listener
37-
ln net.Listener
37+
ln net.Listener
3838
// چنل پیام برای انتقال پیام های دریافتی از اتصال ها بین گوروتین ها
39-
msgch chan Message
39+
msgch chan Message
4040
}
4141

4242
// ایجاد یک سرور جدید
@@ -97,7 +97,7 @@ func (s *Server) readLoop(conn net.Conn) {
9797

9898
s.msgch <- Message{
9999
// ادرس ip ارسال کننده پیام از نوع net.IP
100-
from: conn.RemoteAddr().String(),
100+
from: conn.RemoteAddr().String(),
101101
// متن پیام
102102
payload: buf[:n],
103103
}
@@ -113,7 +113,7 @@ func main() {
113113

114114
//start the server
115115
if err := server.start(); err != nil {
116-
log.Fetal(err)
116+
log.Fatal(err)
117117
}
118118

119119
go func() {

content/chapter 5/5.3-tcp-server-advanced.md

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ import (
3131
"time"
3232
)
3333

34-
35-
type FileServer struct { }
36-
34+
type FileServer struct{}
3735

3836
func (fs *FileServer) start() {
3937
ln, err := net.Listen("tcp", "0.0.0.0:3000")
@@ -57,12 +55,10 @@ func (fs *FileServer) start() {
5755
}
5856

5957
func (fs *FileServer) readLoop(conn net.Conn) {
60-
6158
// make a new buffer
6259
buf := new(bytes.Buffer)
6360

6461
for {
65-
6662
var size int64
6763

6864
// get the size from connection
@@ -81,12 +77,10 @@ func (fs *FileServer) readLoop(conn net.Conn) {
8177
}
8278

8379
func main() {
84-
85-
go func () {
86-
80+
go func() {
8781
time.Sleep(4 * time.Second)
8882

89-
// set your file szie
83+
// set your file szie
9084
sendFile(2000000)
9185
}()
9286

@@ -96,7 +90,6 @@ func main() {
9690

9791
// client example that send a large file to server!
9892
func sendFile(size int) error {
99-
10093
file := make([]byte, size)
10194

10295
// make a random file from the size provided

content/chapter 5/5.4-udp-server-begginer.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ weight: 9004
1111
پروتکل(User Datagram Protocol)
1212
یک پروتکل {{< tooltip text="فاقد اتصال" note="connectionless" >}} است.
1313
به این معنا که {{< tooltip text="بسته" note="packet" >}} های این پروتکل بدون اتصال قبلی و بررسی اینکه ایا همه بسته ها به درستی ارسال شده اند به دستگاه مورد نظر ارسال میشود.
14-
به همین دلیل سرعت در این پروتکل از پروتکل tcp پایین تر است اما تظمین ارسال کامل و سالم داده وجود ندارد.
14+
به همین دلیل سرعت در این پروتکل از پروتکل tcp بیشتر است اما تظمین ارسال کامل و سالم داده وجود ندارد.
1515
از موارد استفاده این پروتکل میتوان سرور بازی های انلاین را مثال زد.
1616

1717
## 5.4.2 پیاده سازی
@@ -26,9 +26,8 @@ import (
2626
"strings"
2727
)
2828

29-
3029
func main() {
31-
// ادرس IP و پورت مورد نظر را برای گوش سپردن به پکت های UDP مشخص میکنیم (مقدار بازگشتی این تابع اتصال ما است که قابلیت نوشتن و خواندن آن را داریم)
30+
// ادرس IP و پورت مورد نظر را برای گوش سپردن به پکت های UDP مشخص میکنیم (مقدار بازگشتی این تابع اتصال ما است که قابلیت نوشتن و خواندن آن را داریم)
3231
conn, err := net.ListenUDP("udp", &net.UDPAddr{
3332
Port: 3000,
3433
IP: net.ParseIP("0.0.0.0"),
@@ -42,16 +41,16 @@ func main() {
4241

4342
for {
4443
message := make([]byte, 20)
45-
// تمام پیام های نوشته شده (ارسال شده) را میخوانیم
46-
// متغییر message را با مقدار ارسال شده پر میکنیم (مقدار های بازگشتی این تابع طول پیام و آدرس ریموت ارسال کننده است)
44+
// تمام پیام های نوشته شده (ارسال شده) را میخوانیم
45+
// متغییر message را با مقدار ارسال شده پر میکنیم (مقدار های بازگشتی این تابع طول پیام و آدرس ریموت ارسال کننده است)
4746
readLen, remote, err := conn.ReadFromUDP(message[:])
4847
if err != nil {
4948
panic(err)
5049
}
5150

52-
// متن پیام را تا قسمت خوانده شده به string تبدیل میکنیم
51+
// متن پیام را تا قسمت خوانده شده به string تبدیل میکنیم
5352
data := strings.TrimSpace(string(message[:readLen]))
54-
// داده خروجی را چاپ میکنیم
53+
// داده خروجی را چاپ میکنیم
5554
fmt.Printf("received: %s from %s\n", data, remote)
5655
}
5756
}
@@ -68,12 +67,12 @@ package main
6867
import "net"
6968

7069
func main() {
71-
// یک اتصال به سرور ایجاد میکنیم
72-
Conn, _ := net.DialUDP("udp", nil, &net.UDPAddr{IP:[]byte{127,0,0,1},Port:3000,Zone:""})
70+
// یک اتصال به سرور ایجاد میکنیم
71+
Conn, _ := net.DialUDP("udp", nil, &net.UDPAddr{IP: []byte{127, 0, 0, 1}, Port: 3000, Zone: ""})
7372

74-
defer Conn.Close()
75-
// متن زیر را به سرور ارسال میکنیم
76-
Conn.Write([]byte("hello, gofarsi!"))
73+
defer Conn.Close()
74+
// متن زیر را به سرور ارسال میکنیم
75+
Conn.Write([]byte("hello, gofarsi!"))
7776
}
7877
{{< /play >}}
7978

content/chapter 5/5.7-http-server-advanced.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,50 @@ func main() {
105105
}
106106
{{< /play >}}
107107

108+
پیش از توضیح نحوه تست سرور http ایجاد شده، اجازه بدهید کمی درباره دو مفهوم
109+
کلیدی Encode و Decode که در کد بالا آمده است و ممکن است برای کسانی که تازه وارد بحث
110+
برنامه نویسی شبکه شده اند کمی گنگ باشد، توضیح بدهیم.
111+
112+
## توضیح Encode و Decode در کد
113+
در کدی که نوشتیم، دو عمل خیلی مهم وجود دارد: Encode و Decode. این‌ها مسئول تبدیل داده‌ها بین دنیای Go و دنیای JSON هستند.
114+
115+
### Encode
116+
هر وقت بخواهیم داده‌های سمت سرور (مثل یک struct یا slice) را به صورت JSON برای کلاینت بفرستیم، از Encode استفاده می‌کنیم.
117+
118+
مثلاً در تابع getTodos:
119+
120+
```go
121+
json.NewEncoder(w).Encode(todos)
122+
```
123+
124+
اینجا متغیر todos (که یک slice از structهای Todo است) گرفته می‌شود و به یک رشته JSON تبدیل می‌شود. خروجی نهایی چیزی شبیه به این خواهد بود:
125+
126+
```json
127+
[
128+
{"id": 1, "title": "Learn Go", "status": false},
129+
{"id": 2, "title": "Write Book", "status": true}
130+
]
131+
```
132+
133+
### Decode
134+
وقتی کلاینت داده‌ای را به سرور می‌فرستد (مثلاً با متد POST یا PATCH)، داده‌ها معمولاً در قالب JSON ارسال می‌شوند. ما باید این JSON را به یک struct در Go تبدیل کنیم تا بتوانیم راحت با آن کار کنیم. اینجاست که Decode به کار می‌آید.
135+
136+
مثلاً در تابع addTodo:
137+
138+
```go
139+
json.NewDecoder(r.Body).Decode(&todo)
140+
```
141+
142+
اینجا بدنه‌ی درخواست (r.Body) خوانده می‌شود و JSON داخل آن مثلاً:
143+
144+
```json
145+
{"title": "Buy milk", "status": false}
146+
```
147+
148+
به یک struct از نوع Todo تبدیل می‌شود و داخل متغیر todo قرار می‌گیرد.
149+
150+
## نحوه تست سرور http ایجاد شده
151+
108152
بعد از اتمام نوشتن سرور با استفاده از یک کلاینت `http` مثل postman سرور خود را به روش زیر تست میکنیم:
109153

110154
نکته: شما می توانید کلاینت خود را خودتان با استفاده از اموزش کلاینت http در قسمت های دیگر بنویسید!

content/chapter 5/5.8-http-client-begginer.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,33 @@ weight: 9008
1919
package main
2020

2121
import (
22-
"fmt"
23-
"io/ioutil"
24-
"net/http"
25-
"time"
22+
"fmt"
23+
"io"
24+
"net/http"
25+
"time"
2626
)
2727

2828
func main() {
29-
// کلاینت خود را با استفاده از ماژول http ایجاد میکنیم
30-
c := http.Client{Timeout: time.Duration(1) * time.Second}
31-
// از طریق کلاینت ایجاد شده یک درخواست با متد GET به آدرس example.com ارسال میکنیم
32-
// دقیقا سروری مشابه به سرور هایی که در قسمت های قبل ایجاد کردیم در آدرسی که الان به آن درخوایت ارسال میکنیم درحال گوش سپردن به درخواست ها میباشد.
33-
resp, err := c.Get("https://www.example.com")
34-
if err != nil {
35-
fmt.Printf("Error %s", err)
36-
return
37-
}
38-
defer resp.Body.Close()
39-
// مقادیر دریافت شده از سرور را میخوانیم و چاپ میکنیم
40-
body, err := ioutil.ReadAll(resp.Body)
41-
fmt.Printf("Body : %s", body)
29+
// کلاینت خود را با استفاده از ماژول http ایجاد میکنیم
30+
c := http.Client{Timeout: time.Duration(1) * time.Second}
31+
32+
// از طریق کلاینت ایجاد شده یک درخواست با متد GET به آدرس example.com ارسال میکنیم
33+
// دقیقا سروری مشابه به سرور هایی که در قسمت های قبل ایجاد کردیم در آدرسی که الان به آن درخوایت ارسال میکنیم درحال گوش سپردن به درخواست ها میباشد.
34+
resp, err := c.Get("https://www.example.com")
35+
if err != nil {
36+
fmt.Printf("Error %s", err)
37+
return
38+
}
39+
defer resp.Body.Close()
40+
41+
// مقادیر دریافت شده از سرور را میخوانیم و چاپ میکنیم
42+
body, err := io.ReadAll(resp.Body)
43+
if err != nil {
44+
fmt.Println("Error: ", err)
45+
return
46+
}
47+
48+
fmt.Printf("Body : %s", body)
4249
}
4350
{{< /play >}}
4451

0 commit comments

Comments
 (0)