C++ Üzerinde Soket Programlama
typedef struct fd_set {
u_int fd_count;
SOCKET fd_array[FD_SETSIZE];
}fd_set;
Gördüğünüz gibi içerisinde bir sayac ve bir de soket dizisi var. Biz dosya tanımlayıcı kümesine veri ekleyip çıkardığımızda aslında bu soket dizisine soket ekleyip çıkarmış oluyoruz ve sayac da ona göre güncelleniyor…
Hemen bir dosya tanımlayıcı kümesi tanımlayalım…
fd_set okunanlar;
Evet, artık okunanlar adında bir dosya tanımlayıcı kümemiz var, şimdi bunun içine soketlerimizi yerleştirmesi kaldı. İstediğimiz soketleri yerleştirip select fonksiyonunun 2. parametresine yani readfds ye yerleştirirsek, bu soketlerden birine veri geldiğinde select bizi uyarır ve biz de recv ile gelen veriyi alırız.. Sanırım taşlar yerine oturmaya başladı J
Şimdi tanımlayıcı kümemize nasıl soket ekleyip sileceğimizi öğrenelim. Bunlar için bazı makroları kullanacağız..
FD_SET(int fd, fd_set * okunanlar); Bu makro ile kümemize bir soket ekleriz.
FD_CLR(int fd, fd_set * okunanlar); Bu makro ile kümemizden bir soket siler iz
FD_ZERO(fd_set *okunanlar); Bu makro ile tüm kümeyi sıfırlayabiliriz.
FD_ISSET(int fd, fd_set * okunanlar); Bu makro ile soketi kümemizde mi diye
Kontrol ederiz…
Burada ilk parametre olan int fd (file descriptor), dosya tanımlayıcısıdır, biz soketimizi yazacağız doğal olarak. Dikkat edilmesi gereken, diğer parametre dosya tanımlayıcı kümemizin kendisi değil adresi. Yani biz kümemizi parametre olarak geçerken & işlecini kullanmalıyız…
FD_SET(skt, &okunanlar);
FD_CLR(skt, &okunanlar);
FD_ZERO(&okunanlar);
FD_ISSET(skt, &okunanlar);
Şeklinde kullanacağız… Artık soket programlama ile ilgili birçok şeyi biliyoruz, uzman sayılmasak da rahatlıkla piyasadaki birçok programın biraz daha amatörünü yazabiliriz.
Sanırım artık bir örnek vermenin zamanı geldi.. İlk programımız bir chat sunucusu olsun..
********************************************************************
// Yazan: KuLTigiN
// www.tahribat.com
#include
#include
#define PORT 5000
int main(){
WSADATA wsdata; // gereksiz MS işleri..
SOCKET ss,is; // sunucu soket ve istemci soket
fd_set anatanim,gecici; // ana ve geçici dosya tanimlayici kümeleri
char tmp[256]; // istemci verisi için tampon
int gelenbayt,boyut; // recv de gelen veri, accept için boyut...
int i, j; // döngü sayacları.
struct sockaddr_in sunucu; // sunucu adres bilgileri
struct sockaddr_in istemci; //istemci adres bilgileri
sunucu.sin_family = AF_INET;
sunucu.sin_port = htons(PORT);
sunucu.sin_addr.s_addr = INADDR_ANY;
WSAStartup(MAKEWORD(2,0),&wsdata);
FD_ZERO(&anatanim); // ana kümeyi ve gecici kümeyi temizle
FD_ZERO(&gecici);
//-----------------------------
if( (ss=socket(AF_INET, SOCK_STREAM, 0))==-1 )
fprintf(stderr,"Sunucu soket hatasi!\n");
//-----------------------------
if( (bind(ss, (struct sockaddr *)&sunucu,sizeof(struct sockaddr) ))==-1 )
fprintf(stderr,"Bind fonksiyonu yurutulemedi!\n");
//-----------------------------
if (listen(ss,10) == -1)
fprintf(stderr,"Port dinlenemiyor!\n");
//-----------------------------
FD_SET(ss, &anatanim);
for(;;) { // Ana for döngüsü
gecici = anatanim;
if(select(0, &gecici, NULL, NULL, NULL)==-1)
fprintf(stderr,"select fonksiyonu yurutulemedi\n");
i=gecici.fd_array[0];
//----------------------------------------------
if (i == ss) {
boyut = sizeof(istemci);
is = accept(ss, (struct sockaddr *)&istemci,&boyut);
FD_SET(is, &anatanim); // ana listeye ekle
printf("Istemci baglandi: %s\n",inet_ntoa(istemci.sin_addr));
}
//----------------------------------------------
else {
if ((gelenbayt=recv(i, tmp, sizeof(tmp), 0)) <= 0) {
if(gelenbayt==0) fprintf(stderr,"Baglantikoptu \n");
else fprintf(stderr,"Baglanti hatasi \n");
closesocket(i);
FD_CLR(i, &anatanim);
}
//----------------------------------------------
else
for(j = 0; j < anatanim.fd_count; j++) if(anatanim.fd_array[j] != ss && anatanim.fd_array[j] != i)
send( anatanim.fd_array[j], tmp, gelenbayt, 0);
//----------------------------------------------
}
}
WSACleanup();
return 0;
}
//Bitti :)
Hit: 10591
Yazar: Tugberk