1.socket 函数创建套接字 lfd
2.bind 绑定地址结构
3.listen 设置监听上限
4.循环监听客户端连接请求
5.子进程关闭lfd(用于监听客户端连接文件描述符)
完成指定任务
6.父进程关闭cfd(关闭与客户端进行数据通信的文件描述符)
注册信号捕捉函数,回收子进程
使用多进程并发服务器时要考虑以下几点:
1.父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
2.系统内创建进程个数(与内存大小相关)
3.进程创建过多是否降低整体服务性能(进程调度)
注:如果不进行信号捕捉 子进程回收,就会产生僵尸进程
代码实现(实现客户端小写转大写功能)
1.#include <stdio.h>
2.#include <ctype.h>
3.#include <stdlib.h>
4.#include <sys/wait.h>
5.#include <string.h>
6.#include <strings.h>
7.#include <unistd.h>
8.#include <errno.h>
9.#include <signal.h>
10.#include <sys/socket.h>
11.#include <arpa/inet.h>
12.#include <pthread.h>
13.
14.#include "wrap.h"
15.
16.#define SRV_PORT 9999
17. void catch_child(int signum)
19.{
20. while ((waitpid(0, NULL, WNOHANG)) > 0);
21. return ;
22.}
18.int main(int argc, char *argv[])
19.{
20. int lfd, cfd;
21. pid_t pid;
22. struct sockaddr_in srv_addr, clt_addr;
23. socklen_t clt_addr_len;
24. char buf[BUFSIZ];
25. int ret, i;
26.
27. //memset(&srv_addr, 0, sizeof(srv_addr)); // 将地址结构清零
28. bzero(&srv_addr, sizeof(srv_addr)); //地址结构清零
29.
30. srv_addr.sin_family = AF_INET; //初始化
31. srv_addr.sin_port = htons(SRV_PORT); //端口号
32. srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //ip地址
33.
34. lfd = Socket(AF_INET, SOCK_STREAM, 0); //创建套接字文件描述符 用来监听客户端的连接请求
35.
36. Bind(lfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); //绑定地址
37.
38. Listen(lfd, 128); //设置监听上限
39.
40. clt_addr_len = sizeof(clt_addr);
41.
42. while (1) {
43.
44. cfd = Accept(lfd, (struct sockaddr *)&clt_addr, &clt_addr_len); //监听到客户端连接请求,返回成功与客户端成功建立连接的文件描述符
45.
46. pid = fork(); //子进程创建
47. if (pid < 0) {
48. perr_exit("fork error");
49. } else if (pid == 0) {
50. close(lfd);
51. break;
52. } else {
59. struct sigaction act;//注册信号捕捉函数,回收子进程
60.
61. act.sa_handler = catch_child;
62. sigemptyset(&act.sa_mask);
63. act.sa_flags = 0;
64.
65. ret = sigaction(SIGCHLD, &act, NULL);
66. if (ret != 0) {
67. perr_exit("sigaction error");
68. }
69. close(cfd);
70. continue;
71. }
72. }
73.
57.
58. if (pid == 0) {
59. for (;;) {
60. ret = Read(cfd, buf, sizeof(buf));
61. if (ret == 0) {
62. close(cfd);
63. exit(1);
64. }
65.
66. for (i = 0; i < ret; i++)
67. buf[i] = toupper(buf[i]);
68.
69. write(cfd, buf, ret); //写回给用于与客户端通信的文件描述符
70. write(STDOUT_FILENO, buf, ret);//写至屏幕
71. }
72. } x
73.
74. return 0;
75.}