伺服器端預先建立子程序(work)同時監聽服務埠和驚群現象
背景
原文連結: http://blog.csdn.net/ordeder/article/details/21721141
1.程序A在n埠上監聽,即呼叫listen(listenfd,backlog);
2.之後A呼叫fork產生子程序B,此時B拷貝了A的listenfd,該描述符使用的是相同的“檔案表項”(具體參考 http://blog.csdn.net/ordeder/article/details/21716639)
3.那麼A程序和B程序將共享一個socket,具體圖解如下:
驚群現象
在該模型下(多個子程序同時共享監聽套接字)即可實現伺服器併發處理客戶端的連線。這裡要注意的是,計算機三次握手建立連線是不需要服務程序引數的,而服務程序僅僅要做的事呼叫accept將已建立的連線構建對應的連線套接字connfd(可參考 http://blog.csdn.net/ordeder/article/details/21551567)。多個服務程序同時阻塞在accept等待監聽套接字已建立連線的資訊,那麼當核心在該監聽套接字上建立一個連線,那麼將同時喚起這些處於accept阻塞的服務程序,從而導致“驚群現象”的產生,喚起多餘的程序間影響伺服器的效能(僅有一個服務程序accept成功,其他程序被喚起後沒搶到“連線”而再次進入休眠)。
例項分析
服務程序:三個服務程序同時監聽一個埠,程式碼如下:#include<stdio.h> #include<unistd.h> #include<sys/types.h> /* basic system data types */ #include<sys/socket.h> /* basic socket definitions */ #include<netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include<arpa/inet.h> /* inet(3) functions */ #include<sys/epoll.h> /* epoll function */ #include<fcntl.h> #include<stdlib.h> #include<errno.h> #include<stdio.h> #include<string.h> #include<sys/select.h> #define WORKERSIZE 3 void waitall() { pid_t cpid; while(1) { cpid = wait(NULL); if(cpid==-1){ perror("end of wait"); break; } printf("worker pid#%d exit...\n",cpid); } } void worker_hander(int listenfd) { fd_set rset; int cnt = 100,connfd,rc; struct timeval tv; tv.tv_sec = 0; tv.tv_usec=0; printf("worker pid#%d is waiting for connection...\n",getpid()); while(1) { FD_ZERO(&rset); FD_SET(listenfd,&rset); //rc = select(listenfd+1,&rset,NULL,NULL,&tv);//設定為非阻塞狀態 rc = select(listenfd+1,&rset,NULL,NULL,NULL);//設定為阻塞 if(rc == -1) perror("select"); else if(rc>0 && FD_ISSET(listenfd,&rset)) { //sleep(1);//第四種,讓三個程序都有足夠的時間資源喚起(防止可能出現某個程序已近開始進行accept結束了,另一個程序還未被喚起(排程的問題)) printf("worker pid#%d 's listenfd is readable\n",getpid(),rc); connfd = accept(listenfd,NULL,0); if(connfd == -1) { perror("accept error"); continue; } printf("worker pid#%d create a new connection...\n",getpid()); sleep(1); close(connfd); } } } int main(int argc,char*argv[]) { int listenfd,connfd; struct sockaddr_in cliaddr,servaddr; int queuelen=5,i,flag; pid_t cpid[WORKERSIZE]; listenfd = socket(AF_INET,SOCK_STREAM,0); //此處設定listenfd的為阻塞 /*flag = fcntl(listenfd,F_GETFL,0); fcntl(listenfd,F_SETFL,flag|O_NONBLOCK);*/ bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET,"172.20.52.140",&servaddr.sin_addr); //servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(2989); bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); listen(listenfd,queuelen); for(i=0;i<WORKERSIZE;i++) { cpid[i]=fork(); if(cpid[i] == -1){ perror("fork error"); waitall(); exit(0); } if(cpid[i]==0){ worker_hander(listenfd); exit(0); } } waitall(); return 0; }
不同設定的結果輸出:
一個客戶端發起連結,而服務端有三個服務程序在監聽同一埠,從而核心會喚起所有處於監聽該埠的服務程序,從而導致驚群現象的發生。服務端設定不通的阻塞情況,可得如下不同的結果:
一個客戶端發起連結,而服務端有三個服務程序在監聽同一埠。服務端設定不通的阻塞情況,可得如下不同的結果。 1.select設定為阻塞,listenfd設定為阻塞或非阻塞,結果如下: worker pid#25583 is waiting for connection... worker pid#25584 is waiting for connection... worker pid#25585 is waiting for connection... worker pid#25585 's listenfd is readable worker pid#25585 create a new connection... 分析:三個服務程序被喚起,25585第一個排程所以執行accept,所以此時連線被取走,其他兩個程序之後開始被排程,而此時連線數目為0,又進入隨眠... 2.select設定為非阻塞,listenfd設定為阻塞,結果如下: worker pid#25743 is waiting for connection... worker pid#25744 is waiting for connection... worker pid#25745 is waiting for connection... worker pid#25745 's listenfd is readable worker pid#25744 's listenfd is readable worker pid#25743 's listenfd is readable worker pid#25745 create a new connection... 分析:三個服務程序都select都成功返回可讀的套接字,從而各個程序都喚起處於阻塞的accept,但是隻有一個程序建立連結,其餘兩個程序沒有獲取到連結而又進入睡眠... 3.select設定為非阻塞,listenfd設定為為非阻塞,結果如下: worker pid#25240 is waiting for connection... worker pid#25241 is waiting for connection... worker pid#25242 is waiting for connection... worker pid#25242 's listenfd is readable worker pid#25240 's listenfd is readable worker pid#25241 's listenfd is readable worker pid#25242 create a new connection... accept error: Resource temporarily unavailable accept error: Resource temporarily unavailable 分析:三個服務程序都進入accept,但是隻有一個程序獲取到連結,其他兩個程序沒有獲取到連結而出錯 4.在select設定為阻塞,select和accept之間新增sleep(1),accept的套接字為非阻塞,結果如下: worker pid#30689 is waiting for connection... worker pid#30690 is waiting for connection... worker pid#30691 is waiting for connection... worker pid#30691 's listenfd is readable worker pid#30691 create a new connection... worker pid#30690 's listenfd is readable worker pid#30689 's listenfd is readable accept error: Resource temporarily unavailable accept error: Resource temporarily unavailable 分析:三個程序被喚起後,由於有sleep(1),三個程序都被排程了,所以select都能查詢到連線,故而從select返回,但是在accept處,只有一個程序得到了連線
相關推薦
伺服器端預先建立子程序(work)同時監聽服務埠和驚群現象
背景 原文連結: http://blog.csdn.net/ordeder/article/details/21721141 1.程序A在n埠上監聽,即呼叫listen(listenfd,backlog); 2.之後A呼叫fork產生子程序B,此時B拷貝了A的listenf
Nginx監聽相同埠和IP通過域名分發到不同的應用伺服器
1、Nginx配置檔案如下: #user nobody; worker_processes 3; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log inf
多程序伺服器中,epoll的建立應該在建立子程序之後
#include <iostream>#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcn
2.fork建立子程序:vfork
getpid/getppid getpid 獲取當前程序id getppid 獲取當前程序的父程序的id fork pid_t fork() 1.為什麼fork有兩個返回值? 因為這兩個返回值是由不同的程序return出來的,而不是由一個fork函式返回兩個數。 (fork
exec族函式詳解及迴圈建立子程序
前言:之前也知道exec族函式,但沒有完全掌握,昨天又重新學習了一遍,基本完全掌握了,還有一些父子程序和迴圈建立子程序的問題,還要介紹一下環境變數,今天分享一下。 一、環境變數 先介紹下環境的概念和特性,再舉例子吧。 環境變數,是指在作業系統中用來指定作業系統執行環境的一些引數。通常具備
linux c建立子程序
*前言 瞭解fork()函式 c程式碼樣例: #include <stdio.h> #include <unistd.h> int main(int arg,cha
WebWork(在主執行緒建立子程序)
WebWork淺談 前言: 都知道JS是單執行緒語言,最讓人頭疼的莫過於在網路正常的情況下經常出現頁面的假死, 以及在進行大量的for迴圈計算時會導致執行緒阻塞,由於要進行大量的計算JS後面的執行會被阻隔在此處,使得效能較差,程式碼維護性差等一系列的問題發生。 本人也看了很多關於web
python建立子程序的幾種常用方式(fork, Process,程序池)
linux下使用fork()建立子程序 Linux 作業系統提供了一個 fork() 函式用來建立子程序,這個函式很特殊,呼叫一次,返回兩次,因為作業系統是將當前的程序(父程序)複製了一份(子程序),然後分別在父程序和子程序內返回。子程序永遠返回0,而父程
【作業系統】如何建立子程序?
實驗環境:Linux Fedora13 需要用到的命令: top 動態檢視程序執行情況,包括殭屍程序的數量 ps 靜態檢視程序執行清情況 pstree 檢視程序樹
zz: Python subprocess建立子程序(Windows下開啟新的CMD視窗)
Python提供多個建立子程序的模組,我比較習慣使用subprocess模組,因為在Python手冊中有這樣一段話: This module intends to replace several other, older modules and functions, such as: os.syst
python 建立子程序subprocess以及注意的問題(死鎖)
原文 : http://blog.csdn.net/jgood/article/details/4498166 最近,我們老大要我寫一個守護者程式,對伺服器程序進行守護。如果伺服器不幸掛掉了,守護者能即時的重啟應用程式。上網Google了一下,發現Python有很幾個模
android應用建立子程序的方法探究
android應用建立子程序的方法探究 1:前言 android應用開發,當前大多數軟體還是停留在java層進行開發,然而android真正可玩的地方,偏偏是本地語言c與c++,藉助JNI這個橋樑,可以使得java呼叫到本地函式,本文則從建立子程序,來進行探究andro
node.js 建立子程序 I
建立father.js檔案 /**************** * child_process模組提供產生子程序的方法 * 當有CPU密集型的任務,為了不阻塞事件迴圈, * 或者是執行一個外部命令可以,產生一個子程序, * 讓子程序執行這個任務
關於fork建立子程序的一些疑惑
Python中執行 os.fork() 會建立 一個子程序,程序號為0 import os import time ret = os.fork() if ret == 0: while T
建立子程序的4種方法及注意事項
/***********************************fork & vfork*********************************/1 1. fork:子程序拷貝父程序的資料段 vfork: 子程序與父程序共享資料段 2.
父程序利用fork()函式建立子程序並且利用shared_memory進行通訊的例項
#include<stdio.h> #include<unistd.h> #include<sys/shm.h> #include<sys/stat.h>
pycharm 執行django伺服器端 以及建立app方法
我們先來了解一下一些必要的概念。Django 裡什麼東西叫 APP 呢? 我們已經建立了 project , 那麼 project 和 APP 之間到底有什麼不同呢?它們的區別就是一個是配置另一個是程式碼: 一個project包含很多個Django app以及對它們的配置。 技術上,project的
C#實現Socket通訊(同時監聽多客戶端)
//建立socket物件 //第一個引數:設定網路定址的協議、第二引數設定資料傳輸的方式、第三個引數設定通訊協議 Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketT
如果有2個ApacheMQ的客戶端同時監聽一個Queue會怎麼樣
我們知道Topic,是傳送一個訊息,多個監聽的客戶端都可以消費到訊息內容。而傳送一個訊息到Queue,只能一個監聽的客戶端可以消費。那麼,如果我有2個客戶端都去監聽同一個Queue,可以嗎?結果會怎麼樣?實際測試結果是逐一交叉監聽消費了訊息。這樣的情況,可以利用微服務➕MQ簡
客戶端連線伺服器,配置出錯“連線超時”或者“無監聽程式”解決方法
這兩天在進行Oracle的客戶端配置,伺服器OS為Windows XP 64,客戶端OS為Win7 64,oracle版本為11.2。 先說下伺服器端自己的疑惑,由於自己是新手,很多都不明白是怎麼個回事。 1)關於服務端監聽程式配置時候的SID設定 我在建立資料庫的時候,設定