/
bgnet.xml
3539 lines (3404 loc) · 173 KB
/
bgnet.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!-- ********************************************************************
$Id: bgnet.xml,v 1.12 2002/12/20 23:23:58 nilgun Exp $
********************************************************************-->
<book xml:id="bgnet">
<?dbhtml dir="../bgnet"?>
<bookinfo>
<title>Beej'in Ağ Programlama Kılavuzu</title>
<subtitle>Internet Soketlerini Kullanarak</subtitle>
<pubdate>Şubat 2003</pubdate>
<pubdate> </pubdate>
<revhistory>
<para><emphasis role="bold">Özgün belgenin sürüm bilgileri:</emphasis></para>
<revision>
<revnumber>1.0.0</revnumber>
<date>Ağustos 1995</date>
<authorinitials>beej</authorinitials>
<revremark>İlk sürüm.</revremark>
</revision>
<revision>
<revnumber>1.5.5</revnumber>
<date>13 Ocak 1999</date>
<authorinitials>beej</authorinitials>
<revremark>Son HTML sürümü.</revremark>
</revision>
<revision>
<revnumber>2.0.0</revnumber>
<date>6 Mart 2001</date>
<authorinitials>beej</authorinitials>
<revremark>DocBook XML formatına dönüştürüldü, düzeltmeler ve eklemeler.</revremark>
</revision>
<!--
<revision>
<revnumber>Version 2.0.1</revnumber>
<date>March 7, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>Minor corrections.</revremark>
</revision>
<revision>
<revnumber>Version 2.0.2</revnumber>
<date>March 16, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>inet_ntoa() should have been inet_aton() in some places.</revremark>
</revision>
<revision>
<revnumber>Version 2.0.3</revnumber>
<date>April 2, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>inet_aton() return values corrected, selectserver
changed, typos fixed, added recvtimeout().</revremark>
</revision>
<revision>
<revnumber>Version 2.1.0</revnumber>
<date>May 3, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>Fixed buffer overruns in client.c and listener.c,
made server.c robustly reap zombies, added email
policy.</revremark>
</revision>
<revision>
<revnumber>Version 2.2.0</revnumber>
<date>June 24, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>Updates QnA, Windows, talker.c, PF_INET info,
accept() demo, no more bzero()s, Solaris setsockopt().</revremark>
</revision>
<revision>
<revnumber>Version 2.2.1</revnumber>
<date>June 25, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>Minor QnA update, added Amazon affiliate
stuff.</revremark>
</revision>
<revision>
<revnumber>Version 2.3.0</revnumber>
<date>July 25, 2001</date>
<authorinitials>beej</authorinitials>
<revremark>Added QnA entries, polished selectserver.c, added
WSACleanup(), struct in_addr size clarification.</revremark>
</revision>
-->
<revision>
<revnumber>2.3.1</revnumber>
<date>8 Ekim 2001</date>
<authorinitials>beej</authorinitials>
<revremark>
client.c içindeki birkaç sözdizimi hatası giderildi, sıkça sorulan
sorular bölümüne yeni malzeme eklendi.
</revremark>
</revision>
</revhistory>
<revhistory>
<para><emphasis role="bold">Bu çevirinin sürüm bilgileri:</emphasis></para>
<revision>
<revnumber>0.9</revnumber>
<date>15 Aralık 2002</date>
<authorinitials>FZ</authorinitials>
<revremark>
Çeviri ve ilk kontroller yapıldı.
</revremark>
</revision>
</revhistory>
<authorgroup>
<author>
<firstname>Brian</firstname><surname>Hall</surname>
<othername>"Beej"</othername>
</author>
<author role="translator">
<firstname>Emre</firstname>
<surname>Sevinç</surname>
<othername>"FZ"</othername>
</author>
</authorgroup>
<abstract>
<para>
Bu belge bir öğretici olarak tasarlanmıştır ve tam teşekküllü bir başvuru
kılavuzu değildir. Soket programlama konusuna ciddi ciddi merak salan
bireyler tarafından adım adım okunursa işe yarayacaktır.
</para>
</abstract>
<legalnotice><title>Yasal Açıklamalar</title>
<para>
BU BELGE "ÜCRETSİZ" OLARAK RUHSATLANDIĞI İÇİN, İÇERDİĞİ BİLGİLER İÇİN İLGİLİ KANUNLARIN
İZİN VERDİĞİ ÖLÇÜDE HERHANGİ BİR GARANTİ VERİLMEMEKTEDİR. AKSİ YAZILI OLARAK BELİRTİLMEDİĞİ
MÜDDETÇE TELİF HAKKI SAHİPLERİ VE/VEYA BAŞKA ŞAHISLAR BELGEYİ "OLDUĞU GİBİ", AŞİKAR VEYA
ZIMNEN, SATILABİLİRLİĞİ VEYA HERHANGİ BİR AMACA UYGUNLUĞU DA DAHİL OLMAK ÜZERE HİÇBİR
GARANTİ VERMEKSİZİN DAĞITMAKTADIRLAR. BİLGİNİN KALİTESİ İLE İLGİLİ TÜM SORUNLAR SİZE AİTTİR.
HERHANGİ BİR HATALI BİLGİDEN DOLAYI DOĞABİLECEK OLAN BÜTÜN SERVİS, TAMİR VEYA DÜZELTME
MASRAFLARI SİZE AİTTİR.
</para><para>
İLGİLİ KANUNUN İCBAR ETTİĞİ DURUMLAR VEYA YAZILI ANLAŞMA HARİCİNDE HERHANGİ BİR ŞEKİLDE
TELİF HAKKI SAHİBİ VEYA YUKARIDA İZİN VERİLDİĞİ ŞEKİLDE BELGEYİ DEĞİŞTİREN VEYA YENİDEN
DAĞITAN HERHANGİ BİR KİŞİ, BİLGİNİN KULLANIMI VEYA KULLANILAMAMASI (VEYA VERİ KAYBI OLUŞMASI,
VERİNİN YANLIŞ HALE GELMESİ, SİZİN VEYA ÜÇÜNCÜ ŞAHISLARIN ZARARA UĞRAMASI VEYA BİLGİLERİN
BAŞKA BİLGİLERLE UYUMSUZ OLMASI) YÜZÜNDEN OLUŞAN GENEL, ÖZEL, DOĞRUDAN YA DA DOLAYLI HERHANGİ
BİR ZARARDAN, BÖYLE BİR TAZMİNAT TALEBİ TELİF HAKKI SAHİBİ VEYA İLGİLİ KİŞİYE BİLDİRİLMİŞ
OLSA DAHİ, SORUMLU DEĞİLDİR.
</para><para>
Tüm telif hakları aksi özellikle belirtilmediği sürece sahibine aittir. Belge içinde geçen herhangi bir terim, bir ticari isim ya da kuruma itibar kazandırma olarak algılanmamalıdır. Bir ürün ya da markanın kullanılmış olması ona onay verildiği anlamında görülmemelidir.
</para>
</legalnotice>
</bookinfo>
<!-- ======================================================= -->
<!-- Introduction -->
<!-- ======================================================= -->
<chapter xml:id="bgnet_intro">
<title>Giriş</title>
<para>
Hey! Soket programlama ile başınız belada mı? Bütün bu ayrıntılar
<command>man</command> sayfalarından çekip çıkarmak için çok mu zor?
En temel Internet programlama tekniklerini öğrenmek istiyorsunuz ama
tonlarca <literal>struct</literal> ve bunları <function>bind()</function>
işlevini çağırmadan <function>connect()</function>, vs., vs.ye parametre
olarak nasıl geçeceğiniz konusunda binlerce ayrıntıyı öğrenmeye vaktiniz
yok mu?
</para><para>
Hmm, bakın burada ne var? Bütün bu sinir bozucu ayrıntılarla ben zamanında
boğuştum ve herkesle deneyimlerimi paylaşmak için can atıyorum! Doğru yere
geldiniz. Bu belge ortalama bir C programcısına tüm bu ağ meseleleri ile
ilgili temel kavramları ve pratik uygulamaları verecek düzeydedir.
</para>
<!-- ======================================================= -->
<!-- Audience -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-whom">
<title>Kimin İçin?</title>
<para>
Bu belge bir öğretici olarak tasarlanmıştır ve tam teşekküllü bir başvuru
kılavuzu değildir. Soket programlama konusuna ciddi ciddi merak salan
bireyler tarafından adım adım okunursa işe yarayacaktır. Bu belge kesinlikle
<emphasis>eksiksiz</emphasis> bir soket programlama kılavuzu değildir.
</para><para>
Eğer şu man sayfalarının sizin için biraz daha anlamlı hale gelmesini
sağlarsa bu belge amacına ulaşmış demektir...<literal>:-)</literal>
</para>
</sect1>
<!-- ======================================================= -->
<!-- Platform and Compiler -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-platform">
<title>Platform ve Derleyiciler</title>
<para>
Bu belgedeki kodlar Linux çalıştıran bir PC üzerinde Gnu'nun
<command>gcc</command> derleyicisi ile derlenmiştir. Ancak
<command>gcc</command> derleyicisinin çalışabildiği her platformda
derlenebilir. Tabii eğer Windows kullanıyorsanız yukarıda dediklerim
geçerli değildir. Bunun için aşağıdaki <xref linkend="bgnet_intro-windows"/>
bölümüne bakın.
</para>
</sect1>
<!-- ======================================================= -->
<!-- Homepage -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-homepage">
<title>Resmi Anasayfa</title>
<para>
Bu belgenin resmi adresi California Devlet Üniversitesi, Chico,
<link xl:href="http://www.ecst.csuchico.edu/~beej/guide/net/"/>'dir.
</para>
</sect1>
<!-- ======================================================= -->
<!-- Solaris and SunOS -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-solaris">
<title>Solaris/SunOS Programcılarının Dikkat Etmesi Gerekenler</title>
<para>
Solaris ya da SunOS için derlerken gerekli işlev kitaplıklarını
programa bağlayabilmek için bazı ek parametreler vermeniz gerekebilir.
Bunun için <literal>-lnsl -lsocket -lresolv</literal> parametrelerini
derleme komutunuzun sonuna ekleyebilirsiniz, örnek:
</para><para>
<screen>
<prompt>$</prompt> <userinput>cc -o server server.c -lnsl -lsocket -lresolv</userinput>
</screen>
</para><para>
eğer hala hata alıyorsanız şunu da ekleyin: <literal>-lxnet</literal>.
Ne işe yaradığını bilmiyorum ama görünen o ki bazı durumlarda
gerekebiliyor.
</para><para>
Problem yaşayabileceğiniz bir başka yer de <function>setsockopt()</function>
işlevinin çağrıldığı yerdir. Bu işlevin Solaris/SunOS'taki prototipi benim
Linux makinamdakinden farklıdır bu yüzden de:
</para><para>
<screen>int yes=1;</screen>
</para><para>
yerine bunu girin:
</para><para>
<screen>char yes='1';</screen>
</para><para>
Elimde bir Sun makinası yok, yukarıdakileri denemedim bu bilgiler bana
deneme yapıp e-posta gönderen insanların söylediklerinden ibarettir.
</para>
</sect1>
<!-- ======================================================= -->
<!-- Windows -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-windows">
<title>Windows Programcılarının Dikkat Etmesi Gerekenler</title>
<para>
Windows'dan pek hoşlandığım söylenemez bu yüzden de bu belgeyi okuyan
tüm Windows programcılarını GNU/Linux, BSD ya da UNIX denemeye davet
ediyorum. Bu laflardan sonra, evet, örnek kodları Windows üzerinde
kullanma imkanınız var.
</para><para>
Öncelikle burada bahsettiğim birçok sistem başlık dosyasını unutun.
Tek yapmanız gereken aşağıdakileri programınıza katmak:
</para><para>
<screen>
#include <winsock.h>
</screen>
</para><para>
Bir dakika! Aynı zamanda <function>WSAStartup()</function> işlevini de
soket kitaplıkları ile herhangi bir iş yapmadan önce çağırmanız gerekiyor.
Bunu yapmak için gerekli kod şöyle bir şey:
</para><para>
<screen>
#include <winsock.h>
{
WSADATA wsaData; // if this doesn't work
//WSAData wsaData; // then try this instead
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
</screen>
</para><para>
Tabii derleyicinize Winsock'u da bağlamasını söylemelisiniz. Bunun için
gerekli dosyanın ismi genellikle şudur: <filename>wsock32.lib</filename>
veya <filename>winsock32.lib</filename> veya benzer bir şey. VC++
ortamında iseniz, bunun için <literal>Project</literal> menüsünden,
<literal>Settings...</literal> kısmına gidin ve <literal>Link</literal>
sekmesine gelip <literal>Object/library modules</literal> kutusunu bulun.
<filename>wsock32.lib</filename> dosyasını bu listeye ekleyin.
</para><para>
En azından ben böyle duydum.
</para><para>
Ve son olarak da <function>WSACleanup()</function> işlevini çağırmanız
gerekir soket kitaplığı ile işiniz bittiğinde. Ayrıntılı bilgi için
derleyicinizin yardım belgelerine bakın.
</para><para>
Bunu yaptığınızda bu belgedeki örneklerin hemen hepsi genel olarak
çalışabilir durumda olmalı belki birkaç küçük değişiklik yapmanız
gerekebilir ama hepsi bu. Dikkat etmeniz gerekenler: Soketi kapatmak
için <function>close()</function> işlevini kullanamazsınız -- bunun
için <function>closesocket()</function> işlevini kullanmalısınız.
Ayrıca <function>select()</function> işlevi sadece soket tanımlayıcılar
içindir, dosya tanımlayıcılar (standart girdi için 0 kullanılması gibi)
için değildir.
</para><para>
Aynı zamanda, <literal>CSocket</literal> isimli bir soket sınıfı da mevcuttur.
Ayrıntılı bilgi için derleyicinizin belgelerini karıştırın.
</para><para>
Winsock hakkında ayrıntılı bilgi için şu adrese bakabilirsiniz: <ulink
url="http://tangentsoft.net/wskfaq/">Winsock FAQ</link>
</para><para>
Son olarak da bildiğim kadarı ile Windows ortamında <function>fork()</function>
isimli işlev yok ve maalesef örneklerde bu işlevi kullanmak durumdayım.
Belki de bir POSIX kitaplığına programınızı bağlamanız gerekebilir veya
<function>CreateProcess()</function> işlevini kullanabilirsiniz.
<function>fork()</function> işlevi herhangi bir argüman almaz ama
<function>CreateProcess()</function> işlevi 48 milyar argüman alır.
Eğer bu gözünüzü biraz korkuttu ise <function>CreateThread()</function>
işlevi biraz daha kolay bir alternatif olabilir ancak "multithreading"
tartışması bu belgenin sınırlarının ötesindedir. Windows konusunu böylece
burada kapatıyoruz!
</para>
</sect1>
<!-- ======================================================= -->
<!-- Email policy -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-emailpolicy">
<title>E-posta Politikası</title>
<para>
Genellikle e-posta ile gönderilen sorulara cevap vermeye çalışırım, bu
yüzden yazmaktan çekinmeyin, ancak bu size cevap vereceğim anlamına
gelmez. Epey meşgulüm ve bazen sorunuzun cevabını tam olarak bilmiyor
olabilirim. Durum bu olduğunda mesajınızı silerim lütfen bunu şahsınıza
yönelik bir harekete olarak algılamayın. İnanın bana sorduğunuz her
soruyu en ince ayrıntısına kadar cevaplayacak kadar vaktim olmayabilir.
</para><para>
Basit bir kural: Sorunuz ne kadar karmaşık ise cevap verme ihtimalim o
kadar düşüktür. Eğer soru kapsamını daraltır ve derdinizle ilgili
ayrıntılı bilgileri de yollarsanız (platform, derleyici, hata mesajları,
vs.), cevap alma ihtimaliniz artar. Daha ayrıntılı bilgi için şu adresi
tavsiye ederim: <link xl:href="http://www.tuxedo.org/~esr/faqs/smart-questions.html">How To Ask Questions The Smart
Way</link>.
</para><para>
Eğer cevap alamıyorsanız biraz daha kurcalayın programınızı ve cevabı
bulmaya çalışın. Hala çözemedi iseniz o zaman bana gene yazın ve belki
o zaman elimizdeki ayrıntılı bilgilerle probleme bir çözüm bulmamız daha
kolay olabilir.
</para><para>
Şimdi sizi bana nasıl yazmanız ve yazmamanız konusunda <emphasis>yeterince</emphasis>
eğittiğime göre bu kılavuzla ilgili süreç içinde bana ulaştırılan
övgülerin beni ne kadar motive ettiğini de itiraf etmek isterim.
<literal>:-)</literal> Teşekkürler!
</para>
</sect1>
<!-- ======================================================= -->
<!-- Copyright -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_intro-copyright">
<title>Telif Hakkı ve Dağıtım</title>
<para>
Beej's Guide to Network Programming - Copyright © 1995-2001
Brian "Beej" Hall.
</para><para>
Bu belge bütünlüğü korunduğu, içeriği değiştirilmediği ve bu kopyalama
bilgisi de yayınlandığı sürece herhangi bir ortamda serbestçe yeninden
yayınlanabilir.
</para><para>
Öğretim görevlileri bu belgeyi öğrencilerine tavsiye edebilirler.
</para><para>
Bu belge herhangi bir dile tercüme edilebilir yeter ki söz konusu tercüme
aslına sadık kalsın ve belgenin bütünlüğünü bozmasın. Tercüme, tercümeyi
yapanın ismini ve temas bilgilerini içerebilir.
</para><para>
Belgedeki C kaynak kodları kamuya açıktır.
</para>
</sect1>
</chapter> <!-- /Introduction -->
<!-- ======================================================= -->
<!-- What is a socket? -->
<!-- ======================================================= -->
<chapter xml:id="bgnet_theory">
<title>Soket Nedir?</title>
<para>
Sürekli "socket"lerden bahsedildiğini duymuşsunuzdur ve belki de bunların
tam olarak ne anlama geldiğini merak ediyor olabilirsiniz. Soket kısaca
şudur: Diğer programlarla standart Unix dosya tanımlayıcılarını kullanarak
haberleşmenizi sağlayan bir yapı.</para><para>Ne?
</para><para>
Pekala -- bazı Unix hacker'larının, "Vay canına! Unix'teki hemen hemen
<emphasis>herşey</emphasis> bir dosya!" dediğini duymuş olabilirsiniz.
Böyle konuşan birinin kast ettiği aslında Unix programlarının, herhangi
bir G/Ç işlemi yaptıklarında bunları bir dosya tanımlayıcıyı okuyarak
ya da ona yazarak yaptıklarıdır. Bir dosya tanımlayıcı basitçe söylemek
gerekirse açık bir dosya ile ilişkilendirilmiş bir tamsayıdır. Ancak
(işin püf noktası da burası), söz konusu bu açık dosya diskteki normal
bir dosya olabileceği gibi aynı zamanda bir ağ bağlantısı, bir FIFO,
bir uçbirim ya da başka herhangi bir veri kaynağı olabilir. Gerçekten
de Unix ortamında her şey bir dosyadır! Öyleyse Internet üzerinden başka
bir programla iletişim kurmak isterseniz bunu bir dosya tanımlayıcı
üzerinden yapacaksınız, inanın buna.
</para><para>
"Peki bay çok bilmiş, ağ iletişimi için kullanacağım bu dosya tanımlayıcı
nerede?" gibi bir soru aklınıza gelmemiş olabilir ancak ben gene de cevabını
vereyim ki içiniz rahat etsin: Bu dosya tanımlayıcıya ulaşmak için
<function>socket()</function> sistem işlevini çağırmanız gerekir. Bu işlev
size soket tanımlayıcıyı döndürür ve siz de bunu ve tabii
<function>send()</function> ile <function>recv()</function>
(<command><link xl:href="http://linux.com.hk/man/showman.cgi?manpath=/man/man2/send.2.inc">man send</link></command>,
<command><link xl:href="http://linux.com.hk/man/showman.cgi?manpath=/man/man2/recv.2.inc">man recv</link></command>)
isimli soket işlevlerini kullanarak istediğiniz şekilde iletişimizini
kurarsınız.
</para><para>
"Hey, bir dakika!" diyebilirsiniz şimdi. "Eğer bir dosya tanımlayıcı söz
konusu ise o halde tanrı aşkına neden her zaman kullandığım normal
<function>read()</function> ve <function>write()</function> işlevlerini
kullanarak soketler üzerinden iletişim kuramayayım ki?" Kısa cevap:
"Evet tabii ki!" Uzun cevap ise "Evet, mümkün ama
<function>send()</function> ve <function>recv()</function> işlevleri
veri iletişiminde çok daha fazla kontrol sağlar ve işinizi kolaylaştırır."
</para><para>
Sırada ne var? Buna ne dersiniz: çeşit çeşit soket vardır. Mesela DARPA
Internet adresleri (Internet Soketleri), yerel bir düğümdeki (node) yol
isimleri (Unix Soketleri), CCITT X.25 adresleri (X.25 Soketleri ki inanın
bunları bilmeseniz de olur) ve kullandığınız Unix sürümüne bağlı daha pek
çok soket tipi. Bu belge sadece birinci tür soketleri ele almaktadır,
yani: Internet Soketleri.
</para>
<!-- ======================================================= -->
<!-- Two Types of Internet Sockets -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_theory-twotypes">
<title>Internet Soketlerinin İki türü</title>
<para>
Bu da ne? İki tür Internet soketi mi var? Evet. Şey, aslında hayır.
Yalan söyledim. Daha çok var ama sizi korkutmak istemedim. Size sadece iki
tür soketten bahsedeceğim. Sadece "Ham Soketler"in (Raw Sockets) çok güçlü
olduğunu belirttiğim bu cümle dışında yani, bir ara bunlara da göz atarsanız
iyi olur.
</para><para>
Pekala, gelelim şu iki tür sokete. Bir tanesi "Veri Akış Soketleri";
diğeri ise "Veri Paketi Soketleri" ve artık biz bunlara sırası ile
"<constant>SOCK_STREAM</constant>" ve "<constant>SOCK_DGRAM</constant>"
diyeceğiz. Veri paketi soketleri bazen "bağlantısız soketler" olarak da
isimlendirilir. (Her ne kadar eğer isterseniz bunlara <function>connect()</function>
işlevi ile bağlanabilecek olsanız da. Detaylı bilgi için aşağıdaki
<link linkend="bgnet_syscalls-connect">connect()</link> maddesine bakın.)
</para><para>
Veri akış soketleri güvenilir iki yönlü iletişim kanallarıdır. Eğer bu
tür bir sokete sıra ile "1, 2" bilgilerini gönderirseniz, bunlar kanalın
diğer ucundan "1, 2" şeklinde çıkar. Aynı zamanda bu iletişim olası
hatalara karşı da korumalıdır. Karşılaşacağınız her türlü hatanın kaynağı
sizin karman çorman aklınız olacaktır ve burada bunları tartışmaya niyetim
yok.
</para><para>
Stream soketleri gerçek hayatta ne işimize yarar? Hmm, sanırım
<command>telnet</command> diye bir program duymuşsunuzdur, değil mi? İşte
bu program veri akış soketlerini kullanır. Yazdığınız tüm karakterler
sizin yazdığınız sırada iletilmelidir öyle değil mi? Aynı zamanda web
tarayıcılar da HTTP protokolü ile iletişim kurarken veri akış soketleri
aracılığı ile sayfa bilgilerini çekerler. Gerçekten de eğer bir web
sitesine <command>telnet</command> ile 80 numaralı port üzerinden
bağlanır ve "<literal>GET /</literal>" komutunu yollarsanız web sitesi
size HTML içeriğini yollayacaktır.
</para><para>
Veri akış soketleri bu kadar sorunsuz bir veri iletişimini nasıl
gerçekleştirir? Bunun için "Aktarım Denetim Protokolü" (Transmission
Control Protocol) isimli kurallar dizisinden yararlanırlar ki siz
bunu "TCP" olarak da duymuş olabilirsiniz (bkz. <ulink
url="http://www.rfc-editor.org/rfc/rfc793.txt">RFC-793</link> bu belge TCP ile ilgili çok
ayrıntılı bilgi içerir.) TCP yollanan verinin sıralı ve düzgün gitmesini
sağlar. "TCP"yi daha önce "TCP/IP" kısaltmasının bir parçası olarak
duymuş olabilirsiniz ki "IP" de "Internet Protocol" sözünün kısaltmasıdır
(bkz. <link xl:href="http://www.rfc-editor.org/rfc/rfc791.txt">RFC-791</link>.) IP kurallar
dizisi temelde Internet yönlendirme ile ilgilidir, veri bütünlüğünün
korunması ile ilgili pek kural içermez.
</para><para>
Harika. Peki veri paketi soketleri? Neden bunlara bağlantısız deniyor?
Mesele nedir kısaca? Neden bunların "güvenilmez" olduğu söyleniyor?
Bakın, bilmeniz gereken bazı gerçekler var: eğer bir veri paketi
yollarsanız bu hedefine ulaşabilir de ulaşmayabilir de. Gönderdiğiniz
sırada ulaşması garanti edilemez. Ancak eğer hedefe ulaşırsa paketin
içerdiği bilgi hatasız olacaktır.
</para><para>
Veri paketi soketleri de yönlendirme için IP protokolünü kullanırlar ancak
TCP'den faydalanmazlar onun yerine "Kullanıcı Veri Paketi Protokokü" (User
Datagram Protocol) veya "UDP" isimli protokolü kullanırlar (bkz. <ulink
url="http://www.rfc-editor.org/rfc/rfc768.txt">RFC-768</link>.)
</para><para>
Neden bağlantısızdırlar? Aslında böyledirler çünkü veri akış soketlerinde
olduğu gibi bağlantıyı sürekli açık tutmanız gerekmemektedir. Sadece bir
paketi oluşturur, tepesine gideceği adresi söyleyen bir IP başlığı yapıştırır
ve onu yollarsınız. Herhangi bir bağlantı açmaya gerek yoktur. Bu tip
soketler genellikle paket paket iletilen veri için kullanılır. Bu tip
soketleri kullanan örnek uygulamalardan bazıları: <command>tftp</command>,
<command>bootp</command>, vs.
</para><para>
"Yeter artık!" diye bağırdığınızı duyar gibiyim. "Eğer veri paketlerinin
yolda kaybolma ihtimali varsa nasıl olur da yukarıda saydığın programlar
çalışır?!" Bak dünyalı dostum bu saydığım programların hepsi UDP protokolü
üzerine kendi protokollerini yerleştirirler. Mesela, <command>tftp</command>
protokolüne göre gönderilen her paket için karşı tarafın "aldım!"
(bir "ACK" paketi) paketini geri yollaması gerekir. Eğer orjinal paketin
göndericisi mesela 5 saniye içinde cevap alamazsa o zaman paketi yeniden
yollar, taa ki ACK cevabını alana kadar. İşte bu "aldım" prosedürü
<constant>SOCK_DGRAM</constant> uygulamalarında çok önemlidir.
</para>
</sect1>
<!-- ======================================================= -->
<!-- Two Types of Internet Sockets -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_theory-lowlevel">
<title>Düşük Seviye Duyarsızlığı ve Ağ Teorisi</title>
<para>
Protokol katmanlarından bahsettiğime göre artık ağların nasıl çalıştığına
dair gerçekleri öğrenmenin ve <constant>SOCK_DGRAM</constant> paketlerinin
nasıl oluşturulduğuna dair örnekler vermenin zamanı geldi. Pratik olarak
bu bölümü atlayabilirsiniz, ancak burayı okursanız iyi bir temel bilgiye
sahip olursunuz.
</para><para>
<figure float="0" xml:id="bgnet_figure1">
<title>Veri Paketlemesi (data encapsulation)</title>
<inlinemediaobject>
<imageobject>
<imagedata align="middle" fileref="dataencap.gif"/>
</imageobject>
<caption>Protokollerin Veriyi Paketlemesi</caption>
</inlinemediaobject>
</figure>
</para><para>
Hey çocuklar, Veri Paketleme konusunu öğrenme zamanı! Bu çok çok önemli.
O kadar önemli o kadar önemli ki burada yani Chico Eyaletinde ağ
teknolojilerine dair bir kurs alırsanız bu konu ile mutlaka
karşılaşırsınız <literal>;-)</literal>. Temelde konu şu: bir paket doğar,
sonra bu paket önce muhatap olduğu ilk protokol tarafından (mesela TFTP
protokolü) ile bir başlık (ve ender olarak da olsa bir dipnot ile)
kullanılarak paketlenir (kapsüle konur), ardından tüm bu yığın
(TFTP başlığı da dahil) bir sonraki protokolün (örn. UDP) kurallarına
göre paketlenir, sonra IP ve en sonundaki en alt katman olan donanım
katmanındaki fiziksel protokol ile (örn. Ethernet) paketlenir.
</para><para>
Başka bir bilgisayar bu paketlenmiş paketi aldığında önce donanım Ethernet
başlığını çıkarır, ardından işletim sistemi çekirdeği IP ve UDP başlıklarını
alır ve ardından da TFTP programı TFTP başlığını alır ve içindeki veriye
erişir.
</para><para>
Artık şu kötü üne sahip Katmanlı Ağ Modeli (Layered Network Model)
kavramından bahsedebilirim. Bu ağ modeli diğer modellere pek çok
üstünlüğü bulunan bir ağ işlevselliğinden bahseder. Mesela yazdığınız
soket programının tek bir harfini bile değiştirmenize gerek kalmadan
bu programı farklı fiziksel donanımlar üzerinde çalıştırabilirsiniz
(seri, thin Ethernet, AUI, her ne ise) çünkü düşük seviyedeki programlar
sizin yerinize ayrıntıları hallederler. Ağ donanımının fiziksel detayları
ve topolojisi soket programcısını ilgilendirmez.
</para><para>
Daha fazla laf kalabalığı yapmadan bu müthiş modelin katmanlarını liste
olarak vereyim, ağ ile ilgili sınava girerseniz işe yarayabilir:
</para><para>
<itemizedlist>
<listitem>Uygulama</listitem>
<listitem>Sunum</listitem>
<listitem>Oturum</listitem>
<listitem>Taşıma</listitem>
<listitem>Ağ</listitem>
<listitem>Veri Bağlantısı</listitem>
<listitem>Fiziksel</listitem>
</itemizedlist>
</para><para>
Fiziksel katman donanımla ilgilidir (seri, Ethernet, vs.). Uygulama
katmanı fiziksel katmandan alabildiğine uzaktır -- kullanıcılar ağ ile bu
katmanda temas kurar.
</para><para>
Açıkçası bu model o kadar geneldir ki eğer isterseniz bu modeli arabanıza
bile uygulayabilirsiniz. Unix ile daha uyumlu bir katmanlı model şöyle
yazılabilir:
</para><para>
<itemizedlist>
<listitem><para>
Uygulama Katmanı (<emphasis>telnet, ftp, etc.</emphasis>)
</para></listitem><listitem><para>
Konaktan Konağa Taşıma Katmanı (<emphasis>TCP, UDP</emphasis>)
</para></listitem><listitem><para>
Internet Katmanı (<emphasis>IP ve yönlendirme</emphasis>)
</para></listitem><listitem><para>
Ağa Erişim Katmanı (<emphasis>Ethernet, ATM ya da her ne ise</emphasis>)
</para></listitem>
</itemizedlist>
</para><para>
Bu aşamada söz konusu katmanların veri paketlenmesinin hangi aşamalarına
karşılık geldiğini görebiliyor olmalısınız.
</para><para>
Tek bir paketi oluşturmak için ne kadar çok iş yapılması gerektiğini
gördünüz mü! Aman allahım! Üstelik paket başlık bilgilerini de
<command>cat</command> komutunu kullanarak elle girmeniz gerekiyor!
Şaka şaka! Tek yapmanız gereken eğer veri akış soketi kullanıyorsanız
<function>send()</function> ile veriyi göndermek. Eğer veri paketi soketi
kullanıyorsanız bu sefer de yapılması gereken paketi uygun şekilde
paketleyip <function>sendto()</function> işlevini kullanarak bunu yollamak.
Çekirdek sizin için Taşıma katmanını ve Internet katmanını kurar,
donanımınız da Ağa Erişim Katmanını halleder. Ah, modern teknoloji.
</para><para>
Ağ teorisi ile ilgili kısa dersimiz burada sona eriyor. Ah evet tabii ki
yönlendirmeyle ilgili söylemem gereken şeyler vardı: unutun! Bundan
bahsetmeyeceğim. Yönlendirici (router) IP başlığını çeker yönlendirme
tablosuna bakar, seçim yapar, vs. vs. vs. Eğer gerçekten meraklı iseniz
<link xl:href="http://www.rfc-editor.org/rfc/rfc791.txt">IP RFC</link> belgesine bakın. Bunu
öğrenmezsiniz ölmezsiniz.
</para>
</sect1>
</chapter> <!-- /What is a socket? -->
<!-- ======================================================= -->
<!-- structs -->
<!-- ======================================================= -->
<chapter xml:id="bgnet_structs">
<title><literal>struct</literal>'lar ve Veri İle Uğraşmak</title>
<para>
Hele şükür bu aşamaya gelebildik. Artık biraz programlamadan bahsedebiliriz.
Bu bölümde soket arayüzleri tarafından kullanılan pek çok veri türünü ele
alacağım çünkü bunlar gerçekten önemli.
</para><para>
Kolay olanlarla başlayalım: bir soket tanımlayıcı. Bir soket tanımlayıcı
aşağıdaki türdendir:
</para><para>
<screen>int</screen>
</para><para>Evet, gayet klasik, alışık olduğumuz basit bir <literal>int</literal>.
</para><para>
İşte bu aşamadan itibaren işler biraz garipleşmeye başlıyor bu yüzden de
dikkatlice okuyun ve bana güvenin. İlk bilmeniz gereken: iki tür byte
sıralaması vardır: en önemli baytın (ki buna bazen öktet de denir)
önce geldiği sıralama veya en önemli baytın sonra geldiği sıralama.
Bu sıralamalardan birincisine "Ağ Bayt Sıralaması" (Network Byte Order)<footnote>
<para>Meraklısına not, Ağ Bayt Sıralaması aynı zamanda "Kıymetlisi Başta Bayt
Sırası" (Big-Endian) ve Konak Bayt Sıralaması da "Kıymetlisi Sonda Bayt
Sırası"(Little-Endian) olarak bilinir.</para></footnote>
denir. Bazı makinalar içsel olarak veriyi kendi belleklerinde bu şekilde
depolar, bazıları ise bu sırayı dikkate almaz. Bir şeyin Ağ Bayt Sıralaması'na
göre sıralanması gerektiğini söylediğimde <function>htons()</function> gibi
bir işlev çağırmanız gerekecek ("Konak Bayt Sıralaması"ndan [Host Byte Order]
"Ağ Bayt Sıralaması"na dönüştürebilmek için). Eğer "Ağ Bayt Sıralaması"ndan
bahsetmiyorsam o zaman ilgili veriyi olduğu gibi yani
"Konak Bayt Sıralaması" düzeninde bırakmanız gerekir.
</para><para>
<trademark>My First Struct</trademark> -- <literal>struct sockaddr</literal>.
Bu veri yapısı pek çok türde soket için soket adres bilgisini barındırır:
</para><para>
<screen>
struct sockaddr {
unsigned short sa_family; // adres ailesi, AF_xxx
char sa_data[14]; // protokol adresinin 14 byte'ı
};
</screen>
</para><para>
<parameter>sa_family</parameter> pek çok değerden birini alabilir ama
bizim örneğimizde <constant>AF_INET</constant> olacak.
<parameter>sa_data</parameter> ise soketle ilgili hedef adres ve port
numarası bilgilerini barındırır. Bunun garip olduğunu kabul ediyorum, yani
herhalde bu bilgiyi kendi ellerinizle paketleyerek <parameter>sa_data</parameter>
değişkenine yerleştirmek istemezsiniz değil mi?
</para><para>
<literal>struct sockaddr</literal> ile başa çıkabilmek için programcılar buna
paralel bir yapı tasarlamışlar: <literal>struct sockaddr_in</literal> ("in"
"Internet" anlamına geliyor.)
</para><para>
<screen>
struct sockaddr_in {
short int sin_family; // Adres ailesi
unsigned short int sin_port; // Port numarası
struct in_addr sin_addr; // Internet adresi
unsigned char sin_zero[8]; // struct sockaddr ile aynı boyda
};
</screen>
</para><para>
Bu yapı soket adresi elemanlarına erişmeyi kolaylaştırır. Dikkat etmeniz
gereken bir nokta: <parameter>sin_zero</parameter>,<footnote><para>Burada
bulunmasının sebebi içinde bulunduğu veri yapısının boyunu <literal>struct
sockaddr</literal> yapısının boyuna tamamlamaktır.</para></footnote>
<function>memset()</function> işlevi kullanılarak tamamen sıfır ile
doldurulmalıdır. Buna ek ve daha da önemli olarak bir <literal>struct
sockaddr_in</literal> göstergesi <literal>struct sockaddr</literal> göstergesine
dönüştürülebilir ve tersi de doğrudur. Yani her ne kadar
<function>socket()</function> işlevi <literal>struct sockaddr*</literal> şeklinde
bir veri beklese de siz gene de <literal>struct sockaddr_in</literal> kullanıp
son anda gerekli dönüştürmeyi yapabilirsiniz! Ayrıca <parameter>sin_family</parameter>
değişkeninin de <literal>struct sockaddr</literal> yapısındaki
<parameter>sa_family</parameter> değişkenine karşılık geldiğini ve
"<constant>AF_INET</constant>" olarak ayarlanması gerektiğini unutmayın.
Son olarak <parameter>sin_port</parameter> ve <parameter>sin_addr</parameter>
değikenlerinin de Ağ Byte Sırasında bulunmaları gerektiğini unutmayın!
</para><para>
"Fakat," diye itiraz edebilirsiniz, "nasıl olur da tüm yapı yani
<literal>struct in_addr sin_addr</literal> Ağ Bayt Sıralamasına göre
dizilebilir ki?" Bu soru tüm zamanların en kötü
<literal>union</literal>'larından biri olan <literal>struct in_addr</literal>
yapısının dikkatli olarak incelenmesini gerektirir:
</para><para>
<screen>
// Internet adresi (tarihi sebeplerden ötürü korunmakta)
struct in_addr {
unsigned long s_addr; // 32-bit yani 4 bytes
};
</screen>
</para><para>
Evet, bir zamanlar kötü bir <literal>union</literal> idi. Neyse ki
geçmişte kaldı. Eğer <parameter>ina</parameter> değişkenini
<literal>struct sockaddr_in</literal> türünden tanımladı iseniz
<parameter>ina.sin_addr.s_addr</parameter> 4 byte'lık Internet
adresini gösterir (Ağ Bayt Sıralamasında). Aklınızda bulunsun eğer
sizin sisteminiz kahrolası <literal>struct in_addr</literal>
<literal>union</literal>'ını kullanıyor olsa bile yine de 4 byte'lık
Internet adresine tamamen benim yaptığım gibi ulaşabilirsiniz
(bunu <literal>#define</literal>'lara borçluyuz).
</para>
<!-- ======================================================= -->
<!-- Convert The Natives -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_structs-convert">
<title>Veri Türlerini Dönüştür!</title>
<para>
Deminden beri şu Ağ ve Konak Bayt Sıralamaları ile yeterince kafa
şişirdim şimdi biraz eylem zamanı!
</para><para>
Pekala. Dönüştürebileceğiniz iki tür vardır: <literal>short</literal>
(iki byte) ve <literal>long</literal> (dört byte). Bu işlevler
<literal>unsigned</literal> ve varyasyonları üzerinde çalışır.
Örneğin bir <literal>short</literal> değişkenin bayt düzenini
Konak Bayt Sıralamasından Ağ Bayt Sıralamasına çevirmek istiyorsunuz.
"h" ile başlayalım ("host"), sonra "to" ve ardından "n" ("network")
son olarak da bir "s" ("short"): h-to-n-s veya htons()
("Host to Network Short" olarak okursanız hatırlamanız kolay olur).
</para><para>O kadar da zor sayılmaz değil mi...
</para><para>
Aptallarca olanlarını bir kenara bırakırsak "n", "h", "s" ve "l" ile
her türlü birleşimi oluşturabilirsiniz. Örneğin tabii ki
<function>stolh()</function> ("Short to Long Host") gibi bir işlev
yoktur. Fakat şu işlevler vardır:
</para><para>
<itemizedlist>
<listitem><para>
<function>htons()</function> -- "Host to Network Short" -- konaktan ağa short
</para></listitem><listitem><para>
<function>htonl()</function> -- "Host to Network Long" -- konaktan ağa long
</para></listitem><listitem><para>
<function>ntohs()</function> -- "Network to Host Short" -- ağdan konağa short
</para></listitem><listitem><para>
<function>ntohl()</function> -- "Network to Host Long" -- ağdan konağa long
</para></listitem>
</itemizedlist>
</para><para>
Bu konuyu kavradığınızı düşünüyor olabilirsiniz. Mesela aklınıza şu
gelebilir: "<literal>char</literal> türünde bir verinin Bayt Sıralamasını
değiştirmem gerekirse ne yapmam gerekir?" Ve sonra şöyle cevap
verebilirsiniz: "Aman, boşver." Ayrıca aklınıza şu da gelebilir:
mesela 68000 işlemcili makinanız zaten Ağ Bayt Sıralamasını kullandığına
göre <function>htonl()</function> işlevini IP adreslerine uygulamanıza
gerek yoktur. Haklı olabilirsiniz. FAKAT eğer geliştirdiğiniz yazılımı
öteki türlü Bayt Sıralamasına göre çalışan bir bilgisayara taşırsanız
programınız kesinlikle çalışmaz. Taşınabilir programlar yazın!
Unutmayın Unix dünyasındasınız! (Her ne kadar Bill Gates aksini
düşünmek istese de.) Sakın unutmayın: baytlarınızı ağ üzerinde
yolculuğa çıkarmadan önce onları Ağ Bayt Sıralaması'na göre dizeceksiniz.
</para><para>
Son bir noktaya daha dikkat çekmek istiyorum: neden
<literal>struct sockaddr_in</literal> yapısı içindeki
<parameter>sin_port</parameter> ve <parameter>sin_addr</parameter>
Ağ Bayt Sıralamasında olmak zorunda iken <parameter>sin_family</parameter>
böyle bir özelliğe sahip olmak durumunda değil? Cevabı:
<parameter>sin_addr</parameter> ve <parameter>sin_port</parameter>
sırası ile IP ve UDP katmanlarında paketlenirler. Bu yüzden Ağ Bayt
Sıralamasında gönderilmeleri gerekir oysa ki
<parameter>sin_family</parameter> sadece işletim sistemi çekirdeği
tarafından veri yapısının barındırdığı adresin türünü tespit etmek
için kullanılır. Bu yüzden de bu alanın Konak Bayt Sıralamasında
bırakılması gerekir. Ayrıca <parameter>sin_family</parameter> ağ
üzerinden bir yere yollanmadığı için Konak Bayt Sıralamasında
olabilir.
</para>
</sect1>
<!-- ======================================================= -->
<!-- IP Addresses -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_structs-ipaddr">
<title>IP Adresleri ve Bunlarla Uğraşma Yöntemleri</title>
<para>
Şanslısınız çünkü IP adresleri ile uğraşmanızı sağlayacak bir grup
işlev vardır. Yani elle hesap kitap yapıp sonra da bunu bir
<literal>long</literal> içine <literal><![CDATA[<<]]></literal>
işleci ile tıkıştırmanıza gerek yok.
</para><para>
Önce örneğin elinizde bir <literal>struct sockaddr_in ina</literal>
değişkeni ve bir de <literal>10.12.110.57</literal> şeklinde bir
IP adresi olduğunu var sayalım. Bu adresi bu değişken içine
yerleştirmek istiyorsunuz. Kullanmanız gereken işlev:
<function>inet_addr()</function>. Bu işlev bir IP adresini
yukarıdaki gibi sayılardan ve noktalardan oluşan bir biçemden alıp
<literal>unsigned long</literal> türünde bir sayıya çevirir. Bu tür
bir atama şu şekilde yapılabilir:
</para><para>
<programlisting><![CDATA[
ina.sin_addr.s_addr = inet_addr("10.12.110.57"); ]]>
</programlisting>
</para><para>
Şuna dikkat edin: <function>inet_addr()</function> zaten döndürdüğü
değeri Ağ Bayt Sıralamasına göre dizilmiş olarak döndürür yani
<function>htonl()</function> işlevini burada çağırmanıza gerek yok.
Harika!
</para><para>
Yukarıdaki kod parçası pek sağlam sayılmaz çünkü hiç hata denetimi yok.
Gördüğünüz gibi <function>inet_addr()</function> hatalı bir durumla
karşılaşınca <constant>-1</constant> değerini döndürür. İkili sayı
sistemini hatırladınız mı? <constant>(unsigned)-1</constant> tam da
şu IP adresine karşılık gelir: <literal>255.255.255.255</literal>!
Bu da yayın adresidir! Aman dikkat. Hata kontrolünü düzgün bir şekilde
yapmayı sakın ihmal etmeyin.
</para><para>
Aslında <function>inet_addr()</function> yerine kullanabileceğiniz
daha güzel bir işlev var: <function>inet_aton()</function> ("aton"u,
"ascii to network" olarak okuyun):
</para><para>
<programlisting><![CDATA[
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp); ]]>
</programlisting>
</para><para>
Bir örnek vermek gerekirse: bu işlev <literal>struct sockaddr_in</literal>
yapısını paketlerken (ilerledikçe bu örnek size daha da anlamlı
gelecek <link linkend="bgnet_syscalls-bind"><function>bind()</function></link>
ve <link linkend="bgnet_syscalls-connect"><function>connect()</function></link>
kısımlarına kadar sabredin.)
</para><para>
<programlisting><![CDATA[
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET; // konak bayt sıralaması
my_addr.sin_port = htons(MYPORT); // short, ağ bayt sıralaması
inet_aton("10.12.110.57", &(my_addr.sin_addr));
memset(&(my_addr.sin_zero), '\0', 8); // geriye kalanı sıfırla ]]>
</programlisting>
</para><para>
<function>inet_aton()</function>, diğer tüm soket-bağlantılı
işlevlerden farklı olarak, sorun çıkmazsa sıfırdan farklı bir değer,
sorun çıkarsa da sıfır değerini döndürür. Ve döndürülen adres
<parameter>inp</parameter> içinde yer alır.
</para><para>
Maalesef her platform <function>inet_aton()</function> işlevini
kullanmamaktadır. Bu yüzden her ne kadar bu işlevi tercih etsek de
daha yaygın olması itibariyle örneklerde
<function>inet_addr()</function> kullanılacaktır.
</para><para>
Artık IP adreslerini ikilik sisteme kolayca dönüştürebileceğinize
göre bunun tersini yapmaya ne dersiniz? Yani mesela elinizde zaten
bir <literal>struct in_addr</literal> yapısı varsa ve siz bunu alışık
olduğunuz sayılı noktalı IP adresi biçeminde basmak istiyorsanız?
Bu durumda kullanacağımız işlev: <function>inet_ntoa()</function>
("ntoa"yı "network to ascii" olarak okuyun). Şu şekilde işinizi görür:
</para><para>
<programlisting><![CDATA[
printf("%s", inet_ntoa(ina.sin_addr)); ]]>
</programlisting>
</para><para>
Bu IP adresini basacaktır. Dikkat edin: <function>inet_ntoa()</function>
argüman olarak <literal>struct in_addr</literal> alır <literal>long</literal>
almaz. Bir diğer önemli nokta da: Bu işlev bir <literal>char</literal>'a
işaret eden bir gösterge döndürür. Söz konusu gösterge
<function>inet_ntoa()</function> içinde statik olarak depolanan bir
karakter dizisine işaret eder ve <function>inet_ntoa()</function>
işlevini her çağırışınızda son işlem görmüş olan IP adresinin üzerine
yazılır. Örneğin:
</para><para>
<programlisting><![CDATA[
char *a1, *a2;
.
.
a1 = inet_ntoa(ina1.sin_addr); // burada 192.168.4.14 var
a2 = inet_ntoa(ina2.sin_addr); // burada 10.12.110.57 var
printf("1. adres: %s\n",a1);
printf("2. adres: %s\n",a2); ]]>
</programlisting>
</para><para>şunu basar:</para><para>
<programlisting><![CDATA[
1. adres: 10.12.110.57
2. adres: 10.12.110.57 ]]>
</programlisting>
</para><para>
Eğer birden fazla adresle iş yapıyorsanız ve bunları yukarıda olduğu
gibi kaybetmek istemiyorsanız o zaman <function>strcpy()</function>
gibi bir işlev kullanarak uygun bir yere kopyalamayı sakın ihmal
etmeyin.
</para><para>
Bu konu ile söyleyeceklerim şimdilik bu kadar. Daha sonra
"whitehouse.gov" gibi bir karakter dizisini hangi yöntemlerle
karşılık gelen IP adresine çevirebileceğinizi göstereceğim
(bkz. <xref linkend="bgnet_syscalls-dns"/>).
</para>
</sect1>
</chapter> <!-- /structs -->
<!-- ======================================================= -->
<!-- System Calls -->
<!-- ======================================================= -->
<chapter xml:id="bgnet_syscalls">
<title>Sistem Çağrıları veya Felaketleri</title>
<para>
Bir UNIX bilgisayardaki ağ işlevselliğine erişmenizi anlatacağım
bölüme hoşgeldiniz. Bu işlevlerden birini çağırdınızda işletim
sistemi çekirdeği devreye girer ve düşük seviyedeki işlemleri
büyüleyici bir şekilde sizin için halleder.
</para><para>
İnsanların bu aşamada en çok takıldıkları nokta bu işlevleri hangi
sıra ile çağıracakları sorusudur. Bu bakımdan <command>man</command>
sayfaları bir işe yaramaz, eğer biraz uğraştıysanız ne demek
istediğimi biliyorsunuzdur. Bu zorlu konu ile başa çıkabilmek için
işlevleri normalde geliştirdiğiniz bir programdaki çağrılış
sıralarına tam olarak (hemen hemen) uygun şekilde size sunmaya
çalışacağım.
</para><para>
Bu açıklamalara ek olarak orada burada birkaç örnek kod parçası,
biraz süt artı kurabiye (üzgünüm bu son ikisini siz tedarik
etmelisiniz) ve tabii biraz da cesaret ile elinizdeki verileri
Internet üzerinden her yere ışınlıyor olacaksınız.
</para>
<!-- ======================================================= -->
<!-- socket -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_syscalls-socket">
<title><function>socket()</function> -- Al Şu Dosya Tanımlayıcıyı!</title>
<para>
Sanırım artık daha fazla erteleyemem -- <function>socket()</function>
sistem çağrısından bahsetmek zorundayım. İşte o işlev:
</para><para>
<programlisting><![CDATA[
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol); ]]>
</programlisting>
</para><para>
Peki ya argümanlar? Önce, <parameter>domain</parameter> argümanına
<constant>AF_INET</constant> değeri verilmeli, tıpkı
<literal>struct sockaddr_in</literal> yapısında olduğu gibi. Sonra
<parameter>type</parameter> argümanı çekirdeğe ne tür bir soket
söz konusu olduğunu söyler: <constant>SOCK_STREAM</constant> veya
<constant>SOCK_DGRAM</constant>. Son olarak da
<parameter>protocol</parameter> argümanına "<constant>0</constant>"
değerini verelim ki <function>socket()</function>,
<parameter>type</parameter> değişkenine karşılık gelen uygun protokolü
seçebilsin. (Dikkat: Bahsettiğimden daha çok
<parameter>domain</parameter> ve <parameter>type</parameter> vardır.
Bkz. <function>socket()</function> man sayfası. Ayrıca
<parameter>protocol</parameter> değerini öğrenmenin "daha iyi" bir
yöntemi vardır. Bkz. <function>getprotobyname()</function> man
sayfası.)
</para><para>
<function>socket()</function> işlevi size bir soket tanımlayıcı
döndürür ve artık siz bunu daha sonraki işlevlerinize parametre olarak
geçebilirsiniz. Eğer bir hata oluşursa işlev <constant>-1</constant>
değerini döndürür. Bu durumda <parameter>errno</parameter> isimli
global değişken hata kodunu tutar (bkz. <function>perror()</function>
man sayfası.)
</para><para>
Bazı belgelerde mistik bir <constant>PF_INET</constant> ifadesi
görebilirsiniz, korkmayın. Normalde bu canavar günlük hayatta pek
karşınıza çıkmaz fakat gene de kendisinden biraz bahsedeyim. Uzun
zaman önce adres ailesinin (<constant>AF_INET</constant>'deki "AF"
"Address Family" manasındadır) pek çok protokolü destekleyebileceği
düşünülmüştü ( <constant>PF_INET</constant>'deki "PF" "Protocol Family"
manasındadır). Ancak böyle bir şey olmadı. Yani doğru olan,
<constant>AF_INET</constant> değerini <literal>struct sockaddr_in</literal>
yapısında kullanmanız ve <constant>PF_INET</constant>'i ise
<function>socket()</function> çağırırken kullanmanızdır. Ancak pratik
olarak <constant>AF_INET</constant>'i her yerde kullanabilirsiniz.
Bu işin üstadlarından W. Richard Stevens kitabında böyle yaptığı için
ben de burada böyle yapacağım.
</para><para>
Peki tamam çok güzel de bu soket ne işe yarar? Tek başına bir işe yaramaz
tabii, lütfen okumaya devam edin ve diğer sistem çağrılarını öğrenin ki
taşlar yerine otursun.
</para>
</sect1>
<!-- ======================================================= -->
<!-- bind -->
<!-- ======================================================= -->
<sect1 xml:id="bgnet_syscalls-bind">
<title><function>bind()</function> -- Hangi Port Üzerindeyim?</title>
<para>
Bir soket edindikten sonra bunu makinanızdaki bir "port" ile
ilişkilendirmek isteyeceksiniz<footnote><para>Yani eğer
<function>listen()</function> kullanacaksanız genellikle böyle
bir şey yapmanız beklenir zaten. Mesela bir oyun sunucusuna
"telnet x.y.z port 6969" şeklinde bağlanmanız söylendiğinde karşı
tarafta tam da böyle bir hazırlık yapılmıştır.</para></footnote>.
Bu port numarası dediğimiz şey işletim sistemi çekirdeği tarafından
gelen bir paketi belli bir sürecin soket tanımlayıcısı ile
ilişkilendirebilmesi için gereklidir. Eğer tek yapacağınız bir yere
<function>connect()</function> ile bağlanmaksa o zaman buna gerek
yoktur tabii. Gene de okumaya devam edin, zevk alacaksınız.
</para><para>
<function>bind()</function> sistem çağrısının özetine man komutu
ile bakacak olursanız şöyle bir şeyle karşılaşırsınız:
</para><para>
<programlisting><![CDATA[
#include <sys/types.h>