多进程服务器端
多进程服务端
利用信号回收子进程例子(利用子进程结束后向父进程发送SIGCHLD信号来回收子进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include <me.h>
//子进程结束信号
void read_childproc(int signo)
{
int status;
pid_t id = waitpid(-1,&status,WNOHANG);
if (WIFEXITED(status))
{
printf("Removed proc id: %d \n",id);
printf("Child send: %d \n",WEXITSTATUS(status));
}
}
int main(int argc,char *argv[])
{
pid_t pid;
struct sigaction act;
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);//信号处理函数执行时期的信号屏蔽字
act.sa_flags = 0;
sigaction(SIGCHLD,&act,0);
pid = fork();
if (pid == 0)
{
puts("Hi! I'm child process.");
sleep(10);
return 12;
}
else
{
printf("Child proc id: %d \n",pid);
pid = fork();
if (pid == 0)//第二个子进程
{
puts("Hi! I'm child process");
sleep(10);
exit(24);
}
else//主进程
{
int i;
printf("Child proc id: %d \n",pid);
for (i=0; i<5; i++)
{
puts("wait...");
sleep(5);
}
}
}
return 0;
}通过多个进程来实现并发(
由父进程来监听连接请求,多个子进程来处理逻辑 ,因为fork后文件描述符也被复制一份到子进程,因为一个端口对应一个套接字,而此时文件描述符多了1份,
让唯一的父进程处理连接请求,那么去掉fork前连接成功的客户端socket fd,
多个子进程只需要负责数据,不需要监听,那么关闭监听的socket fd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82#include <me.h>
#define BUF_SIZE 30
void read_childproc(int);
int main(int argc,char *argv[])
{
int serv_sock,clnt_sock;
struct sockaddr_in serv_adr,clnt_adr;
pid_t pid;
struct sigaction act;
int str_len,state;
socklen_t adr_sz;
char buf[BUF_SIZE];
if (argc != 2)
{
printf("Usage : %s <port> \n",argv[0]);
exit(1);
}
//注册信号处理函数
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
state = sigaction(SIGCHLD,&act,0);
if (state == -1)
error_handle("sigaction error")
serv_sock = socket(AF_INET,SOCK_STREAM,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if (bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
error_handle("bind() error")
if (listen(serv_sock,5) == -1)
error_handle("listen() error")
while(1)
{
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
if (clnt_sock == -1)
continue;
else
puts("new client connected...");
pid = fork();
if (pid == -1)//连接成功,但是fork失败
{
close(clnt_sock);
continue;
}
if (pid == 0)
{
close(serv_sock); //子进程不需要监听相应端口,所以此进程关闭该复制的套接字
while((str_len = read(clnt_sock,buf,BUF_SIZE)) != 0)
write(clnt_sock,buf,str_len);
close(clnt_sock);
puts("client disconnected...");
return 0;
}
else
{
//父进程用不到此套接字(因为已经交给子进程来处理了)
close(clnt_sock);
}
}
close(serv_sock);//父进程结束,服务器端套接字关闭
return 0;
}
void read_childproc(int signo)
{
pid_t pid;
int status;
pid = waitpid(-1,&status,WNOHANG);//不阻塞回收子进程
printf("removed proc id: %d \n",pid);
}分割IO程序,开子进程让2个进程分别In和out
普通回声服务器客户端(写了之后在读:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47#include <me.h>
#define BUF_SIZE 1024
int main(int argc,char *argv[])
{
int sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_adr;
if (argc != 3)
{
printf("Usage : %s <IP> <port>\n",argv[0]);
exit(1);
}
sock = socket(AF_INET,SOCK_STREAM,0);
if (sock == -1)
error_handle("socket() error");
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if (connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
error_handle("connect() error")
else
puts("connected...");
//已经连接上了服务器
while(1)
{
fputs("Input message(Q to quit): ",stdout);
fgets(message,BUF_SIZE,stdin);
if (!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
write(sock,message,strlen(message));
str_len = read(sock,message,BUF_SIZE-1);
message[str_len] = 0;
printf("Message from server: %s",message);
}
close(sock);
return 0;
}
开子进程同时读和写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65#include <me.h>
#define BUF_SIZE 30
void read_routine(int,char*);
void write_routine(int,char*);
int main(int argc,char *argv[])
{
int sock;
pid_t pid;
char buf[BUF_SIZE];
struct sockaddr_in serv_adr;
if (argc != 3)
{
printf("Usage : %s <IP> <port> \n",argv[0]);
exit(1);
}
sock = socket(AF_INET,SOCK_STREAM,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if (connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
error_handle("connect() error");
//IO分割
pid = fork();
if (pid == 0)
{
write_routine(sock,buf);
}
else
{
read_routine(sock,buf);
}
close(sock);
return 0;
}
void read_routine(int sock,char *buf)
{
while(1)
{
int str_len = read(sock,buf,BUF_SIZE);
if (str_len == 0)
return ;
buf[str_len] = 0;
printf("Message from server: %s",buf);
}
}
void write_routine(int sock,char *buf)
{
while(1)
{
fgets(buf,BUF_SIZE,stdin);
if (!strcmp(buf,"q\n") || !strcmp(buf,"Q\n"))
{
shutdown(sock,SHUT_WR);
return ;
}
write(sock,buf,strlen(buf));
}
}
来自<<TCP/IP 网络编程 尹圣雨>>
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!