并發(fā)網(wǎng)絡(luò)服務(wù)器:
- 基本概念解釋
多進(jìn)程并發(fā)服務(wù)器
togglesp.c
void sigchld_handler(int sig) {
while (waitpid(-1, 0, WNOHANG) > 0);
return;
}
int main(int argc, char **argv) {
int listen_sock, conn_sock, port;
socklen_t clientlen=sizeof(struct sockaddr_in);
struct sockaddr_in clientaddr;
if (argc != 2) { … }
port = atoi(argv[1]);
signal(SIGCHLD, sigchld_handler);
listen_sock = open_listen_sock(port);
while (1) {
conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
if (fork() == 0) {
close(listen_sock);
toggle(conn_sock); /* Child process services client */
close(conn_sock);
exit(0);
}
close(conn_sock);
}
}
特點(diǎn):父子共享打開(kāi)文件表劳坑,但不共享用戶地址空間若厚。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):每個(gè)進(jìn)程都有獨(dú)立的地址空間裙士,進(jìn)程間不會(huì)相互影響,有較好的可靠性和安全性
缺點(diǎn):進(jìn)程間共享狀態(tài)信息變得麻煩,IPC機(jī)制開(kāi)銷(xiāo)很高心剥,進(jìn)程間數(shù)據(jù)共享低效
基于多線程并發(fā)服務(wù)器
togglest.c:
int main(int argc, char **argv) {
int listen_sock, *conn_sock_p, port;
socklen_t clientlen=sizeof(struct sockaddr_in);
struct sockaddr_in clientaddr;
pthread_t tid;
if (argc != 2) {。瘩缆。关拒。 }
port = atoi(argv[1]);
listen_sock = open_listen_sock(port);
while (1) {
conn_sock_p = malloc(sizeof(int));
*conn_sock_p = accept(listen_sock, (SA *) &clientaddr, &clientlen);
pthread_create(&tid, NULL, serve_client, conn_sock_p);
}
}
void * serve_client (void *vargp) {
int conn_sock = *((int *)vargp);
pthread_detach(pthread_self());
free(vargp);
toggle(conn_sock);
close(conn_sock);
return NULL;
}
預(yù)線程化并發(fā)服務(wù)器
-
基本思想
預(yù)先創(chuàng)建一批工作者線程,每次建立一個(gè)連接庸娱,工作者線程就領(lǐng)取一個(gè)任務(wù)着绊,負(fù)責(zé)與一個(gè)客戶端通信以消除服務(wù)器運(yùn)行過(guò)程中創(chuàng)建、撤銷(xiāo)線程的開(kāi)銷(xiāo).
image.png
任務(wù)池定義(task_pool.c涌韩、task_pool.h)
生產(chǎn)者/消費(fèi)者模型
# inpos畔柔、outpos分別是緩沖區(qū)寫(xiě)入、讀出指針
# mutex:為互斥信號(hào)量
# avail臣樱、ready是同步信號(hào)量
typedef struct {
int *socks; /* Buffer array */
int cnt; /* Maximum number of cell */
int inpos; /* buf[inpos] is first available cell */
int outpos; /* buf[outpos] is fist item */
sem_t mutex; /* Protects accesses to socks */
sem_t avail; /* Counts available cells */
sem_t ready; /* Counts ready items */
} task_pool_t;
緩沖區(qū)初始化
void task_pool_init(task_pool_t *tp, int n)
{
tp->socks = Calloc(n, sizeof(int));
tp->cnt = n; /* socks holds max of n items */
tp->inpos= tp->outpos = 0; /* Empty socks iff inpos== outpos */
sem_init(&tp->mutex, 0, 1); /* Binary semaphore for locking */
sem_init(&tp->avail, 0, cnt); /* Initially, socks has cnt empty cell */
sem_init(&tp->ready, 0, 0); /* Initially, socks has zero data items */
}
讀寫(xiě)緩沖區(qū)
void task_insert (task_pool_t *tp, int item){
sem_wait(&tp->avail); /* Wait for available cell */
sem_wait(&tp->mutex); /* Lock the shared variable tail pointer */
tp->socks[tp->inpos] = item; /* Insert the item */
tp-> inpos =(tp-> inpos +1)%(tp->cnt); /* adjuset tail point */
sem_post(&tp->mutex); /* Unlock the buffer */
sem_post(&tp->ready); /* Announce available item */
}
int task_remove(task_pool_t *tp){靶擦。腮考。。}
預(yù)線程化服務(wù)器代碼(togglest_pre.c)
int main(int argc, char **argv) {
int i, listen_sock, conn_sock, port;
socklen_t clientlen=sizeof(struct sockaddr_in);
struct sockaddr_in clientaddr;
pthread_t tid;
if (argc != 2) { 玄捕。踩蔚。。 }
port = atoi(argv[1]);
task_pool_init(&tp, SBUFSIZE);
listen_sock = open_listen_sock(port);
for (i = 0; i < NTHREADS; i++) /* Create worker threads */
pthread_create(&tid, NULL, serve_client, NULL);
while (1) {
conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
task_insert(&tp, conn_sock); /* Insert conn_sock in task pool */
}
}
void * serve_client(void *vargp) {
pthread_detach(pthread_self());
while (1) {
int conn_sock = task_remove(&tp);
toggle(conn_sock);
close(conn_sock);
}
}
網(wǎng)絡(luò)編程:
套接字枚粘、
結(jié)構(gòu):網(wǎng)卡馅闽、TCP協(xié)議、套接字(Socket)
套接字:含有進(jìn)程接收信息的完整地址(Socket地址:IP地址馍迄、端口號(hào))
- Internet連接客戶端與服務(wù)器的網(wǎng)卡,
- TCP/IP協(xié)議軟件連接Socket與網(wǎng)卡,
- 套接字接口連接進(jìn)程與Socket,
TCP連接整合了以上兩個(gè)工具,tcp連接是連接通訊雙方套接字的一條通信線路.一條TCP連接實(shí)際上就是一個(gè)文件描述符,可用read/write或send/recv進(jìn)行數(shù)據(jù)收發(fā).
-
TCP連接實(shí)例
服務(wù)器端口號(hào):規(guī)定為80
客戶端端口號(hào):隨機(jī)分配福也,12345
image.png
字節(jié)序、
-
網(wǎng)絡(luò)序(網(wǎng)絡(luò)序):高位在低地址字節(jié)
大端模式 -
主機(jī)序(小端模式):低位在低地址字節(jié)
小端模式 主機(jī)序與網(wǎng)絡(luò)序的轉(zhuǎn)換
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
返回:網(wǎng)絡(luò)序的值攀圈。
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsiged short int netshort);
返回:主機(jī)序的值暴凑。IP地址
由32位整數(shù)網(wǎng)絡(luò)序0x8002c2f2轉(zhuǎn)換成點(diǎn)分十進(jìn)制128.2.193.242
128=0x80,2=0x02赘来,193=0xc2现喳,242=0xf2
轉(zhuǎn)換函數(shù):
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
a: 字符串 n:32位整數(shù)
網(wǎng)絡(luò)通信API函數(shù):
(一)客戶端
(1)創(chuàng)建套接字
int socket(int domain, int type , int protocol);
示例:client_sock = socket(AF_INET , SOCK_STREAM, 0);
(2) connect 函數(shù)
int connect (int client_sock , struct sockaddr *serv_addr , int addrlen);
(3)包裝函數(shù)open_client_sock
(二)服務(wù)器端
(1)創(chuàng)建
int socket(int domain, int type , int protocol);
(2)綁定
int bind(int serv_sock, struct sockaddr *my_addr , int addrlen);
(3)監(jiān)聽(tīng)
int listen(int serv_sock, int backlog);
(4)接受連接請(qǐng)求
int accept(int listen_sock, struct sockaddr *addr , int *addrlen);
包裝函數(shù):open_listen_sock