fork()理解及简单并发服务器应用

首先,我觉得有两个容易混淆的地方:

1,fork()函数并不是创建新进程,而是复制 当前进程。

2,fork()函数被共享执行,有2种返回值。

========================分割线===================================

对于第一点:

父进程fork()后,子进程完全与父进程相等,包括数据段与代码段。可以理解成,数据段有2份相同 的,而代码段只有一份供他们共享。关于如何区分子进程与父进程在第二点讲述。

特别强调“复制”这个概念还有一个原因是因为fork()并不是用于创建新进程的,一般Linux下有两种创建新进程的方法:system()与exec()。

system()的底层是exec(),它会重新启动一个shell来执行新进程;exec()是替换 当前进程为新进程。

如果用exec()创建新进程,那么必须配合fork()先复制一份进程,再调用exec()将复制品替换掉。、

补充:Linux下的进程是很廉价的,多进程常常比多线程更加方便,关于他们的异同,最主要的就是在多线程中,数据段是共享的,而多进程中,正如上面所述,独立性很高。

对于第二点:

由于子进程与父进程代码段是共享的,所以这点与多线程相同,创建子进程后,马上执行相同的函数,自然子进程也会执行fork()函数,但是并不创建新进程且返回值与父进程不同,这就是区分子进程与父进程的办法。

========================分割线===================================

一个例子:简单多进程并发服务器框架:

pid_t pid;
int listenfd, connfd;

listenfd = Socket( ... );

/* fill in sockaddr_in{} with server's well-known port */
Bind(listenfd, ... );
Listen(listenfd, LISTENQ);

for ( ; ; ) {
connfd = Accept (listenfd, ... ); /* probably blocks */

if ( (pid = fork()) == 0) {
#2 Close(listenfd); /* child closes listening socket */
doit(connfd); /* process the request */
Close(connfd); /* done with this client */
exit(0); /* child terminates */
}

#1 Close(connfd); /* parent closes connected socket */
}

以上只是一个框架,很多代码都简化了,可以看出fork()的常规使用方法:if ( (pid = fork()) == 0) 的代码块为子进程才能执行的区域。另外特别需要注意的是,listenfd与connfd被close两次,这是必须的,因为系统对套接字的使用是计数的,当计数为0时才真正关闭。又因为父进程只关心listenfd,所以在父进程区域内,必须关闭connfd(#1处);子进程只关心connfd,所以在子进程区域内,必须关闭listenfd(#2处)。

另外补充一点,socket的close()采用计数,当计数为0才发送FIN,但是shutdown()函数可以不管计数,直接发送FIN。显然这里不能用shutdown()。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用fork()函数可以实现简单并发访问服务器,实现方式如下: 1. 服务器在一个循环中等待客户端请求。 2. 当有一个请求到来时,使用fork()函数创建一个新的进程来处理该请求。 3. 子进程处理该请求,父进程继续等待其他请求。 4. 子进程处理完请求后结束进程,释放资源。 下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8080 #define MAX_CONN 10 void handle_request(int client_socket) { char buffer[1024] = {0}; read(client_socket, buffer, 1024); printf("Received message: %s\n", buffer); char *response = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body><h1>Hello, World!</h1></body></html>"; write(client_socket, response, strlen(response)); close(client_socket); } int main() { int server_socket, client_socket; struct sockaddr_in server_address, client_address; int addrlen = sizeof(server_address); // 创建套接字 server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { perror("socket failed"); exit(EXIT_FAILURE); } // 绑定地址和端口 server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = INADDR_ANY; server_address.sin_port = htons(PORT); if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听端口 if (listen(server_socket, MAX_CONN) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } while (1) { // 等待客户端连接 client_socket = accept(server_socket, (struct sockaddr *)&client_address, (socklen_t*)&addrlen); if (client_socket < 0) { perror("accept failed"); exit(EXIT_FAILURE); } // 创建子进程处理请求 pid_t pid = fork(); if (pid == 0) { // 子进程处理请求 handle_request(client_socket); exit(EXIT_SUCCESS); } else if (pid < 0) { perror("fork failed"); exit(EXIT_FAILURE); } // 父进程继续监听 } return 0; } ``` 在该示例中,我们创建了一个简单HTTP服务器,它可以监听来自客户端的请求并返回“Hello, World!”的响应。使用fork()函数可以实现多个客户端同时访问服务器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值