diff --git a/tr/02.7.md b/tr/02.7.md new file mode 100644 index 000000000..5b2eac398 --- /dev/null +++ b/tr/02.7.md @@ -0,0 +1,250 @@ +# 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'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 - 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 +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 - 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 +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 - Aralık ve Kapanış + +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 - 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. + +`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 - 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 +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 - Çalışma Zamanı + +`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 + +## Linkler + +- [İç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 new file mode 100644 index 000000000..c31e87eeb --- /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. + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Eşzamanlılık](02.7.md) +- Sonraki bölüm: [Web Temel Kuruluşu](03.0.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) diff --git a/tr/04.0.md b/tr/04.0.md new file mode 100644 index 000000000..1bee0f4e3 --- /dev/null +++ b/tr/04.0.md @@ -0,0 +1,23 @@ +# 4 Kullanıcı formu + +Kullanıcı formu, web uygulamaları geliştirirken çok yaygın olarak kullanılan bir şeydir. İstemciler ve sunucular arasında iletişim kurma olanağı sağlar. Eğer bir web geliştiricisiyseniz formlara çok aşina olmalısınız; eğer bir `C/C++` programcısıysanız şunu sormak isteyebilirsiniz: kullanıcı formu nedir? + +Form, form öğelerini içeren bir alandır. Kullanıcılar metin kutuları, açılır listeler, radyo düğmeleri, onay kutuları vb. gibi form öğelerine bilgi girebilir. Formları tanımlamak için `
+ +Go'nun zaten kullanıcı formlarıyla başa çıkmak için birçok kullanışlı fonksiyonu bulunmaktadır. HTTP isteklerinde form verilerini kolayca alabilir ve kendi web uygulamalarınıza entegre etmek de kolaydır. 4.1 bölümünde, Go'da form verilerini nasıl ele alacağımızı konuşacağız. Ayrıca, istemci tarafından gelen herhangi bir veriye güvenemeyeceğinizden, veriyi kullanmadan önce ilk olarak doğrulamanız gerekir. 4.2 bölümünde form verilerini nasıl doğrulayacağımıza dair bazı örnekleri inceleyeceğiz. + +HTTP'nin durumsuz (stateless) olduğunu söylüyoruz. Belirli formların aynı kullanıcıdan geldiğini nasıl belirleyebiliriz? Ve nasıl yaparız ki bir form sadece bir kez gönderilebilsin? Hem 4.3 hem de 4.4 bölümlerinde çerezlerle ilgili bazı detaylara bakacağız (bir çerez, isteğin sunucuya gönderildiği zaman talep başlığına eklenebilen bilgidir). + +Formlar için başka yaygın bir kullanım durumu da dosyaları yüklemektir. 4.5 bölümünde, Go'da bunu nasıl yapacağınızı ve dosya yükleme öncesinde dosya yükleme boyutunu nasıl kontrol edeceğinizi öğreneceksiniz. + +## Linkler + +- [İçerik](preface.md) +- Önceki bölüm: [Bölüm 3 Özeti](03.5.md) +- Sonraki bölüm: [Form girdilerini işle](04.1.md) diff --git a/tr/04.1.md b/tr/04.1.md new file mode 100644 index 000000000..208e59747 --- /dev/null +++ b/tr/04.1.md @@ -0,0 +1,112 @@ +# 4.1 Form girdilerini işle + +Başlamadan önce, projenizin klasöründe `login.gtpl` olarak kaydedilmiş tipik bir kullanıcı formunun basit bir örneğine bakalım. + +```html + + +