2017年9月30日 星期六

2 進階技術 select

7.1. Blocking(阻塞)


很多函式都會 block,accept() 會 block,全部的 recv() 函式都會 block。
socket() 建立 socket descriptor 時,kernel(核心)會將它設定為 blocking。若你不想要 blocking socket,你必須呼叫 fcntl().

#include <unistd.h> #include <fcntl.h> sockfd = socket(PF_INET, SOCK_STREAM, 0); fcntl(sockfd, F_SETFL, O_NONBLOCK);
如果你試著讀取 non-blocking socket,而 socket 沒有資料時,函式就不會發生 block,而是傳回 -1,並將 errno 設定為 EWOULDBLOCK。



7.2. select():同步 I/O 多工


select() 授予你同時監視多個 sockets 的權力,它會告訴你哪些 sockets 已經有資料可以讀取、哪些 sockets 已經可以寫入,如果你真的想知道,還可以告訴你哪些 sockets 觸發了例外。

即使 select() 有相當好的可移植性,不過卻是最慢的監視 sockets 方法。一個比較可行的替代方案是 libevent ,將全部的系統相依要素封裝起來,用在取得 socket 的通知。


#include <sys/select.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
           struct timeval *timeout);

FD_SET(int fd, fd_set *set);
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_ZERO(fd_set *set);


第一個參數 n 的值是最大的那個 socket descriptor 數值在加上 1。

struct timeval 可以設定 timeout 的時間, 如果timeout為0則一個一個檢查不stop

struct timeval {
  int tv_sec; // 秒(second)
  int tv_usec; // 微秒(microseconds)
};




p.s. 怎決定放readfds or writefds or exceptfds



  • poll vs select


??

  • Socket Option 設定

修改socket 設定技術



int getsockopt(int s, int level, int optname, void *optval,
               socklen_t *optlen);
int setsockopt(int s, int level, int optname, const void *optval,
               socklen_t optlen);



level通常為SOL_SOCKET
optname 可以有很多,細看socket man page , 如修改receive buffer , SO_REVBUF

int rcvBufferSize; 
int sockOptSize = sizeof(rcvBufferSize); 

// Retrieve and print the default buffer size 
if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize, &sockOptSize) < 0)       DieWithSystemMessage("getsockopt() failed"); 
     printf("Initial Receive Buffer Size: %d\n", rcvBufferSize);

// Double the buffer size rcvBufferSize *= 2;

 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize, sizeof(rcvBufferSize)) < 0) 
     DieWithSystemMessage("setsockopt() failed");


receive buffer default=>/proc/sys/net/core/rmem_default
min size=> doubled (256)
max size=>/proc/sys/net/core/rmem_max