某有事件發生時就會發出signal通知Process,而Process就必須來處理這些signal。
signal可以由Process到另一個Process,或是由Kernel到Process。
我們可以自行定義signal handler來處理各個不同的signal。
系統雖有signal()的function來讓我們指定signal對應的signal handler。然而,由於沒有統一的標準,所以各家UNIX實作上會有所不同,會造成相容性的問題。所以POSIX規範要使用sigaction()這個function。然而sigaction()使用上較signal()複雜。
2008年1月25日 星期五
signal
2007年11月26日 星期一
Concurrent Server
Server可以分為兩種型態,iterative和concurrent。
iterative server一次服務一個使用者,所以若其中某個使用者的服務時間過久,會影響到整個效能。而concurrent server則是可以同時服務多個使用者,最簡單的方法可以利用fork來產生child process來達成此目的。下面則為簡單的範例。
pid_t pid;
int listenfd, connfd;
listenfd = socket( ... );
bind(listenfd, ... );
listen(listenfd, 5);
for (; ;) {
connfd = accept (listenfd, ... );
if((pid = fork()) == 0) {
close(listenfd);
handle the connection
close(connfd);
exit(0);
}
close(connfd); // 由於fork產生的child process會讓connfd的reference counter多1,要記得關掉
}
2007年11月24日 星期六
fork
如何寫一個concurrent server?我們可以使用fork這個function來達成,定義於"unistd.h",用法如下:
pid_t fork(void);
呼叫fork()會產生一個child process,在呼叫fork()指令之前所有parent process開啟的descriptors會與child processs共享。至於如何分辨parent還是child,則依呼叫fork()後的回傳值決定,parent會收到child的Process ID,而child則會收到0。因為,兒子只有一個父親,只要呼叫getppid即可取得父親的PID,而父親可能會有很多的兒子,所以需要記錄每一個兒子的PID。
fork有兩種使用方法:
- Process複製自己一份,讓其中一個處理某一個運算,另一個則是做其它事。
- Process想執行其它程式,當呼叫fork時會複製一份child process,然後child process執行exec用新程式來取代目前的程式。
2007年11月6日 星期二
IP位址轉換
如何將人讀的140.120.*.*的IP轉換成network byte order的兩進位表示,可以使用以下的函式(定義於"arpa/inet.h">:
// String to 32-bit binary
int inet_aton(const char *strptr, struct in_addr *addrptr);
// 32-bit binary to String
char *inet_ntoa(struct in_addr inaddr);
然而,以上的函式不能處理IPv6的問題,因此有另外兩個函式可以同時處理IPv4與IPv6:
int inet_pton(int family, const char *strptr, void *addrptr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
其中當處理IPv4時,family值為AF_INET,IPv6時則為AF_INET6。
inet_ntoa裡,size_t len為回傳string的長度,避免Overflow。
"netinet/in.h"有定義兩個常數,讓我們可以使用他來設定長度。
#define INET_ADDRSTRLEN 16 /* for IPv4 dotted-decimal */
#define INET6_ADDRSTRLEN 46 /* for IPv6 hex string */
2007年11月5日 星期一
Network Byte Order
Internet Protocols是採用Big-endian,因此有四個函式(定義於"netinet/in.h")可供我們轉換host byte order <--> network byte order:
uint16_t htons(uint16_t host16bitvalue) ; // host to network short
uint32_t htonl(uint32_t host32bitvalue) ; // host to network long
uint16_t ntohs(uint16_t net16bitvalue) ; // network to host short
uint32_t ntohl(uint32_t net32bitvalue) ; // network to host long
當處理port的時候,可以使用hotns()和ntohs()
當處理IPv4位址,可以使用hotnl()和ntohl()
2007年11月3日 星期六
Value-Result
Socket address sturcture總是以reference(指標指向結構)傳進socket函式,而結構的大小也會被傳入。然而長度傳入的方法取決於process to kernel或是kernel to process。
Process to Kernel(bind, connect, sendto)
struct sockaddr_in serveraddr;
bind(sockfd, (Struct sockaddr *) &serveraddr, sizeof(serveraddr));
長度的資訊是用來告訴該copy多少資料從process到kernel
Kernel to Process(accept, recvfrom, getsockname, getpeername)
struct sockaddr_in clientaddr;
socklen_t letngth;
length = sizeof(clientaddr);
getpeername( sockfd, (Struct sockaddr*) &clientaddr, &length)
其中,長度的值會改變。用指標傳入,告訴kernel所傳入的struture大小。而當函式結束時,會回傳kernel儲存多少資料在structure,將值存在length上。像length這種參數稱為value-result參數。
2007年11月1日 星期四
Socket Address Structure
IPv4與IPv6的Socket Address Structure定義於"netinet/in.h"裡。
IPv4 Socket address structure: sockaddr_in
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
/* Structure describing an Internet socket address. */
struct sockaddr_in {
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8]; /* Padding */
};
/* IPv6 address */
IPv6 Socket address structure: sockaddr_in6
struct in6_addr {
uint8_t s6_addr[16];
};
struct sockaddr_in6 {
uint8_t sin6_len;
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port;
uint32_t sin6_flowinfo
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};