此篇博文主要講解如何動態創建進程的方法,此方法模型如下:
<span style="font-size:18px;">main{
ps=socket();
bind();
listen();
while(1){
cs=accept();
if(cs){
pid=fork();
if(pid==0){//子進程處理
close(ps);
do_child(cs);
}
else{//父進程處理
.......
close(cs);
}
}
}
}
do_child(cs){
read();
write();
close(cs);
}</span>
下面用代碼介紹如何使用此種模型:
服務端程序:
<span style="font-size:18px;">#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFLEN 1024
#define SERVER_PORT 8888
#define BACKLOG 5
static void handle_request(int s_c)
{
printf("process %d is being to handle client %d\n",getpid(),s_c);
time_t now; /*時間*/
char buff[BUFFLEN];/*收發數據緩衝區*/
int n = 0;
memset(buff, 0, BUFFLEN);/*清零*/
n = recv(s_c, buff, BUFFLEN,0);/*接收發送方數據*/
if(n > 0 && !strncmp(buff, "TIME", 4))/*判斷是否合法接收數據*/
{
memset(buff, 0, BUFFLEN);/*清零*/
now = time(NULL);/*當前時間*/
sprintf(buff, "%24s\r\n",ctime(&now));/*將時間拷貝入緩衝區*/
send(s_c, buff, strlen(buff),0);/*發送數據*/
}
/*關閉客戶端*/
close(s_c);
}
static void handle_connect(int s_s)
{
int s_c; /*客戶端套接字文件描述符*/
struct sockaddr_in from; /*客戶端地址*/
int len = sizeof(from);
/*主處理過程*/
while(1)
{
/*接收客戶端連接*/
s_c = accept(s_s, (struct sockaddr*)&from, &len);
if(s_c > 0)/*客戶端成功連接*/
{
/*創建進程進行數據處理*/
if(fork() > 0){/*父進程*/
close(s_c);/*關閉父進程的客戶端連接套接字*/
}else{
handle_request(s_c);/*處理連接請求*/
exit(0);
}
}
}
}
int main(int argc, char *argv[])
{
int s_s; /*服務器套接字文件描述符*/
struct sockaddr_in local; /*本地地址*/
/*建立TCP套接字*/
s_s = socket(AF_INET, SOCK_STREAM, 0);
int optval=1;
int ret=setsockopt(s_s,SOL_SOCKET,SO_REUSEADDR,(int *)&optval,sizeof(optval));
/*初始化地址接哦股*/
memset(&local, 0, sizeof(local));/*清零*/
local.sin_family = AF_INET;/*AF_INET協議族*/
local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
local.sin_port = htons(SERVER_PORT);/*服務器端口*/
/*將套接字文件描述符綁定到本地地址和端口*/
int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
err = listen(s_s, BACKLOG);/*偵聽*/
/*處理客戶端連接*/
handle_connect(s_s);
close(s_s);
return 0;
}
</span>
客戶端程序:
<span style="font-size:18px;">#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#define BUFFLEN 1024
#define SERVER_PORT 8888
int main(int argc, char *argv[])
{
int s; /*服務器套接字文件描述符*/
struct sockaddr_in server; /*本地地址*/
char buff[BUFFLEN];/*收發數據緩衝區*/
int n = 0; /*接收字符串長度*/
/*建立TCP套接字*/
s = socket(AF_INET, SOCK_STREAM, 0);
/*初始化地址接哦股*/
memset(&server, 0, sizeof(server));/*清零*/
server.sin_family = AF_INET;/*AF_INET協議族*/
server.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
server.sin_port = htons(SERVER_PORT);/*服務器端口*/
/*連接服務器*/
int err = connect(s, (struct sockaddr*)&server,sizeof(server));
memset(buff, 0, BUFFLEN);/*清零*/
strcpy(buff, "TIME");/*拷貝發送字符串*/
/*發送數據*/
send(s, buff, strlen(buff), 0);
memset(buff, 0, BUFFLEN);/*清零*/
/*接收數據*/
n = recv(s, buff, BUFFLEN, 0);
/*打印消息*/
if(n >0){
printf("TIME:%s\n",buff);
}
close(s);
return 0;
}
</span>
此模式是最傳統且最普遍常用的併發模型,那麼他也存在缺陷:
1 動態創建也就是臨時創建進程,會增加cpu的開銷(目前此影響不怎麼明顯,可以通過命令ps aux| grep 進程名)
2 如果連接過多,那麼就會創建更多的子進程,會受到系統爲此用戶分配的最大進程數的限制(例如:root用戶爲kevin用戶設置最大開啓100進程數)