赞
踩
当父进程产生新的子进程后,父,子进程共享父进程在调用fork之前的所有描述符,一般情况下,接下来父进程只负责
接收客户请求,而子进程只负责处理客户请求。关闭不需要的描述符既可以节省系统资源,又可以防止父,子进程同时对共享描
述符进程操作,产生不可预计的后果。
此外,由于当fork()函数返回后,与监听和已连接描述符相关联的文件表项的访问计数值均加一,当父进程调用close关
闭已连接描述符时,只是将访问计数值减1,而描述符只在访问计数为0时才真正关闭,所以为了正确地关闭链接,当调用fork()函数
后父进程将不需要的已连接描述符(accept函数返回的描述符)关闭,而子进程关闭不需要的监听描述符(socket函数返回的描述符)。
多进程并发服务器实例:
服务器端的程序步骤如下:
- /*
- * =====================================================================================
- *
- * Filename: server.c
- *
- * Description: 多进程并发服务器的server端程序
- *
- * Version: 1.0
- * Created: 2014年07月17日 09时45分30秒
- * Revision: none
- * Compiler: gcc
- * CopyRight: open , free , share
- * Author: yexingkong(zhangbaoqing)
- * Email: abqyexingkong@gmail.com
- * Company: Xi'an University of post and Telecommunications
- *
- * =====================================================================================
- */
-
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
-
-
- #define SERV_PORT 4507 //服务端的端口
- #define LISTENQ 12 //链接请求队列的最大长度
-
-
- void my_err(const char *err_string, int err_line)
- {
- fprintf(stderr,"line: %d",err_line);
- perror(err_string);
- exit(1);
- }
-
-
- int main()
- {
- int sock_fd,conn_fd;
- int optval;
- int ret;
- int name_num;
- pid_t pid;
- socklen_t cli_len;
- struct sockaddr_in cli_addr,serv_addr;
-
- //创建一个TCPT套接字
- sock_fd = socket(AF_INET, SOCK_STREAM, 0);
- {
- if(sock_fd < 0)
- {
- my_err("socket", __LINE__);
- }
- }
-
- //设置该套接字使之可以重新绑定端口
- optval = 1;
- if(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0)
- {
- my_err("setsockopt", __LINE__);
- }
-
-
- //初始化服务端地址结构
- memset(&serv_addr, 0 , sizeof(struct sockaddr_in));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_port = htons(SERV_PORT);
- serv_addr.sin_addr.s_addr = htons(INADDR_ANY);
-
-
- //将套接字绑定到本地端口
- if(bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) < 0)
- {
- my_err("bind", __LINE__);
- }
-
- //将套接字转化为监听套接字
- if(listen(sock_fd, LISTENQ))
- {
- my_err("listen", __LINE__);
- }
-
- cli_len = sizeof(struct sockaddr_in);
- while(1)
- {
- //通过accept接收客户端的链接请求,并返回链接套接字
- conn_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &cli_len);
- if(conn_fd < 0)
- {
- my_err("accept", __LINE__);
- }
-
- printf("accept a new client , ip: %s\n", inet_ntoa(cli_addr.sin_addr));
- //创建一个子进程处理刚刚接收的链接请求
- if((pid = fork()) == 0)
- {
- close(sock_fd); //子进程关闭监听描述符
- //child handle with something
- //...............
- exit(0); //结束子进程
- }else if(pid > 0) //父进程关闭刚刚接收的链接请求,执行accept等待其他链接请求
- {
- close(conn_fd); //父进程关闭已连接描述符
- continue;
- }
- else {
- printf("fork() error\n");
- exit(1);
- }
- }
- close(sock_fd);
- return 0;
- }
- /*
- * =====================================================================================
- *
- * Filename: client.c
- *
- * Description: 多进程并发服务器的client端程序
- *
- * Version: 1.0
- * Created: 2014年07月17日 10时18分16秒
- * Revision: none
- * Compiler: gcc
- * CopyRight: open , free , share
- * Author: yexingkong(zhangbaoqing)
- * Email: abqyexingkong@gmail.com
- * Company: Xi'an University of post and Telecommunications
- *
- * =====================================================================================
- */
- #include<stdio.h>
- #include<string.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include<sys/socket.h>
- #include<string.h>
- #include<errno.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- #include<netdb.h>
-
-
- #define SERV_PORT 4507 //服务器端的端口
-
-
- void my_err(const char * err_string, int err_line)
- {
- fprintf(stderr,"%d",err_line);
- perror(err_string);
- exit(1);
- }
-
- int main(int argc, char **argv)
- {
- int i;
- int ret;
- int sock_fd;
- struct sockaddr_in serv_addr;
- struct hostent *he;
-
-
- //检查参数的个数
- if (argc != 2)
- {
- printf("Usage: %s [serv_address]\n",argv[0]);
- exit(1);
- }
- if ((he=gethostbyname(argv[1])) == NULL)
- {
- printf("gethostbyname() error\n");
- exit(1);
- }
- //创建一个TCP套接字
- sock_fd = socket (AF_INET, SOCK_STREAM, 0);
- if (sock_fd < 0)
- {
- my_err("socket", __LINE__);
- }
-
- //初始化服务器端的端口与地址
- memset(&serv_addr, 0, sizeof (struct sockaddr_in));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_port = htons(SERV_PORT);
- serv_addr.sin_addr = *((struct in_addr *)he->h_addr);
-
-
-
- //向服务器端发送链接请求
- if (connect(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) < 0)
- {
- my_err("connect", __LINE__);
- }
- //函数调用
- //................
-
- close(sock_fd);
- return 0;
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。