From 48a4d8367096fd2ceaad02017834c984d7246333 Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 20:25:15 +0300 Subject: [PATCH 1/7] update 02.7.md for turkish --- tr/02.7.md | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 tr/02.7.md diff --git a/tr/02.7.md b/tr/02.7.md new file mode 100644 index 000000000..3ed9c757f --- /dev/null +++ b/tr/02.7.md @@ -0,0 +1,250 @@ +# Concurrency + +Go'nun 21. yüzyılın C'si olduğu söyleniyor. Bence bunun iki nedeni var. Birincisi, Go basit bir dil. İkincisi, eşzamanlılık günümüz dünyasında çok popüler bir konu ve Go bu özelliği dil seviyesinde destekliyor. + +## goroutine + +goroutine'ler ve eşzamanlılık Go'nun çekirdek tasarımında yer almaktadır. Thread'lere benzerler ancak farklı çalışırlar. Go ayrıca goroutinlerinizde bellek paylaşımı için tam destek sağlar. Bir goroutine genellikle 4~5 KB yığın bellek kullanır. Bu nedenle, tek bir bilgisayarda binlerce goroutine çalıştırmak zor değildir. Bir goroutine, sistem iş parçacıklarından daha hafif, daha verimli ve daha kullanışlıdır. + +goroutine'ler Go'da çalışma zamanında iş parçacığı yöneticisi üzerinde çalışır. Temel düzeyde bir fonksiyon olan yeni bir goroutine oluşturmak için `go` anahtar sözcüğünü kullanırız ( ***main() bir goroutine'dir*** ). +```Go +go hello(a, b, c) +``` +Bir örnek görelim. +```Go +package main + +import ( + "fmt" + "runtime" +) + +func say(s string) { + for i := 0; i < 5; i++ { + runtime.Gosched() + fmt.Println(s) + } +} + +func main() { + go say("dünya") // yeni bir goroutine oluşturun + say("merhaba") // mevcut goroutine +} + +``` +Çıktı: +``` + merhaba + dünya + merhaba + dünya + merhaba + dünya + merhaba + dünya + merhaba +``` +Go'da `go` anahtar kelimesini kullanarak eşzamanlılığı kullanmanın çok kolay olduğunu görüyoruz. Yukarıdaki örnekte, bu iki goroutin bir miktar bellek paylaşmaktadır, ancak tasarım tarifini takip etmemiz daha iyi olacaktır: İletişim kurmak için paylaşılan verileri kullanmayın, veri paylaşmak için iletişimi kullanın. + +`runtime.Gosched()`, CPU'nun diğer goroutinleri yürütmesine ve bir noktada geri gelmesine izin vermek anlamına gelir. + +Go 1.5'te, çalışma zamanı artık `GOMAXPROCS` tarafından tanımlanan aynı anda çalışacak varsayılan iş parçacığı sayısını CPU'daki mevcut çekirdek sayısına göre ayarlamaktadır. + +Go 1.5'ten önce, zamanlayıcı tüm goroutinleri çalıştırmak için yalnızca bir iş parçacığı kullanır, bu da yalnızca eşzamanlılığı uyguladığı anlamına gelir. Paralel işlemeden yararlanmak için daha fazla CPU çekirdeği kullanmak istiyorsanız, kullanmak istediğiniz çekirdek sayısını ayarlamak için runtime.`GOMAXPROCS(n)` komutunu çağırmanız gerekir. Eğer `n<1` ise, hiçbir şey değişmez. + +## channels + +goroutinler aynı bellek adres alanında çalışır, bu nedenle paylaşılan belleğe erişmek istediğinizde senkronizasyonu sürdürmeniz gerekir. Farklı goroutinler arasında nasıl iletişim kurarsınız? Go, `channel` adı verilen çok iyi bir iletişim mekanizması kullanır. Bir `channel` Unix kabuklarındaki iki yönlü boru hattı gibidir: veri göndermek veya almak için `channel` kullanın. Kanallarda kullanılabilecek tek veri tipi `channel` tipi ve `chan` anahtar kelimesidir. Yeni bir `kanal` oluşturmak için `make` kullanmanız gerektiğini unutmayın. +```Go +ci := make(chan int) +cs := make(chan string) +cf := make(chan interface{}) +``` +kanalı veri göndermek veya almak için `<-` operatörünü kullanır. +```Go +ch <- v // v'yi kanal ch'ye gönderin. +v := <-ch // ch'den veri alır ve v'ye atar +``` +Daha fazla örnek görelim. +```Go +package main + +import "fmt" + +func sum(a []int, c chan int) { + total := 0 + for _, v := range a { + total += v + } + c <- total // toplamı c'ye gönder +} + +func main() { + a := []int{7, 2, 8, -9, 4, 0} + + c := make(chan int) + go sum(a[:len(a)/2], c) + go sum(a[len(a)/2:], c) + x, y := <-c, <-c // toplamı c'den al + + fmt.Println(x, y, x+y) +} + +``` +Kanallarda veri gönderme ve alma varsayılan olarak bloklanır, bu nedenle senkron goroutinleri kullanmak çok daha kolaydır. Bloktan kastım, bir goroutinin boş bir kanaldan veri alırken, yani (`value := <-ch`), diğer goroutinler bu kanala veri gönderene kadar devam etmeyeceğidir. Öte yandan, goroutine bir kanala gönderdiği veri, yani (`ch<-5`), alınana kadar devam etmeyecektir. + +## Buffered channels + +Yukarıda tamponlanmamış kanalları tanıttım. Go aynı zamanda tek bir elemandan daha fazlasını saklayabilen tamponlu kanallara da sahiptir. Örneğin, `ch := make(chan bool, 4)`, burada 4 boolean elemanı saklayabilen bir kanal oluşturuyoruz. Yani bu kanalın içine bloklama olmadan 4 eleman gönderebiliyoruz, ancak beşinci bir eleman göndermeye çalıştığınızda ve hiçbir goroutine bunu almadığında goroutine bloklanacaktır. +```Go +ch := make(chan type, n) + +n == 0 ! non-buffer(block) +n > 0 ! buffer(non-block until n elements in the channel) +``` +Aşağıdaki kodu bilgisayarınızda deneyebilir ve bazı değerleri değiştirebilirsiniz. +```Go +package main + +import "fmt" + +func main() { + c := make(chan int, 2) // 2'yi 1 olarak değiştirirseniz çalışma zamanı hatası olur, ancak 3 iyidir + c <- 1 + c <- 2 + fmt.Println(<-c) + fmt.Println(<-c) +} + +``` +## Range and Close + +Dilim ve eşlemede olduğu gibi tampon kanallar üzerinde çalışmak için aralığı kullanabiliriz. +```Go +package main + +import ( + "fmt" +) + +func fibonacci(n int, c chan int) { + x, y := 1, 1 + for i := 0; i < n; i++ { + c <- x + x, y = y, x+y + } + close(c) +} + +func main() { + c := make(chan int, 10) + go fibonacci(cap(c), c) + for i := range c { + fmt.Println(i) + } +} + +``` +`for i := range c` kanal kapatılana kadar kanaldan veri okumayı durdurmayacaktır. Yukarıdaki örnekte kanalı kapatmak için `close` anahtar sözcüğünü kullanıyoruz. Kapalı bir kanalda veri göndermek veya almak imkansızdır; bir kanalın kapalı olup olmadığını test etmek için `v, ok := <-ch` kullanabilirsiniz. Eğer `ok` false döndürürse, bu kanalda veri olmadığı ve kanalın kapalı olduğu anlamına gelir. + +Kanalları her zaman tüketicilerde değil üreticilerde kapatmayı unutmayın, aksi takdirde panik durumuna geçmek çok kolaydır. + +Hatırlamanız gereken bir başka şey de kanalların dosyalar gibi olmadığıdır. Kanalın tamamen yararsız olduğundan emin değilseniz veya aralık döngülerinden çıkmak istemiyorsanız, bunları sık sık kapatmanız gerekmez. + +## Select + +Yukarıdaki örneklerde sadece bir kanal kullandık, ancak birden fazla kanalla nasıl başa çıkabiliriz? Go, birçok kanalı dinlemek için `select` adlı bir anahtar kelimeye sahiptir. + +`select` varsayılan olarak engelleyicidir ve yalnızca kanallardan birinde gönderilecek veya alınacak veri olduğunda çalışmaya devam eder. Aynı anda birden fazla kanal kullanıma hazırsa, select hangisinin çalıştırılacağını rastgele seçer. +```Go +package main + +import "fmt" + +func fibonacci(c, quit chan int) { + x, y := 1, 1 + for { + select { + case c <- x: + x, y = y, x+y + case <-quit: + fmt.Println("quit") + return + } + } +} + +func main() { + c := make(chan int) + quit := make(chan int) + go func() { + for i := 0; i < 10; i++ { + fmt.Println(<-c) + } + quit <- 0 + }() + fibonacci(c, quit) +} + +``` +`select`in de tıpkı `switch` gibi bir `default` durumu vardır. Tüm kanallar kullanıma hazır olmadığında, varsayılan durumu çalıştırır (artık kanalı beklemez). +```Go +select { +case i := <-c: +// use i +default: +// executes here when c is blocked +} +``` +## Timeout + +Bazen bir goroutine bloke olur. Tüm programın bloke olmasını önlemek için bunu nasıl önleyebiliriz? Çok basit, select içinde bir zaman aşımı ayarlayabiliriz. +```Go +func main() { + c := make(chan int) + o := make(chan bool) + go func() { + for { + select { + case v := <-c: + println(v) + case <-time.After(5 * time.Second): + println("timeout") + o <- true + break + } + } + }() + <-o +} + +``` +## Runtime goroutine + +`runtime` paketi goroutine'lerle çalışmak için bazı fonksiyonlara sahiptir. + +- `runtime.Goexit()` + + Geçerli goroutine'den çıkar, ancak ertelenen işlevler her zamanki gibi yürütülür. + +- `runtime.Gosched()` + + Zamanlayıcının diğer goroutinleri yürütmesine ve bir noktada geri gelmesine izin verir. + +- `runtime.NumCPU() int` + + CPU çekirdeği sayısını döndürür + +- `runtime.NumGoroutine() int` + + Goroutin sayısını döndürür + +- `runtime.GOMAXPROCS(n int) int` + + Kaç CPU çekirdeği kullanmak istediğinizi ayarlar + +## Links + +- [Directory](preface.md) +- Önceki bölüm: [interface](02.6.md) +- Sonraki bölüm: [Summary](02.8.md) From 9de95b09d70dc91f88e2366b448d12fbd7f9690f Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 20:34:36 +0300 Subject: [PATCH 2/7] update 02.8.md for Turkish --- tr/02.8.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tr/02.8.md diff --git a/tr/02.8.md b/tr/02.8.md new file mode 100644 index 000000000..bc907e8cb --- /dev/null +++ b/tr/02.8.md @@ -0,0 +1,32 @@ +# 2.8 Özet + +Bu bölümde temel olarak 25 Go anahtar kelimesini tanıttık. Şimdi bunların ne olduklarını ve ne işe yaradıklarını gözden geçirelim. +```Go + break default func interface select + case defer go map struct + chan else goto package switch + const fallthrough if range type + continue for import return var +``` +- `var` ve `const` değişkenleri ve sabitleri tanımlamak için kullanılır. +- `package` ve `import` paket kullanımı içindir. +- `func` fonksiyonları ve metotları tanımlamak için kullanılır. +- `return` fonksiyonlarda veya metotlarda değer döndürmek için kullanılır. +- `defer`, defer fonksiyonlarını tanımlamak için kullanılır. +- `go` yeni bir goroutine başlatmak için kullanılır. +- `select` iletişim için birden fazla kanal arasında geçiş yapmak için kullanılır. +- `interface` arayüzleri tanımlamak için kullanılır. +- `struct` özel özelleştirilmiş türleri tanımlamak için kullanılır. +- `break`, `case`, `continue`, `for`, `fallthrough`, `else`, `if`, `switch`, `goto` ve `default` bölüm 2.3'te tanıtılmıştır. +- `chan` goroutinler arasındaki iletişim için kullanılan kanal türüdür. +- `type` özelleştirilmiş türleri tanımlamak için kullanılır. +- `map` diğer dillerdeki hash tablolarına benzeyen map tanımlamak için kullanılır. +- `range`, `slice`, `map` ve `channel`'dan veri okumak için kullanılır. + +Bu 25 anahtar kelimeyi nasıl kullanacağınızı anladıysanız, Go hakkında çok şey öğrenmişsiniz demektir. + +## Bağlantılar + +- [Directory](preface.md) +- Önceki bölüm: [Eşzamanlılık](02.7.md) +- Sonraki bölüm: [Web vakfı](03.0.md) From 284c9d1b8e25399a06e7b0b08a26267c78569d53 Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 20:42:14 +0300 Subject: [PATCH 3/7] update next and previous title --- tr/02.7.md | 4 ++-- tr/02.8.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tr/02.7.md b/tr/02.7.md index 3ed9c757f..36cebb066 100644 --- a/tr/02.7.md +++ b/tr/02.7.md @@ -246,5 +246,5 @@ func main() { ## Links - [Directory](preface.md) -- Önceki bölüm: [interface](02.6.md) -- Sonraki bölüm: [Summary](02.8.md) +- Önceki bölüm: [Interface - Arayüz](02.6.md) +- Sonraki bölüm: [Summary - Özet](02.8.md) diff --git a/tr/02.8.md b/tr/02.8.md index bc907e8cb..b831220ba 100644 --- a/tr/02.8.md +++ b/tr/02.8.md @@ -25,7 +25,7 @@ Bu bölümde temel olarak 25 Go anahtar kelimesini tanıttık. Şimdi bunların Bu 25 anahtar kelimeyi nasıl kullanacağınızı anladıysanız, Go hakkında çok şey öğrenmişsiniz demektir. -## Bağlantılar +## Links - [Directory](preface.md) - Önceki bölüm: [Eşzamanlılık](02.7.md) From c99eff076bc5ef8af7a85a0ed3acac2444772c1f Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 20:47:19 +0300 Subject: [PATCH 4/7] update title --- tr/02.7.md | 20 ++++++++++---------- tr/02.8.md | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tr/02.7.md b/tr/02.7.md index 36cebb066..e205a35b3 100644 --- a/tr/02.7.md +++ b/tr/02.7.md @@ -1,8 +1,8 @@ -# Concurrency +# Concurrency - Eşzamanlılık Go'nun 21. yüzyılın C'si olduğu söyleniyor. Bence bunun iki nedeni var. Birincisi, Go basit bir dil. İkincisi, eşzamanlılık günümüz dünyasında çok popüler bir konu ve Go bu özelliği dil seviyesinde destekliyor. -## goroutine +## Goroutine goroutine'ler ve eşzamanlılık Go'nun çekirdek tasarımında yer almaktadır. Thread'lere benzerler ancak farklı çalışırlar. Go ayrıca goroutinlerinizde bellek paylaşımı için tam destek sağlar. Bir goroutine genellikle 4~5 KB yığın bellek kullanır. Bu nedenle, tek bir bilgisayarda binlerce goroutine çalıştırmak zor değildir. Bir goroutine, sistem iş parçacıklarından daha hafif, daha verimli ve daha kullanışlıdır. @@ -52,7 +52,7 @@ Go 1.5'te, çalışma zamanı artık `GOMAXPROCS` tarafından tanımlanan aynı Go 1.5'ten önce, zamanlayıcı tüm goroutinleri çalıştırmak için yalnızca bir iş parçacığı kullanır, bu da yalnızca eşzamanlılığı uyguladığı anlamına gelir. Paralel işlemeden yararlanmak için daha fazla CPU çekirdeği kullanmak istiyorsanız, kullanmak istediğiniz çekirdek sayısını ayarlamak için runtime.`GOMAXPROCS(n)` komutunu çağırmanız gerekir. Eğer `n<1` ise, hiçbir şey değişmez. -## channels +## Channels - Kanallar goroutinler aynı bellek adres alanında çalışır, bu nedenle paylaşılan belleğe erişmek istediğinizde senkronizasyonu sürdürmeniz gerekir. Farklı goroutinler arasında nasıl iletişim kurarsınız? Go, `channel` adı verilen çok iyi bir iletişim mekanizması kullanır. Bir `channel` Unix kabuklarındaki iki yönlü boru hattı gibidir: veri göndermek veya almak için `channel` kullanın. Kanallarda kullanılabilecek tek veri tipi `channel` tipi ve `chan` anahtar kelimesidir. Yeni bir `kanal` oluşturmak için `make` kullanmanız gerektiğini unutmayın. ```Go @@ -93,7 +93,7 @@ func main() { ``` Kanallarda veri gönderme ve alma varsayılan olarak bloklanır, bu nedenle senkron goroutinleri kullanmak çok daha kolaydır. Bloktan kastım, bir goroutinin boş bir kanaldan veri alırken, yani (`value := <-ch`), diğer goroutinler bu kanala veri gönderene kadar devam etmeyeceğidir. Öte yandan, goroutine bir kanala gönderdiği veri, yani (`ch<-5`), alınana kadar devam etmeyecektir. -## Buffered channels +## Buffered Channels - Tamponlanmış Kanallar Yukarıda tamponlanmamış kanalları tanıttım. Go aynı zamanda tek bir elemandan daha fazlasını saklayabilen tamponlu kanallara da sahiptir. Örneğin, `ch := make(chan bool, 4)`, burada 4 boolean elemanı saklayabilen bir kanal oluşturuyoruz. Yani bu kanalın içine bloklama olmadan 4 eleman gönderebiliyoruz, ancak beşinci bir eleman göndermeye çalıştığınızda ve hiçbir goroutine bunu almadığında goroutine bloklanacaktır. ```Go @@ -117,7 +117,7 @@ func main() { } ``` -## Range and Close +## Range and Close - Aralık ve Kapanış Dilim ve eşlemede olduğu gibi tampon kanallar üzerinde çalışmak için aralığı kullanabiliriz. ```Go @@ -151,7 +151,7 @@ Kanalları her zaman tüketicilerde değil üreticilerde kapatmayı unutmayın, Hatırlamanız gereken bir başka şey de kanalların dosyalar gibi olmadığıdır. Kanalın tamamen yararsız olduğundan emin değilseniz veya aralık döngülerinden çıkmak istemiyorsanız, bunları sık sık kapatmanız gerekmez. -## Select +## Select - Seçim Yukarıdaki örneklerde sadece bir kanal kullandık, ancak birden fazla kanalla nasıl başa çıkabiliriz? Go, birçok kanalı dinlemek için `select` adlı bir anahtar kelimeye sahiptir. @@ -196,7 +196,7 @@ default: // executes here when c is blocked } ``` -## Timeout +## Timeout - Zaman Aşımı Bazen bir goroutine bloke olur. Tüm programın bloke olmasını önlemek için bunu nasıl önleyebiliriz? Çok basit, select içinde bir zaman aşımı ayarlayabiliriz. ```Go @@ -219,7 +219,7 @@ func main() { } ``` -## Runtime goroutine +## Runtime Goroutine - Çalışma Zamanı `runtime` paketi goroutine'lerle çalışmak için bazı fonksiyonlara sahiptir. @@ -243,8 +243,8 @@ func main() { Kaç CPU çekirdeği kullanmak istediğinizi ayarlar -## Links +## Links - Linkler - [Directory](preface.md) -- Önceki bölüm: [Interface - Arayüz](02.6.md) +- Önceki bölüm: [Interface - Arabirim](02.6.md) - Sonraki bölüm: [Summary - Özet](02.8.md) diff --git a/tr/02.8.md b/tr/02.8.md index b831220ba..ab37e2981 100644 --- a/tr/02.8.md +++ b/tr/02.8.md @@ -25,7 +25,7 @@ Bu bölümde temel olarak 25 Go anahtar kelimesini tanıttık. Şimdi bunların Bu 25 anahtar kelimeyi nasıl kullanacağınızı anladıysanız, Go hakkında çok şey öğrenmişsiniz demektir. -## Links +## Linkler - [Directory](preface.md) - Önceki bölüm: [Eşzamanlılık](02.7.md) From d029a8a58dc911d9d7d3b8c44cb1c2bc55ee9f23 Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 21:17:09 +0300 Subject: [PATCH 5/7] update title --- tr/02.7.md | 4 ++-- tr/02.8.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tr/02.7.md b/tr/02.7.md index e205a35b3..5b2eac398 100644 --- a/tr/02.7.md +++ b/tr/02.7.md @@ -243,8 +243,8 @@ func main() { Kaç CPU çekirdeği kullanmak istediğinizi ayarlar -## Links - Linkler +## Linkler -- [Directory](preface.md) +- [İçerik](preface.md) - Önceki bölüm: [Interface - Arabirim](02.6.md) - Sonraki bölüm: [Summary - Özet](02.8.md) diff --git a/tr/02.8.md b/tr/02.8.md index ab37e2981..7411129c3 100644 --- a/tr/02.8.md +++ b/tr/02.8.md @@ -27,6 +27,6 @@ Bu 25 anahtar kelimeyi nasıl kullanacağınızı anladıysanız, Go hakkında ## Linkler -- [Directory](preface.md) +- [İçerik](preface.md) - Önceki bölüm: [Eşzamanlılık](02.7.md) - Sonraki bölüm: [Web vakfı](03.0.md) From 223aefaad688807c9317ea8b9848d25af8d238ed Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 21:50:57 +0300 Subject: [PATCH 6/7] update next section --- tr/02.8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tr/02.8.md b/tr/02.8.md index 7411129c3..c31e87eeb 100644 --- a/tr/02.8.md +++ b/tr/02.8.md @@ -29,4 +29,4 @@ Bu 25 anahtar kelimeyi nasıl kullanacağınızı anladıysanız, Go hakkında - [İçerik](preface.md) - Önceki bölüm: [Eşzamanlılık](02.7.md) -- Sonraki bölüm: [Web vakfı](03.0.md) +- Sonraki bölüm: [Web Temel Kuruluşu](03.0.md) From 432954f55d0afd45a2179a5e6c2b7ce938d7d0e2 Mon Sep 17 00:00:00 2001 From: mstgnz Date: Fri, 12 Jan 2024 21:55:47 +0300 Subject: [PATCH 7/7] update 03.* for Turkish --- tr/03.0.md | 9 +++ tr/03.1.md | 155 +++++++++++++++++++++++++++++++++++++++ tr/03.2.md | 67 +++++++++++++++++ tr/03.3.md | 86 ++++++++++++++++++++++ tr/03.4.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tr/03.5.md | 11 +++ 6 files changed, 535 insertions(+) create mode 100644 tr/03.0.md create mode 100644 tr/03.1.md create mode 100644 tr/03.2.md create mode 100644 tr/03.3.md create mode 100644 tr/03.4.md create mode 100644 tr/03.5.md diff --git a/tr/03.0.md b/tr/03.0.md new file mode 100644 index 000000000..b04e61651 --- /dev/null +++ b/tr/03.0.md @@ -0,0 +1,9 @@ +# 3 Web Temel Kuruluşu + +Bu kitabı okumanızın nedeni, Go'da web uygulamaları oluşturmayı öğrenmek istemenizdir. Daha önce de söylediğim gibi, Go `http` gibi birçok güçlü paket sağlar. Bu paketler web uygulamaları oluşturmaya çalışırken size çok yardımcı olabilir. İlerleyen bölümlerde size bilmeniz gereken her şeyi öğreteceğim ve bu bölümde web ile ilgili bazı kavramlardan ve web uygulamalarının Go'da nasıl çalıştırılacağından bahsedeceğiz. + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Bölüm 2 Özet](02.8.md) +- Sonraki bölüm: [Web Çalışma Prensipleri](03.1.md) diff --git a/tr/03.1.md b/tr/03.1.md new file mode 100644 index 000000000..e707879d2 --- /dev/null +++ b/tr/03.1.md @@ -0,0 +1,155 @@ +# Web Çalışma Prensipleri + +Tarayıcınızı her açtığınızda, bazı URL'ler yazıp enter tuşuna bastığınızda, ekranınızda güzel web sayfalarının belirdiğini göreceksiniz. Peki bu basit eylemlerin arkasında neler olduğunu biliyor musunuz? + +Normalde tarayıcınız bir istemcidir. Siz bir URL yazdıktan sonra, URL'nin ana bilgisayar kısmını alır ve ana bilgisayarın IP adresini almak için bir Alan Adı Sunucusuna (DNS) gönderir. Daha sonra IP adresine bağlanır ve bir TCP bağlantısı kurulmasını ister. Tarayıcı bağlantı üzerinden HTTP istekleri gönderir. Sunucu bunları ele alır ve web sayfasını oluşturan içeriği içeren HTTP yanıtlarıyla yanıt verir. Son olarak, tarayıcı web sayfasının gövdesini oluşturur ve sunucuyla bağlantısını keser. + +![](images/3.1.web2.png?raw=true) + +Şekil 3.1 Bir web sitesini ziyaret eden kullanıcıların süreçleri + +HTTP sunucusu olarak da bilinen bir web sunucusu, istemcilerle iletişim kurmak için HTTP protokolünü kullanır. Tüm web tarayıcıları istemci olarak kabul edilebilir. + +Web'in çalışma prensiplerini aşağıdaki adımlara ayırabiliriz: + +- İstemci sunucuya bağlanmak için TCP/IP protokolünü kullanır. +- İstemci sunucuya HTTP istek paketleri gönderir. +- Sunucu HTTP yanıt paketlerini istemciye döndürür. İstenen kaynaklar dinamik komut dosyaları içeriyorsa, sunucu önce komut dosyası motorunu çağırır. +- İstemci sunucu bağlantısını keser, HTML oluşturmaya başlar. + +Bu, HTTP işlerinin basit bir iş akışıdır - sunucunun istemcilere veri gönderdikten sonra bağlantılarını kapattığına ve ardından bir sonraki isteği beklediğine dikkat edin. + +## URL ve DNS çözünürlüğü + +Web sayfalarına erişmek için her zaman URL'leri kullanırız, ancak URL'lerin nasıl çalıştığını biliyor musunuz? + +URL'nin tam adı Uniform Resource Locator'dır. İnternet üzerindeki kaynakları tanımlamak için kullanılır ve temel şekli aşağıdaki gibidir. + + scheme://host[:port#]/path/.../[?query-string][#anchor] + scheme temel protokolü atama (HTTP, HTTPS, FTP gibi) + host HTTP sunucusunun IP veya alan adı + port# varsayılan bağlantı noktası 80'dir ve bu durumda atlanabilir. + Başka bağlantı noktaları kullanmak istiyorsanız, hangi bağlantı noktasını kullanacağınızı belirtmeniz gerekir. Örneğin, + http://www.cnblogs.com:8080/ + path kaynaklar yolu + query-string veriler sunucuya gönderilir + anchor çapa + +DNS, Alan Adı Sisteminin kısaltmasıdır. Bilgisayar ağı hizmetleri için adlandırma sistemidir ve tıpkı bir çevirmen gibi alan adlarını gerçek IP adreslerine dönüştürür. + +![](images/3.1.dns_hierachy.png?raw=true) + +Şekil 3.2 DNS çalışma prensipleri + +Çalışma prensibi hakkında daha fazla bilgi edinmek için aşağıdaki detaylı DNS çözümleme sürecini görelim. + +1. Tarayıcıya `www.qq.com` alan adını yazdıktan sonra, işletim sistemi bu alan adı için hosts dosyalarında herhangi bir eşleme ilişkisi olup olmadığını kontrol edecektir. Eğer varsa, alan adı çözümlemesi tamamlanmıştır. +2. Ana bilgisayar dosyalarında herhangi bir eşleme ilişkisi yoksa, işletim sistemi DNS'de herhangi bir önbellek olup olmadığını kontrol eder. Eğer varsa, alan adı çözümlemesi tamamlanmıştır. +3. Hem ana bilgisayar hem de DNS önbelleğinde herhangi bir eşleme ilişkisi yoksa, işletim sistemi TCP/IP ayarlarınızdaki ilk DNS çözümleme sunucusunu bulur; bu da muhtemelen yerel DNS sunucunuzdur. Yerel DNS sunucusu sorguyu aldığında, sorgulamak istediğiniz etki alanı adı bölgesel kaynaklarının yerel yapılandırmasında bulunuyorsa, sonuçları istemciye döndürür. Bu DNS çözümlemesi yetkilidir. +4. Yerel DNS sunucusu alan adını içermiyorsa ancak önbellekte bir eşleme ilişkisi varsa, yerel DNS sunucusu bu sonucu istemciye geri verir. Bu DNS çözümlemesi yetkili değildir. +5. Yerel DNS sunucusu, bölgesel kaynakların yapılandırılması veya önbellek nedeniyle bu alan adını çözümleyemezse, yerel DNS sunucusunun ayarlarına bağlı olan bir sonraki adıma geçer. + -Yerel DNS sunucusu yönlendirmeyi etkinleştirmezse, isteği kök DNS sunucusuna yönlendirir, ardından alan adını (bu durumda `.com`) bilen bir üst düzey DNS sunucusunun IP adresini döndürür. İlk üst düzey DNS sunucusu alan adını tanımazsa, alan adını tanıyan bir sunucuya ulaşana kadar isteği bir sonraki üst düzey DNS sunucusuna yönlendirir. Daha sonra en üst düzey DNS sunucusu bu bir üst düzey DNS sunucusundan `www.qq.com` adresine karşılık gelen IP adresini ister. + -Yerel DNS sunucusunda yönlendirme etkinse, isteği bir üst düzey DNS sunucusuna gönderir. Üst düzey DNS sunucusu da alan adını tanımazsa, istek sonunda alan adını tanıyan bir DNS sunucusuna ulaşana kadar daha üst düzeylere yönlendirilmeye devam eder. + +Yerel DNS sunucusu yönlendirmeyi etkinleştirse de etkinleştirmese de, alan adının IP adresi her zaman yerel DNS sunucusuna döner ve yerel DNS sunucusu bunu istemciye geri gönderir. + +![](images/3.1.dns_inquery.png?raw=true) + +Şekil 3.3 DNS çözümleme iş akışı + +`Recursive query process - Yinelemeli sorgu süreci` basitçe sorgulayıcıların süreç içinde değiştiği anlamına gelir. Yinelemeli sorgu süreçlerinde sorgulayıcılar değişmez. + +Artık istemcilerin sonunda IP adresleri aldığını biliyoruz, bu nedenle tarayıcılar sunucularla IP adresleri üzerinden iletişim kuruyor. + +## HTTP protokolü + +HTTP protokolü web hizmetlerinin temel bir parçasıdır. Web'in nasıl çalıştığını anlamadan önce HTTP protokolünün ne olduğunu bilmek önemlidir. + +HTTP, tarayıcı ve web sunucusu arasındaki iletişimi kolaylaştırmak için kullanılan protokoldür. TCP protokolüne dayanır ve genellikle web sunucusu tarafında 80 numaralı bağlantı noktasını kullanır. İstek-yanıt modelini kullanan bir protokoldür -istemciler istek gönderir ve sunucular yanıt verir. HTTP protokolüne göre, istemciler her zaman yeni bağlantılar kurar ve sunuculara HTTP istekleri gönderir. Sunucular istemcilere proaktif olarak bağlanamaz veya geri arama bağlantıları kuramaz. Bir istemci ile sunucu arasındaki bağlantı her iki tarafça da kapatılabilir. Örneğin, indirme isteğinizi ve HTTP bağlantınızı iptal edebilirsiniz ve tarayıcınız siz indirmeyi bitirmeden önce sunucuyla bağlantıyı kesecektir. + +HTTP protokolü durumsuzdur, yani her ikisi de aynı istemciden gelse bile sunucunun iki bağlantı arasındaki ilişki hakkında hiçbir fikri yoktur. Bu sorunu çözmek için, web uygulamaları bağlantıların durumunu korumak için çerezler kullanır. + +HTTP protokolü TCP protokolüne dayandığından, tüm TCP saldırıları sunucunuzdaki HTTP iletişimini etkileyecektir. Bu tür saldırılara örnek olarak SYN flooding, DoS ve DDoS saldırıları verilebilir. + +### HTTP istek paketi (tarayıcı bilgileri) + +İstek paketlerinin tümü üç bölümden oluşur: istek satırı, istek başlığı ve gövde. Başlık ve gövde arasında bir boş satır vardır. + + GET /domains/example/ HTTP/1.1 // istek satırı: istek yöntemi, URL, protokol ve sürümü + Host:www.iana.org // alan adı + User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 // tarayıcı bilgileri + Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 // istemcilerin kabul edebileceği mime + Accept-Encoding:gzip,deflate,sdch // akış sıkıştırma + Accept-Charset:UTF-8,*;q=0.5 // istemci tarafında karakter kümesi + // boş satır + // gövde, istek kaynağı argümanları (örneğin, POST'taki argümanlar) + +Aşağıdaki istek bilgilerini almak için fiddler kullanıyoruz. + +![](images/3.1.http.png?raw=true) + +Şekil 3.4 Fiddler tarafından yakalanan bir GET isteğinin bilgileri + +![](images/3.1.httpPOST.png?raw=true) + +Şekil 3.5 Fiddler tarafından yakalanan bir POST isteğinin bilgileri + +**GET'in, POST'un aksine bir istek gövdesine sahip olmadığını görebiliriz.** + +HTTP'de sunucularla iletişim kurmak için kullanabileceğiniz birçok yöntem vardır; GET, POST, PUT ve DELETE genellikle kullandığımız 4 temel yöntemdir. Bir URL ağ üzerindeki bir kaynağı temsil eder, dolayısıyla bu 4 yöntem bu kaynaklar üzerinde işlem yapabilecek sorgulama, değiştirme, ekleme ve silme işlemlerini tanımlar. GET ve POST HTTP'de çok yaygın olarak kullanılır. GET, URL ve parametreleri ayırmak için `?` ve argümanlar arasında `&` kullanarak sorgu parametrelerini URL'ye ekleyebilir, örneğin `EditPosts.aspx?name=test1&id=123456`. URL, tarayıcı aracılığıyla bir uzunluk sınırlaması uyguladığından POST, verileri istek gövdesine koyar. Böylece POST, GET'e göre çok daha fazla veri gönderebilir. Ayrıca, kullanıcı adlarını ve parolaları gönderdiğimizde, bu tür bilgilerin URL'de görünmesini istemeyiz, bu nedenle bunları görünmez tutmak için POST kullanırız. + +### HTTP yanıt paketi (sunucu bilgileri) + +Yanıt paketlerinde hangi bilgilerin yer aldığını görelim. + + HTTP/1.1 200 OK // durum satırı + Server: nginx/1.0.8 // web sunucusu yazılımı ve sunucu makinesindeki sürümü + Date:Date: Tue, 30 Oct 2012 04:14:25 GMT // yanıt verilen zaman + Content-Type: text/html // yanıtlanan veri türü + Transfer-Encoding: chunked // verilerin parçalar halinde gönderildiği anlamına gelir + Connection: keep-alive // bağlantıyı sürdür + Content-Length: 90 // gövde uzunluğu + // boş satır + max { + tempDelay = max + } + log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) + time.Sleep(tempDelay) + continue + } + return e + } + tempDelay = 0 + c, err := srv.newConn(rw) + if err != nil { + continue + } + go c.serve() + } +} +``` + +Bir portu dinlemeye başladıktan sonra istemci isteklerini nasıl kabul ederiz? Kaynak kodda, istemci isteklerini işlemek için `srv.Serve(net.Listener)` fonksiyonunun çağrıldığını görebiliriz. Fonksiyonun gövdesinde bir `for{}` vardır. Bir isteği kabul eder, yeni bir bağlantı oluşturur ve ardından yeni bir goroutine başlatarak istek verilerini `go c.serve()` goroutine'ine aktarır. Go yüksek eşzamanlılığı bu şekilde destekler ve her goroutine bağımsızdır. + +İstekleri işlemek için belirli fonksiyonları nasıl kullanırız? `conn` ilk önce `c.ReadRequest()` isteğini ayrıştırır, sonra ilgili işleyiciyi alır: `handler := sh.srv.Handler`, `ListenAndServe` fonksiyonunu çağırdığımızda verdiğimiz ikinci argümandır. Biz `nil` değerini verdiğimiz için, Go varsayılan işleyicisi `handler = DefaultServeMux` değerini kullanır. Peki `DefaultServeMux` burada ne yapıyor? Belirli URL'ler için işleyici fonksiyonlarını çağırabilen yönlendirici değişkeni. Bunu ayarladık mı? Evet, ayarladık. Bunu `http.HandleFunc("/", sayhelloName)` kullandığımız ilk satırda yaptık. Bu fonksiyonu "/" yolu için yönlendirici kuralını kaydetmek için kullanıyoruz. URL `/` olduğunda, yönlendirici `sayhelloName` fonksiyonunu çağırır. DefaultServeMux, farklı yollar için işleyici işlevleri almak üzere ServerHTTP'yi çağırır ve bu özel durumda `sayhelloName` işlevini çağırır. Son olarak, sunucu verileri yazar ve istemcilere yanıt verir. + +Detaylı iş akışı: + +![](images/3.3.illustrator.png?raw=true) + +Şekil 3.10 Bir HTTP isteğinin ele alınmasına ilişkin iş akışı + +Sanırım artık Go'nun web sunucularını nasıl çalıştırdığını biliyor olmalısınız. + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Basit bir web sunucusu oluşturma](03.2.md) +- Sonraki bölüm: [Http paketine girin](03.4.md) diff --git a/tr/03.4.md b/tr/03.4.md new file mode 100644 index 000000000..0ecd88ed8 --- /dev/null +++ b/tr/03.4.md @@ -0,0 +1,207 @@ +# 3.4 Http paketine girin + +Önceki bölümlerde, web'in iş akışını öğrendik ve Go'nun `http` paketinden biraz bahsettik. Bu bölümde, `http` paketindeki iki temel fonksiyon hakkında bilgi edineceğiz: Conn ve ServeMux. + +## Conn'da goroutine + +Normal HTTP sunucularından farklı olarak Go, yüksek eşzamanlılık ve performans elde etmek için Conn tarafından başlatılan her iş için goroutine kullanır, böylece her iş bağımsızdır. + +Go, istemcilerden gelen yeni bağlantıları beklemek için aşağıdaki kodu kullanır. +```Go +c, err := srv.newConn(rw) +if err != nil { + continue +} +go c.serve() +``` +Gördüğünüz gibi, her bağlantı için yeni bir goroutine oluşturuyor ve istekten veri okuyabilen işleyiciyi goroutine'e geçiriyor. + +## Özelleştirilmiş ServeMux + +Önceki bölümlerde conn.server'ı tartışırken Go'nun varsayılan yönlendiricisini kullandık, yönlendirici istek verilerini bir arka uç işleyicisine aktarıyordu. + +Varsayılan yönlendiricinin yapısı: +```Go +type ServeMux struct { + mu sync.RWMutex // eşzamanlılık nedeniyle burada bir muteks kullanmak zorundayız + m map[string]muxEntry // yönlendirici kuralları, bir işleyiciyle eşleşen her dize +} +``` +muxEntry'nin yapısı: +```Go +type muxEntry struct { + explicit bool // tam eşleşme ya da değil + h Handler +} +``` +İşleyici arayüzü: +```Go +type Handler interface { + ServeHTTP(ResponseWriter, *Request) // yönlendi̇rme uygulayıcısı +} +``` +`Handler` bir arayüzdür, ama eğer `sayhelloName` fonksiyonu bu arayüzü uygulamıyorsa, o zaman onu nasıl handler olarak ekledik? Cevap, `http` paketindeki `HandlerFunc` adlı başka bir türde yatmaktadır. Biz `sayhelloName` metodumuzu tanımlamak için `HandlerFunc` çağırdık, böylece `sayhelloName` aynı zamanda `Handler` metodunu da implemente etti. Sanki `HandlerFunc(f)` çağırıyoruz ve `f` fonksiyonu zorla `HandlerFunc` tipine dönüştürülüyor. +```Go +type HandlerFunc func(ResponseWriter, *Request) + +// ServeHTTP f(w, r)'yi çağırır. +func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { + f(w, r) +} +``` +Yönlendirici kurallarını belirledikten sonra yönlendirici işleyicileri nasıl çağırır? + +Yönlendirici, istekleri aldığında `mux.handler.ServeHTTP(w, r)` arayüzünü çağırır. Başka bir deyişle, kendisini uygulayan işleyicilerin `ServeHTTP` arayüzünü çağırır. + +Şimdi, `mux.handler`ın nasıl çalıştığını görelim. +```Go +func (mux *ServeMux) handler(r *Request) Handler { + mux.mu.RLock() + defer mux.mu.RUnlock() + + // Ana bilgisayara özgü kalıp, genel olanlara göre önceliklidir + h := mux.match(r.Host + r.URL.Path) + if h == nil { + h = mux.match(r.URL.Path) + } + if h == nil { + h = NotFoundHandler() + } + return h +} +``` +Yönlendirici, eşlemede kayıtlı ilgili işleyiciyi bulmak için isteğin URL'sini bir anahtar olarak kullanır, ardından verileri işleyecek işlevleri yürütmek için handler.ServeHTTP'yi çağırır. + +Şimdiye kadar varsayılan yönlendiricinin iş akışını anlamış olmalısınız ve Go aslında özelleştirilmiş yönlendiricileri destekler. `ListenAndServe`ün ikinci argümanı özelleştirilmiş yönlendiricileri yapılandırmak içindir. Bu bir `Handler` arayüzüdür. Bu nedenle, `Handler` arayüzünü uygulayan herhangi bir yönlendirici kullanılabilir. + +Aşağıdaki örnekte basit bir yönlendiricinin nasıl uygulanacağı gösterilmektedir. + +```Go +package main + +import ( + "fmt" + "net/http" +) + +type MyMux struct { +} + +func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + sayhelloName(w, r) + return + } + http.NotFound(w, r) + return +} + +func sayhelloName(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello myroute!") +} + +func main() { + mux := &MyMux{} + http.ListenAndServe(":9090", mux) +} +``` + +# Routing - Yönlendirme + +Bir Yönlendirici kullanmak istemiyorsanız, `ListenAndServe` öğesinin ikinci bağımsız değişkenini nil olarak değiştirerek ve en iyi eşleşmeyi bulmak için tüm kayıtlı URL'leri gözden geçiren bir `HandleFunc` işlevi kullanarak URL'leri kaydederek yukarıdaki bölümde yazdıklarımızı yine de elde edebilirsiniz, bu nedenle kayıt sırasına dikkat edilmelidir. + +örnek kod: +```Go +http.HandleFunc("/", views.ShowAllTasksFunc) +http.HandleFunc("/complete/", views.CompleteTaskFunc) +http.HandleFunc("/delete/", views.DeleteTaskFunc) + +// ShowAllTasksFunc, varsayılan ons olan "/" URL'sini işlemek için kullanılır +// TODO http404 hatası ekle +func ShowAllTasksFunc(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + context := db.GetTasks("pending") //silinmemiş görevler istediğinizde true + //db, veritabanı ile etkileşime giren bir pakettir + if message != "" { + context.Message = message + } + homeTemplate.Execute(w, context) + message = "" + } else { + message = "Yönteme izin verilmiyor" + http.Redirect(w, r, "/", http.StatusFound) + } +} +``` +Bu, parametrelendirilmiş yönlendirme gerektirmeyen basit uygulamalar için iyidir, peki ya buna ihtiyacınız olduğunda? Mevcut araç setlerini veya çerçeveleri kullanabilirsiniz, ancak bu kitap golang'da web uygulamaları yazmakla ilgili olduğundan, bu senaryonun nasıl ele alınacağını da öğreteceğiz. + +`HandleFunc` işlevinde eşleşme yapıldığında, URL eşleştirilir, bu nedenle bir yapılacaklar listesi yöneticisi yazdığımızı ve bir görevi silmek istediğimizi varsayalım, böylece bu uygulama için karar verdiğimiz URL `/delete/1` olur, bu nedenle silme URL'sini şu şekilde kaydederiz +`http.HandleFunc("/delete/", views.DeleteTaskFunc)` +`/delete/1` bu URL, "/delete/" URL'si ile diğer URL'lerden daha yakın eşleşir, bu nedenle `r.URL.path` içinde isteğin tüm URL'sini alırız. + +```Go +http.HandleFunc("/delete/", views.DeleteTaskFunc) +// DeleteTaskFunc bir görevi silmek için kullanılır, trash = geri dönüşüm kutusuna taşı, delete = kalıcı silme +func DeleteTaskFunc(w http.ResponseWriter, r *http.Request) { + if r.Method == "DELETE" { + id := r.URL.Path[len("/delete/"):] + if id == "all" { + db.DeleteAll() + http.Redirect(w, r, "/", http.StatusFound) + } else { + id, err := strconv.Atoi(id) + if err != nil { + fmt.Println(err) + } else { + err = db.DeleteTask(id) + if err != nil { + message = "Görev silinirken hata oluştu" + } else { + message = "Görev silindi" + } + http.Redirect(w, r, "/", http.StatusFound) + } + } + } else { + message = "Yönteme izin verilmiyor" + http.Redirect(w, r, "/", http.StatusFound) + } +} +``` + +link: https://github.com/thewhitetulip/Tasks/blob/master/views/views.go#L170-#L195 + +Yukarıdaki yöntemde temel olarak yaptığımız şey, `/delete/` URL'sini işleyen işlevde, `/delete/1` olan compelete URL'sini almak, ardından dizenin bir dilimini almak ve gerçek parametre olan delete kelimesinden sonra başlayan her şeyi çıkarmaktır, bu durumda bu `1`dir. Daha sonra bunu bir tamsayıya dönüştürmek için `strconv` paketini kullanırız ve görevi bu taskID ile sileriz. + +Daha karmaşık senaryolarda da bu yöntemi kullanabiliriz, avantajı herhangi bir üçüncü taraf araç seti kullanmak zorunda olmamamızdır, ancak yine de üçüncü taraf araç setleri kendi başlarına yararlıdır, hangi yöntemi tercih edeceğinize karar vermeniz gerekir. Hiçbir cevap doğru cevap değildir. + + +## Go kod yürütme akışı + +Tüm yürütme akışına bir göz atalım. + +- Çağır `http.HandleFunc` + 1. DefaultServeMux'ın HandleFunc işlevini çağırın + 2. DefaultServeMux Çağrı Tanıtıcısı + 3. DefaultServeMux'un map[string]muxEntry'sine yönlendirici kuralları ekleyin +- Çağır `http.ListenAndServe(":9090", nil)` + 1. Sunucu Oluşturma + 2. Sunucunun ListenAndServe yöntemini çağırın + 3. Portu dinlemek için net.Listen("tcp", addr) çağrısı yapın + 4. Bir döngü başlatın ve döngü gövdesinde istekleri kabul edin + 5. Bir Conn Instantiate edin ve her istek için bir goroutine başlatın: `go c.serve()` + 6. İstek verilerini okuyun: `w, err := c.readRequest()` + 7. İşleyicinin boş olup olmadığını kontrol edin, boşsa DefaultServeMux kullanın + 8. İşleyicinin ServeHTTP'sini çağırın + 9. Bu durumda DefaultServeMux içindeki kodu çalıştırın + 10. URL'ye göre işleyici seçin ve bu işleyici işlevindeki kodu çalıştırın: `mux.handler.ServeHTTP(w, r)` + 11. İşleyici nasıl seçilir: + A. Bu URL için yönlendirici kurallarını kontrol edin + B. Eğer varsa, bu işleyicide ServeHTTP'yi çağırın + C. Aksi takdirde NotFoundHandler'ın ServeHTTP'sini çağırın + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Go web ile nasıl çalışır?](03.3.md) +- Sonraki bölüm: [Özet](03.5.md) diff --git a/tr/03.5.md b/tr/03.5.md new file mode 100644 index 000000000..5000ea3fe --- /dev/null +++ b/tr/03.5.md @@ -0,0 +1,11 @@ +# 3.5 Özet + +Bu bölümde HTTP'yi, DNS çözümleme akışını ve basit bir web sunucusunun nasıl oluşturulacağını tanıttık. Daha sonra `net/http` paketinin kaynak koduna bakarak Go'nun bizim için web sunucularını nasıl uyguladığından bahsettik. + +Umarım artık web geliştirme hakkında çok daha fazla şey biliyorsunuzdur ve Go'da bir web uygulaması oluşturmanın oldukça kolay ve esnek olduğunu görmelisiniz. + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Http paketine girin](03.4.md) +- Sonraki bölüm: [Kullanıcı formu](04.0.md)