日本免费精品_最新日韩一区_亚洲视频一区在线_a在线视频观看_天天射夜夜骑_粉嫩av一区二区三区_欧美中日韩免费视频_综合图区欧美_国内精品美女在线观看_午夜精品久久久久久久男人的天堂

首頁 > 學院 > 開發設計 > 正文

多進程、共享內存的網絡聊天室

2019-11-10 20:07:59
字體:
來源:轉載
供稿:網友

好久沒寫網絡聊天室了,去年暑假可以說寫了一暑假,最近復習這些,又因為我一直偏向于多線程,就用多進程復習一下。

下面給出昨天寫的基于多進程、共享內存的網絡聊天室代碼。每個進程負責一個連接,多個進程之間僅共享讀,不共享寫,因此無需信號量來同步。分配的一段內存中,以數組的方式,分配給每個client一段buffer,每個clilent對應的buffer的索引就是connfd。當一個子進程收到客戶端數據后,通過每客戶端管道發送自己的pid給主進程,主進程通知除了該子進程的其他進程將該片內存寫好的數據轉發給其他客戶端(sub_PRoess[pid]=connd)。

代碼如下:

#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <assert.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <sys/epoll.h>#include <signal.h>#include <sys/wait.h>#include <sys/mman.h>#include <sys/stat.h>#include <fcntl.h>const int USER_LIMIT = 3;const int BUFFER_SIZE = 1024;const int FD_LIMIT = 65545;const int MAX_EVENT_NUMBER = 1024;const int PROCESS_LIMIT = 65536;//封裝每個客戶端連接數據struct client_data { sockaddr_in address; int connfd; pid_t pid; //負責該客戶端子進程的pid int pipefd[2]; //每個子進程pipe};static const char* shm_name = "/my_shm"; //共享內存的名字int sig_pipefd[2]; //用來統一事件源int epollfd;int listenfd;int shmfd; char* share_mem = NULL; //共享內存起始地址//客戶端連接數組,進程用客戶連接的編號來索引這個數組,即可取得相關的客戶連接數據client_data* users = NULL; //子進程和客戶連接的關系映射表,用子進程的pid來索引這個數組,即可取得該進程處理的客戶連接的編號int* sub_process = 0;int user_count = 0; //客戶連接下標,這個名字有點誤導,總之user_count>=USER_LIMIT即連接過多bool stop_child = false; //停止一個子進程,這個是全部變量,每個子進程都有自己拷貝的一份int setnonblocking(int fd){ int old_option = fcntl(fd, F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd, F_SETFL, new_option); return old_option;}void addfd(int epfd, int fd){ epoll_event event; event.data.fd = fd; event.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); setnonblocking(fd);}void sig_handler(int sig){ int save_errno = errno; int msg = sig; send(sig_pipefd[1], (char*)&msg, 1, 0); errno = save_errno;}void addsig(int sig, void(*handler)(int), bool restart = true){ struct sigaction sa; memset(&sa, '/0', sizeof(sa)); sa.sa_handler = handler; if(restart) sa.sa_flags |= SA_RESTART; sigfillset(&sa.sa_mask); assert(sigaction(sig, &sa, NULL) != -1);}void del_resource(){ close(sig_pipefd[0]); close(sig_pipefd[1]); close(listenfd); close(epollfd); shm_unlink(shm_name);}//子進程的信號處理函數,停止一個子進程void child_term_handler(int sig){ stop_child = true;}//子進程運行的函數,參數inx指出該子進程處理的客戶連接的編號,users是保存所有客戶連接數據的數組,參數share_mem指出共享內存的起始地址int run_child(int idx, client_data* users, char* share_mem){ epoll_event events[MAX_EVENT_NUMBER]; //每個子進程使用I/O服用同時監聽客戶連接socket和與父進程通信的pipe描述符 int child_epollfd = epoll_create(5); assert(child_epollfd != -1); int connfd = users[idx].connfd; addfd(child_epollfd, connfd); int pipefd = users[idx].pipefd[1]; addfd(child_epollfd, pipefd); int ret; //子進程需要設置自己的信號處理函數,因為fork會繼承父進程信號處理函數 addsig(SIGTERM, child_term_handler, false); while(!stop_child){ int number = epoll_wait(child_epollfd, events, MAX_EVENT_NUMBER, -1); if(number < 0 && errno != EINTR){ printf("epoll failure/n"); break; } for(int i=0; i<number; ++i){ int sockfd = events[i].data.fd; //本子進程負責的客戶鏈接有數據到達 if(sockfd == connfd && (events[i].events & EPOLLIN)){ //清零該客戶對應的緩沖區 memset(share_mem+idx*BUFFER_SIZE, '/0', BUFFER_SIZE); //將客戶數據讀取到對應的讀緩存中,該讀緩存是共享內存的一段,它開始于idx*BUFFER_SIZE處,長度為BUFFER_SIZE字節,因此每個客戶連接是共享的 ret = recv(connfd, share_mem+idx*BUFFER_SIZE, BUFFER_SIZE-1, 0); //留一個字節為'/0'間隔 if(ret < 0){ if(errno != EAGAIN) stop_child = true; } else if(ret == 0) stop_child = true; else //成功讀取客戶數據后就通知主進程,讓主進程吩咐其他進程轉發 send(pipefd, (char*)&idx, sizeof(idx), 0); } //主進程通過管道通知本進程需要轉發第client個客戶端的數據到本進程負責的客戶 else if(sockfd == pipefd && (events[i].events & EPOLLIN)){ int client = 0; //接受主進程發來的數據,即客戶的編號,用來索引buffer ret = recv(sockfd, (char *)&client, sizeof(client), 0); if(ret < 0){ if(errno != EAGAIN) stop_child = true; } else if(ret == 0) stop_child = true; else //轉發給自己的客戶 send(connfd, share_mem+client*BUFFER_SIZE, BUFFER_SIZE, 0); } else continue; } } close(connfd); close(pipefd); close(child_epollfd); return 0;}int main(int argc, char** argv){ if( argc <= 2 ) { printf( "usage: %s ip_address port_number/n", basename( argv[0] ) ); return 1; } const char* ip = argv[1]; int port = atoi( argv[2] ); int ret = 0; struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET, ip, &address.sin_addr); address.sin_port = htons(port); int listenfd = socket(PF_INET, SOCK_STREAM, 0); assert(listenfd >= 0); int on = 1; ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); assert(ret != -1); ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address)); assert(ret != -1); ret = listen(listenfd, 5); assert(ret != -1);///////////////////////////////////////////////////////////// user_count = 0; users = new client_data[USER_LIMIT]; sub_process = new int [PROCESS_LIMIT]; for(int i=0; i<PROCESS_LIMIT; ++i) sub_process[i] = -1;//////////////////////////////////////////////////////////// epoll_event events[MAX_EVENT_NUMBER]; epollfd = epoll_create(5); assert(epollfd != -1); addfd(epollfd, listenfd); //socketpair是全雙工的,所以父子進程通信無需向pipe一樣需要兩個pipe[2] //fork完畢socketpair可以雙向通信 ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sig_pipefd); assert(ret != -1); setnonblocking( sig_pipefd[1] ); addfd(epollfd, sig_pipefd[0]); // add all the interesting signals here addsig(SIGCHLD, sig_handler); addsig(SIGTERM, sig_handler); addsig(SIGINT, sig_handler); addsig(SIGPIPE, SIG_IGN); bool stop_server = false; bool terminate = false;/////////////////////////////////////////////////////////////// //創建共享內存,作為所有客戶連接的讀緩存 shmfd = shm_open(shm_name, O_CREAT | O_RDWR, 0666); assert(shmfd != -1); //清空且resize文件大小為USER_LIMIT*BUFFER_SIZE ret = ftruncate(shmfd, USER_LIMIT*BUFFER_SIZE); assert(ret != -1); //通過上面生成的一定大小的文件來使用mmap映射共享內存 //這是共享內存的一種方式,另外一種使用SystemV的shmat share_mem = (char *)mmap(NULL, USER_LIMIT*BUFFER_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, shmfd, 0); assert(share_mem != MAP_FAILED); close(shmfd); //close shmfd is ok////////////////////////////////////////////////////////////// while(!stop_server){ int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1); if(number < 0 && errno != EINTR){ printf("epoll failure/n"); break; } for(int i=0; i<number; ++i){ int sockfd = events[i].data.fd; if(sockfd == listenfd){ struct sockaddr_in client_address; socklen_t len = sizeof(client_address); int connfd = accept(listenfd, (struct sockaddr*)&client_address, &len); if(connfd < 0){ printf("errno is: %d/n", errno); continue; } if(user_count >= USER_LIMIT){ //limit const char* info = "too many users/n"; printf("%s", info); send(connfd, info, strlen(info), 0); close(connfd); continue; } //保存第user_count個客戶連接的數據 users[user_count].address = client_address; users[user_count].connfd = connfd; //在子進程和父進程間建立管道,以傳遞必要的數據 ret = socketpair(PF_UNIX, SOCK_STREAM, 0, users[user_count].pipefd); assert(ret != -1); pid_t pid = fork(); if(pid < 0){ close(connfd); continue; //!!!!!!! } else if(pid == 0){ //in child close(epollfd); close(listenfd); close(users[user_count].pipefd[0]); //子進程關掉一端,子進程給父進程發數據使用pipefd[1] close(sig_pipefd[0]); close(sig_pipefd[1]); run_child(user_count, users, share_mem); munmap((void*)share_mem, USER_LIMIT*BUFFER_SIZE); exit(0); } else{ close(connfd); close(users[user_count].pipefd[1]); //同理 addfd(epollfd, users[user_count].pipefd[0]); //記錄新的客戶連接在數組users中的索引值,建立進程pid和索引值的映射關系 users[user_count].pid = pid; sub_process[pid] = user_count; user_count++; } } //handle signal else if(sockfd == sig_pipefd[0] && (events[i].events & EPOLLIN)){ int sig; char signals[1024]; ret = recv(sig_pipefd[0], signals, sizeof(signals), 0); if(ret == -1) continue; else if(ret == 0) continue; else{ for(int i=0; i<ret; ++i){ switch(signals[i]){ case SIGCHLD: //子進程退出,表示有客戶端關閉了連接 { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0){ //用子進程的pid取得被關閉客戶連接的編號 int del_user = sub_process[pid]; sub_process[pid] = -1; if(del_user < 0 || del_user > USER_LIMIT) continue; //清除數據 epoll_ctl(epollfd, EPOLL_CTL_DEL, users[del_user].pipefd[0], 0); close(users[del_user].pipefd[0]); //用最后一個user替換該位置 users[del_user] = users[--user_count]; sub_process[users[del_user].pid] = del_user; //修正sub_process對應的值,也就是修正最后一個客戶端pid對應的客戶編號 } if(terminate && user_count == 0) stop_server = true; break; } case SIGTERM: case SIGINT: //結束服務器程序 { printf("kill all the child new/n"); if(user_count == 0){ stop_server = true; break; } for(int i=0; i<user_count; ++i){ int pid = users[i].pid; kill(pid, SIGTERM); //kill每個子進程 } terminate = true; break; } default: break; } } } } //某個子進程收到數據,向父進程通知 else if(events[i].events & EPOLLIN){ int child = 0; //讀取管道數據,收到的數據時child變量記錄了哪個客戶連接有數據到達 ret =recv(sockfd, (char*)&child, sizeof(child), 0); if(ret == -1) continue; else if(ret == 0) continue; else{ //向除負責第child個客戶的子進程之外的子進程發送消息,通知他們有客戶數據要寫 for(int j=0; j<user_count; ++j){ if(users[j].pipefd[0] != sockfd){ printf("send data to child accross pipe/n"); send(users[j].pipefd[0], (char*)&child, sizeof(child), 0); } } } } } } del_resource(); return 0;}
上一篇:log4j日志記錄級別

下一篇:四種修飾符

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
在线视频你懂得一区| 日韩欧美色综合| 午夜国产在线| 日韩免费高清一区二区| 亚洲一区在线观看网站| 欧美日韩在线国产| 久久69成人| 亚洲视频 中文字幕| 色综合久久六月婷婷中文字幕| 1024国产在线| 亚洲经典中文字幕| 一区三区二区视频| 国产在线不卡一区| 最近免费中文字幕在线第一页| aaa欧美日韩| 在线观看精品国产| 久久69成人| 阿v免费在线观看| wwwwww在线观看| 欧美国产日韩在线播放| 中文精品电影| 欧美日韩在线播放一区| 欧美国产一级片| 欧美1234区| 亚洲大片精品永久免费| 国产高清视频一区二区| 欧美日韩在线看| 亚洲区中文字幕| 久久综合久久综合九色| 国产 日韩 欧美 综合| 日韩在线观看一区| 欧美婷婷精品激情| 久久久久久自在自线| 久久久99精品久久| 国产成人综合av| 久久久99免费| 一区二区三区精品在线| 最新中文字幕在线| 日韩三级视频在线| 国产网站av| 婷婷中文字幕在线观看| www.日韩免费| 国产黄色小视频| 国产区日韩欧美| 欧美日韩亚洲国产综合| 欧美日韩精品免费| 日韩 欧美 中文| 交视频在线观看国产| 欧美三级在线播放| 中文字幕第一页在线播放| 日韩国产成人| 亚洲乱码中文字幕综合| 国产超级va在线视频| 亚洲视频日韩| 精品久久人人做人人爽| 日韩精品首页| 亚洲狠狠婷婷综合久久久久图片| 国内国产区免费视频| 日韩欧美国产免费| 欧洲精品久久久| 日韩中文字幕在线观看视频| 亚洲欧美日本另类| 日韩精品视频在线播放| 日韩精品视频免费| 欧美高清一级片在线| 精品视频1区2区3区| 国产视频2区| 久久99蜜桃精品| 国产在线观看精品| 欧美日韩性视频一区二区三区| 国产999精品在线观看| 中文网丁香综合网| 欧美99久久| 中文在线第一页| lutube成人福利在线观看| 中文不卡在线| 视频一区二区中文字幕| 欧美日韩乱国产| 日韩视频一区在线观看| 日韩在线观看精品| 国产一级片网站| 国产一级片在线播放| 在线日韩中文字幕| 亚洲综合在线不卡| 日韩欧美色综合网站| 亚洲成在线观看| 欧美日韩精品在线视频| 亚洲免费婷婷| 欧美日韩国产一区| www.中文字幕在线| 日韩中文首页| 欧美日韩精品不卡| 亚洲成av人综合在线观看| 日韩精品视频在线观看免费| 国产在线不卡一区| 91精品婷婷国产综合久久| 欧美日韩在线三级| 久久精品一二三| 欧美在线视频第一页| 91精品国产综合久久久久| 中文字幕国产在线| 92久久精品| 日韩欧美中文字幕一区| 中文字幕日韩欧美在线视频| 日韩在线小视频| 国产欧美日韩在线| 久久综合久久综合九色| 中文字幕国产亚洲| 精品福利一区二区三区| 日韩欧美中文字幕在线观看| 91精品国产经典在线观看| 九七久久人人| 一区二区三区免费看视频| 欧美大片在线观看一区| 日韩精品在线中文字幕| 99综合精品久久| 天天综合天天做| 大香一本蕉伊线亚洲网| 日韩欧美成人一区二区三区| 人人做人人澡人人爽欧美| 日韩欧美一卡二卡| 中文字幕日韩欧美在线| 国产激情三区| 日韩在线三区| 99精品人妻国产毛片| 亚洲综合在线小说| 日韩欧美99| 中文字幕在线视频网| 亚洲成av人片一区二区密柚| 欧美三级中文字幕| 欧美三级日韩三级| 精品国内自产拍在线视频| 中文字幕无线码一区| 国产成人精品综合久久久| 午夜av一区二区| 色一区在线观看| 日韩在线中文字幕| 亚洲开心激情| va中文字幕| 91精品国产自产| 日韩欧美999| 精品人妻一区二区免费视频| 亚洲高清视频一区| 国产激情久久久| 日韩欧美亚洲国产一区| 国产乱一区二区| 日韩欧美亚洲视频| 高清日韩中文字幕| 欧美日韩国产免费观看| 国产卡1卡2卡三卡在线| 精品日韩视频在线观看| 日韩在线一区二区视频| 国产小视频免费在线网址| 欧美三级视频在线| 久久激情一区| 欧美日韩在线看| 欧美高清一级片在线| 国产欧美日韩视频在线| 国产婷婷在线观看| 日韩精品一区二区三区视频播放| 国产日韩中文字幕| 极品久久久久久| 91精品无人成人www| 一区二区在线高清视频| 欧美日韩三级一区| 日韩免费精品视频| 久久激情中文| 日本不卡视频一区| 亚洲福利视频专区| 国产日产一区二区三区| 亚洲永久字幕| 国产在线黄色片| 一级片免费网站| 在线视频你懂得一区| 黄色国产网站在线观看| 午夜国产福利一区二区| 天堂精品高清1区2区3区| 天天综合天天做| 国产乱国产乱300精品| 在线视频不卡一区二区| 偷窥国产亚洲免费视频| 中文字幕欧美亚洲| 日韩不卡中文字幕| 首页国产欧美久久| 国产91大片| 欧美日韩成人一区| 麻豆精品视频入口| 亚洲视频在线观看日本a | 中文字幕亚洲一区二区av在线| 国产日韩中文字幕| 日韩久久99| 国产免费一级| 日韩欧美国产综合| 久久久精品网| 91麻豆免费视频网站| 国产亚洲短视频| 欧美三级中文字幕在线观看| 国产欧美久久久精品免费| 欧美日韩日本视频| 久久婷婷亚洲| 日韩a一区二区| 日本不卡视频一区| 亚洲免费中文字幕| 狠狠色噜噜狠狠狠狠97| 国产一区深夜福利| 在线视频不卡国产V| 影音先锋一区二区资源站| 激情综合色综合久久| 欧美日韩国产高清视频| 欧美三级在线看| 亚洲免费视频一区| 国产欧美日韩在线| av一区在线| 日韩精品在线观看网站| 国产 欧美 在线| 91精品在线免费| 精品国产欧美成人夜夜嗨| 日韩欧美亚洲国产一区| 欧美日韩精品在线视频| 高清国产一区| 中文字幕欧美日韩在线| 国产成人日日夜夜| 国产欧美日产一区| 欧美 日韩 中文字幕| 欧美一级二级三级区| 一区在线播放视频| 精品国产乱码久久久久久蜜臀| 中文字幕在线视频日韩| 中文在线第一页| 亚洲 欧美 中文字幕| 亚洲一区导航| 国产成人一二三区| 久久夜色精品国产噜噜亚洲av| 国产欧美日韩综合精品| 在线视频国产三级| 日韩中文字幕视频在线观看| 日本中文字幕在线观看| 日韩不卡高清视频| 欧美99久久| av手机天堂| 中文字幕4区| 91精品在线观看国产| 亚洲精品欧美二区三区中文字幕| 中文字幕在线观看播放| 久久久久黄色| 国产在线欧美| 日本不卡免费高清视频| 一区二区91| 一区二区在线高清视频| 亚洲欧洲三级| 久久人人精品| 日韩欧美中文字幕公布| 99日韩精品| 黄色欧美日韩| 精品视频在线导航| 欧美 日韩 中文字幕| 日韩欧美亚洲国产| 精品三级av| 91精品国产91| 中文字幕日韩高清| 亚洲一级在线| 国产日韩中文在线| 欧美日韩高清一区二区不卡| 欧美日韩国产在线看| 亚洲男人在线| 在线精品观看| 欧美日韩激情一区二区三区| 欧美日韩亚洲国内综合网俺| 国产成人精品亚洲| 亚洲国产无线乱码在线观看| 中文字幕最新精品| 黄色国产网站在线观看| 91精品国产乱码久久蜜臀| 国产欧美日韩中文| 中文字幕日韩高清| 国产一二三视频| 91精品在线观看入口| 91精品国产综合久久精品app| a视频免费在线观看| 精品日韩欧美在线| 午夜黄色小视频| 欧美日韩在线不卡| 麻豆一区二区99久久久久| 91精品久久久久久蜜臀| 国产中文伊人| 精品久久蜜桃| 国产日韩精品在线| 欧美一级搡bbbb搡bbbb| 欧美wwww| 中文字幕亚洲乱码| 国产蜜臀在线| 欧美三级视频在线| 日韩精品免费视频一区二区三区| 亚洲第一视频| 国产欧美三级| 久久久精品日韩欧美| 欧美1234区| 欧美在线日韩精品| 国产三级中文字幕| 精品日韩视频在线观看| 91九色在线播放| 亚洲最新永久观看在线| 日韩欧美在线精品| 日韩亚洲不卡在线| 欧美 日韩 国产在线观看| wwwwww在线观看| 中文字幕亚洲国产| 91xxx在线观看| wwwav91com| 中文字幕在线观看网址| 国产最新在线| 91精品国产日韩91久久久久久| 91吃瓜在线观看| 在线日韩欧美| 亚洲综合欧美在线| 亚洲影视资源网| 国产一区久久| 国产在线日韩精品| 欧美三级三级三级爽爽爽| 一区二区三区久久| 亚洲成年人在线播放| 精品日本视频| 日韩三级视频在线看| 欧洲精品在线视频| 99视频在线看| 日韩中文字幕精品视频| 中文字幕日韩欧美| 亚洲va韩国va欧美va精品| 日韩美女视频一区二区在线观看| 日韩在线观看精品| 蜜臀久久精品| 日韩视频一区| 免费网站看黄yyy222| 午夜少妇久久久久久久久| 国产在线不卡一区| 日韩欧美在线网站| 亚洲热线99精品视频| 国产日韩第一页v| 中文字幕不卡三区| 一区二区在线观看不卡| 一区视频在线播放| 在线日韩中文| 在线亚洲人成| 精品国产99久久久久久| 91一区二区| 国产综合成人久久大片91| 中文字幕线观看| 日韩欧美国产免费| 日韩精品视频网| 欧美日韩在线精品一区二区三区激情综| 国产三级精品在线观看| www.尤物.com| 最近中文字幕在线中文高清版| 国产欧美久久久| 国产v日产∨综合v精品视频| 日韩精品在线中文字幕| av免费在线不卡| 国产最新在线| 黄色欧美日韩| 欧美亚洲专区| 国产日韩电影| 国产一级视频在线播放| 色综合天天综合网国产成人综合天| 一级片免费在线| 欧美午夜影院在线视频| 日韩欧美亚洲国产| 中文字幕亚洲欧美| 日韩欧美国产午夜精品| 国产欧美综合在线观看第十页| 高清一区二区| 欧美日韩激情一区| 欧美日韩综合色| 欧美99久久| 国产日产一区二区三区| av影视在线看| 搞黄在线观看| 国产福利三区| 蜜臀国产一区| 不卡在线一区二区| 亚洲欧美日本国产专区一区| 91精品视频国产| 亚洲综合视频一区| 久久久久蜜桃| wwww亚洲| 亚洲视频日韩| 亚洲乱码在线观看| 欧美中文字幕精品| 日韩视频一区| 日韩不卡高清视频| 亚洲第一视频网站| 欧美三级日韩三级| 欧美日韩综合在线观看| 美女黄a一级视频| 欧美日韩国产亚洲一区| 中文字幕在线视频久| 国产精品福利视频一区二区三区| 免费国产成人看片在线| 中文字幕在线视频网| 欧美日韩视频在线| 中文欧美字幕免费|