13 Ekim 2017 Cuma

select örnekleri

Giriş
Açıklaması şöyle
select and poll does a linear search across the sockets, which does not scale very well.
select () ile kullanılan socketler non-blocking olmak zorunda değil. Ancak ben non-blocking olmasını tercih ediyorum. Eğer socket okumak üzere hazır olarak görünse bile, hata olursa sadece EWOULDBLOCK koduna bakarak problemsiz çalışabiliriz. Java'da ise socketin non-blocking olması gerekir.
Seri iletişim için şöyle yaparız.
open  (...,O_RDRW |O_NDELAY |O_NONBLOCK);

fd_set
Önce bir set tanımlanır.
fd_set sockSet;
Aynı zamanda FD_SET olarak ta tanımlanabilir.
FD_SET sockSet;
Bu set sıfırlanır.
FD_ZERO(&sockSet);
Daha sonra set'e izlemek istediğimiz fd'leri atarız. Bu çağrı her bir socket için tekrarlanır
FD_SET(fd1, &sockSet);
select çağrısı sonucunda fd_set değişir. Bu yüzden çağrıdan önce fd_set izlenmek istenen fd'ler için tekrar doldurulur. (rearm) Şöyle yaparız.
int maxfd = server_sock2 + 1;
FD_SET sockSet;
int ret;
while(1) {
  // Setup SD_SET each time calling select
  FD_ZERO(&read_fs);
  FD_SET(server_sock1, &read_fs);
  FD_SET(server_sock2, &read_fs);
  if ((ret = select(maxfd+1,&readfds,NULL,NULL,NULL)) == -1) {
    error("Err in select");
  }
  for(i = 0; i < maxfd && ret; i++, ret--) {
    if(FD_ISSET(i, &readfds) {...}
  }
}
Writable socket
Bir socketin yazılabilir olması sanırım sadece TCP soketi için geçerli. UDP connectionless olduğu için socket her zaman yazılabilir durumda.

FD_ISSET macrosu
Eğer belli bir socketi kontrol etmek istersek şöyle yaparız.
if(FD_ISSET(f1, &sockSet)) {
  recv(f1, ..., ...);
}
FD_SET macrosu
İzlemek istediğimiz fd'yi fd_set yapısına ekler. Şöyle yaparız.
int server_sock = ...;
FD_SET sockSet;
FD_ZERO(&rsockSet);
FD_SET(server_sock, &sockSet);
FD_ZERO macrosu
fd_set yapısını sıfırlar. Şöyle yaparız.
FD_SET sockSet;
FD_ZERO(&sockSet);
select çağrı parametreleri
İlk parametre fd_set'e girilmiş en büyük socket değerinin bir fazlasıdır. İkinci parametre okunacak fd_set'i. Üçüncü parametre yazılacak fd_set'i, Dördüncü parametre exception fd_set'i, altıncı parametre is timeout değeridir.

select - timeout olmadan okuma
Timeout kullanmadan şöyle yaparız.
if(select(maxfd+1, &read_fs, NULL, NULL, NULL))
{...}
select - timeout ile okuma
select çağrısı Linux'ta timeout değerini değiştirir. Bu yüzden her çağrıdan önce timeout değişkenini tekrar doldurmak gerekir. Açıklaması şöyle.
On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1-2001 permits either behavior.) This causes problems both when Linux code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
Yani şöyle yaparız.
while (1)
{
  struct timeval tv = {1, 0};

  int retval=select(maxfd+1,read_fs, NULL, NULL,&tv);
  ...
}
select çağrı sonucu
Çağrı sonucu -1 ise hata olmuştur.
Çağrı sonucu > 0 ise okunacak bir şey vardır.
Çağrı sonucu  0 ise timeout olmuştur.

Örnek
Şöyle yaparız.
if (select(max_fd+1, &socketSet, NULL, NULL, &tv) > 0) {...}
Örnek
Şöyle yaparız.
int result = select(max_fd + 1, &socketSet, NULL, NULL, &tv);

switch (select_result) {
  case -1: //Error
    ...
  case 0: //Timeout
    ...
  default:
    //DATA AVAILABLE
    break;
}

Hiç yorum yok:

Yorum Gönder