linux
select
C LANGUAGE
Author: WhoAmI
Date: 20220805
E-mail: kccddb@gmail.com
Copyright: CC BY-NC-SA
有效的 fd 個數, fd 的 狀態(新連線, 讀, 寫, 例外), timeout , 與 select() 回傳狀態 是此種方法的重點之一!
至於 poll 而 epoll epoll_wait 則是 Linux 改良版 (red-black tree)! 都是類似觀念!
重要提醒這是一個小程式(能動不代表能用) 但是可學的問題很多, select (與 epoll, epoll_wait)是很重要的system call, "一定要會". 這不一定只用於網路程式, 用於很多地方, 尤其I/O 的部分!
Futher Reading:
select system call-synchronous I/O multiplexing
/*
Source:
select.c
Usage:
Server:
./select
Client:
telnet ip port
//如果用 window putty 的 telnet 可能怪怪的, 因此最好寫一簡單的client 參考 Append A.
select 是很重要的 function 用途很多!
上課說明 UNIX OS 原來設計的缺點, (不用害怕, 不難的!!) 效能不好 因此後來改 epoll_wait 或 non-blocking mode 這裡也是實作關鍵, 還有 write_fds 也可用
再次提醒: tv 值會被 OS 改變為剩下時間!!
**TRY IT and FIX IT **
以下很重要 不小心會崩潰如山倒*
congestion propagation:整個系統效能除了本身程式效能以外還與系統規劃設計有關
input buffer 與 output buffer 的觀念相當重要! (這裡我們不研究研究數學理論)
整個 系統是 input queue 與 output queue 環環相扣的 queueing networks 的問題!(想像這世界的交通網路!)
Computer Organization | Locality and Cache friendly code
if(發生機率高){
}else{
}
效能一般比較好
Linux kernel 中就有 likely ()和 unlikely () macro
優化效能
DEAD LOCK
There are many bugs when "recv/read" and "send/write" are performed, in real case.
Notice that "send/write" may cause the blocking effect, when the network or OS is un-stable.
HW:
TRY to WRITE a CLIENT to GENERATE SERVER CRASH
HELP 1:
(a) system level ERROR PROPAGATION & DEAD LOCK
for (…){
assume i=k
(nbytes=read(i, buf, sizeof(buf))) > 0
…
for all j!=k {
send(j, buf, nbytes, 0)
}
If client k has many data frames, the server will forward data frames to all clients (j!=k).
This will cause a big problem because the network will crash.
Hence, one must set "send IO" timeout usually.
…
}
(b) send: blocking problem (non-blocking mode or timeout)
HOW TO generate this problem
如何測試? 提供您想法: client >>透過無線或3G 大量資料快速傳送至 server
© send: broken pipe (SIGPIPE)
(a) HOW TO generate this problem
(b) Use signal(SIGPIPE, SIG_IGN) to avoid the signal
如何測試? 提供您想法: client >>透過無線或3G 大量資料快速傳送至 server, 然後讓server 非正常 off!
/*
Please see man 2 send
*/
(d)
For advanced user, please study three problems:
Handle TCP_NODELAY with care
/* Disable TCP Nagle i.e., set tcp_proto->p_proto TCP_NODELAY*/
optval=1;
setsockopt(fd, SOL_TCP, TCP_NODELAY, &optval, sizeof(optval))
Please care
O_NONBLOCK
fcntl(fd, F_SETFL, O_NONBLOCK);
SO_KEEPALIVE
*/
HELP 3 "zombie" 的產生!! & SIGCHLD
Linux man page
exit - cause normal process termination
#include <stdlib.h>
void exit(int status);
The exit() function causes normal process termination and the value of status & 0377 is returned to the parent (see wait(2)).
//小心~~~順便一提 0377 是 C 語言 的8進位 (0377 =0xFF) <<<很多人搞錯的!!
The C standard specifies two constants, EXIT_SUCCESS and EXIT_FAILURE, that may be passed to exit() to indicate successful or unsuccessful termination, respectively. ***
Constant Explanation
EXIT_SUCCESS successful execution of a program
EXIT_FAILURE unsuccessful execution of a program
***http://en.cppreference.com/w/c/program/EXIT_status
If your process has child processes, please handle SIGCHLD or set signal(SIGCHLD, SIG_IGN) before the fork.
see https://www.win.tue.nl/~aeb/linux/lk/lk-5.html
After exit(), the exit status must be transmitted to the parent process. There are three cases:
(A) If the parent has set SA_NOCLDWAIT, or has set the SIGCHLD handler to SIG_IGN, the status is discarded and the child dies immediately.
(B) If the parent was waiting on the child, it is notified of the exit status and the child dies immediately.
© Otherwise, the child becomes a "zombie" process: most of the process resources are recycled, but a slot containing minimal information about the child process (termination status, resource usage statistics) is retained in process table. This allows the parent to subsequently use waitpid(2) (or similar) to learn the termination status of the child; at that point the zombie process slot is released.
其實會簡單的 GPIO driver 配合 user space select 很有用途
我只提幾個
很多 device node 可以用 open 但不能用 fopen ! 為甚麼?
很多 device node 可以用 read 不能用 select 為甚麼?
當不能用時, 如何改寫!
只能一個 process 讀取, 如何改變成 多個 process 讀取?
…
很多技巧…期待您好好學~這可是您的專長之一
再次顯示 "會動容易, 實用不容易"
Append A. 這是簡單測試用
//注意小bug 沒有 '\0'!!! 請自己寫!!
Appendix B.
O_NONBLOCK, connect, read, send 與 select 合併運用提供參考
ERRORS:
EAGAIN or EWOULDBLOCK
The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.
EINTR
The call was interrupted by a signal before any data was read;
ERRORS:
EAGAIN
The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the write would block.
EINTR
The call was interrupted by a signal before any data was written;
EPIPE
fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
Socket options (see man 7 socket)
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an
error. The argument is a struct timeval. If an input or out‐
put function blocks for this period of time, and data has been
sent or received, the return value of that function will be
the amount of data transferred; if no data has been trans‐
ferred and the timeout has been reached, then -1 is returned
with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for
connect(2)) just as if the socket was specified to be non‐
blocking. If the timeout is set to zero (the default), then
the operation will never timeout.
Timeouts only have effectfor system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2));
timeouts have no effect for select(2), poll(2), epoll_wait(2), and so on.
運用 popen 執行server 端的程式
popen, pclose - pipe stream to or from a process
Homework: