Sıkı durun -- accept() işlevi biraz gariptir!
Neler oluyor? Şu oluyor: çok çok uzaklardan birileri
connect() işevi ile sizin makinanızda sizin
listen() ile dinlemekte olduğunuz bir porta
bağlanmaya çalışıyor. Bu bağlantı talebi accept()
ile kabul edilene dek kuyrukta bekleyecektir. Siz
accept() işlevini çağırırsınız ve ona beklemekte
olan çağrıyı kabul etmesini söylersiniz. O da size yepyeni bir soket
dosya tanımlayıcısı döndürür sadece ve sadece söz konusu bağlantıya
özel. Evet doğru duydunuz birdenbire elinizin altında iki soket dosya
tanımlayıcısı oldu! Orjinal olanı halen port üzerinden dinleme işlemini
gerçekleştirmek için kullanılıyor yeni olarak yaratılmış olan ise
send() ve recv() işlevlerinde
kullanılmak üzere emrinize amade. Hele şükür!
İşlevi şu şekilde çağırırsınız:
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
sockfd dediğimiz listen()
ile dinlediğiniz soket tanımlayıcıdır. Basit. addr
yerel olarak kullandığınız struct sockaddr_in
yapısını gösteren bir göstergedir. Gelen bağlantılarla ilgili
bilgiler burada barındırılacak (yani bu yapıyı kullanarak gelen
bağlantının hangi bilgisayar ve hangi porttan geldiğini
öğrenebilirsiniz). addrlen yerel bir tamsayı
değişkendir ve kullanılmadan önce accept()
sizeof(struct sockaddr_in) değerini almalıdır.
accept() işlevi bu değerden daha fazla
sayıda baytı addr içine yerleştirmeyecektir.
Eğer söz konusu değerden daha azını yerleştirirse o zaman da
addrlen değerini, bunu yansıtacak şekilde
değiştirecektir.
Tahmin edin ne diyeceğim? accept() hata durumunda
-1 değerini döndürür ve errno
değişkenine ilgili hata kodunu yerleştirir. Tahmin etmiş miydiniz?
Gerçekten?
Biliyorum, bir seferde sindirmesi kolay değil. İsterseniz aşağıdaki
örnek koda bakalım:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MYPORT 3490 // kullanıcıların bağlanacağı port
#define BACKLOG 10 // kuyrukta bekleyecek bağlantı sayısı
main()
{
int sockfd, new_fd; // sock_fd ile dinle, new_fd yeni bağlantı için
struct sockaddr_in my_addr; // benim adres bilgim
struct sockaddr_in their_addr; // bağlananın adres bilgisi
int sin_size;
sockfd = socket(AF_INET, SOCK_STREAM, 0); // hata denetimi yap!
my_addr.sin_family = AF_INET; // konak bayt sıralaması
my_addr.sin_port = htons(MYPORT); // short, ağ bayt sıralaması
my_addr.sin_addr.s_addr = INADDR_ANY; // otomatik olarak benim IP'im
memset(&(my_addr.sin_zero), '\0', 8); // geriye kalanı sıfırla
// hata denetimi yapmayı sakın unutmayın:
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
listen(sockfd, BACKLOG);
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
.
.
.
Lütfen dikkat edin: new_fd şeklindeki soket
tanımlayıcıyı tüm send() ve recv()
işlevleri için kullanacağız. Eğer sadece ve sadece tek bir bağlantıyı
kabul edecekseniz close() ile
sockfd üzerindeki dinleyici soketi
kapatabilirsiniz böylece aynı port üzerinden başka bağlantı yaplamaz,
eğer istediğiniz gerçekten bu ise.