亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

多進程、共享內(nèi)存的網(wǎng)絡(luò)聊天室

2019-11-10 20:07:59
字體:
供稿:網(wǎng)友

好久沒寫網(wǎng)絡(luò)聊天室了,去年暑假可以說寫了一暑假,最近復(fù)習(xí)這些,又因為我一直偏向于多線程,就用多進程復(fù)習(xí)一下。

下面給出昨天寫的基于多進程、共享內(nèi)存的網(wǎng)絡(luò)聊天室代碼。每個進程負(fù)責(zé)一個連接,多個進程之間僅共享讀,不共享寫,因此無需信號量來同步。分配的一段內(nèi)存中,以數(shù)組的方式,分配給每個client一段buffer,每個clilent對應(yīng)的buffer的索引就是connfd。當(dāng)一個子進程收到客戶端數(shù)據(jù)后,通過每客戶端管道發(fā)送自己的pid給主進程,主進程通知除了該子進程的其他進程將該片內(nèi)存寫好的數(shù)據(jù)轉(zhuǎn)發(fā)給其他客戶端(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;//封裝每個客戶端連接數(shù)據(jù)struct client_data { sockaddr_in address; int connfd; pid_t pid; //負(fù)責(zé)該客戶端子進程的pid int pipefd[2]; //每個子進程pipe};static const char* shm_name = "/my_shm"; //共享內(nèi)存的名字int sig_pipefd[2]; //用來統(tǒng)一事件源int epollfd;int listenfd;int shmfd; char* share_mem = NULL; //共享內(nèi)存起始地址//客戶端連接數(shù)組,進程用客戶連接的編號來索引這個數(shù)組,即可取得相關(guān)的客戶連接數(shù)據(jù)client_data* users = NULL; //子進程和客戶連接的關(guān)系映射表,用子進程的pid來索引這個數(shù)組,即可取得該進程處理的客戶連接的編號int* sub_process = 0;int user_count = 0; //客戶連接下標(biāo),這個名字有點誤導(dǎo),總之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);}//子進程的信號處理函數(shù),停止一個子進程void child_term_handler(int sig){ stop_child = true;}//子進程運行的函數(shù),參數(shù)inx指出該子進程處理的客戶連接的編號,users是保存所有客戶連接數(shù)據(jù)的數(shù)組,參數(shù)share_mem指出共享內(nèi)存的起始地址int run_child(int idx, client_data* users, char* share_mem){ epoll_event events[MAX_EVENT_NUMBER]; //每個子進程使用I/O服用同時監(jiān)聽客戶連接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; //子進程需要設(shè)置自己的信號處理函數(shù),因為fork會繼承父進程信號處理函數(shù) 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; //本子進程負(fù)責(zé)的客戶鏈接有數(shù)據(jù)到達 if(sockfd == connfd && (events[i].events & EPOLLIN)){ //清零該客戶對應(yīng)的緩沖區(qū) memset(share_mem+idx*BUFFER_SIZE, '/0', BUFFER_SIZE); //將客戶數(shù)據(jù)讀取到對應(yīng)的讀緩存中,該讀緩存是共享內(nèi)存的一段,它開始于idx*BUFFER_SIZE處,長度為BUFFER_SIZE字節(jié),因此每個客戶連接是共享的 ret = recv(connfd, share_mem+idx*BUFFER_SIZE, BUFFER_SIZE-1, 0); //留一個字節(jié)為'/0'間隔 if(ret < 0){ if(errno != EAGAIN) stop_child = true; } else if(ret == 0) stop_child = true; else //成功讀取客戶數(shù)據(jù)后就通知主進程,讓主進程吩咐其他進程轉(zhuǎn)發(fā) send(pipefd, (char*)&idx, sizeof(idx), 0); } //主進程通過管道通知本進程需要轉(zhuǎn)發(fā)第client個客戶端的數(shù)據(jù)到本進程負(fù)責(zé)的客戶 else if(sockfd == pipefd && (events[i].events & EPOLLIN)){ int client = 0; //接受主進程發(fā)來的數(shù)據(jù),即客戶的編號,用來索引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 //轉(zhuǎn)發(fā)給自己的客戶 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;/////////////////////////////////////////////////////////////// //創(chuàng)建共享內(nèi)存,作為所有客戶連接的讀緩存 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映射共享內(nèi)存 //這是共享內(nèi)存的一種方式,另外一種使用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個客戶連接的數(shù)據(jù) users[user_count].address = client_address; users[user_count].connfd = connfd; //在子進程和父進程間建立管道,以傳遞必要的數(shù)據(jù) 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]); //子進程關(guān)掉一端,子進程給父進程發(fā)數(shù)據(jù)使用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]); //記錄新的客戶連接在數(shù)組users中的索引值,建立進程pid和索引值的映射關(guān)系 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: //子進程退出,表示有客戶端關(guān)閉了連接 { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0){ //用子進程的pid取得被關(guān)閉客戶連接的編號 int del_user = sub_process[pid]; sub_process[pid] = -1; if(del_user < 0 || del_user > USER_LIMIT) continue; //清除數(shù)據(jù) 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對應(yīng)的值,也就是修正最后一個客戶端pid對應(yīng)的客戶編號 } if(terminate && user_count == 0) stop_server = true; break; } case SIGTERM: case SIGINT: //結(jié)束服務(wù)器程序 { 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; } } } } //某個子進程收到數(shù)據(jù),向父進程通知 else if(events[i].events & EPOLLIN){ int child = 0; //讀取管道數(shù)據(jù),收到的數(shù)據(jù)時child變量記錄了哪個客戶連接有數(shù)據(jù)到達 ret =recv(sockfd, (char*)&child, sizeof(child), 0); if(ret == -1) continue; else if(ret == 0) continue; else{ //向除負(fù)責(zé)第child個客戶的子進程之外的子進程發(fā)送消息,通知他們有客戶數(shù)據(jù)要寫 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日志記錄級別

下一篇:四種修飾符

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
欧美xxxx在线观看| 中文在线а√在线8| 国产亚洲一二三区| 五月天激情四射| 老司机在线精品视频| 国产主播在线资源| 国产精品免费久久久| 91情侣偷在线精品国产| 国产一区二区三区在线观看| 性欧美一区二区三区| 色婷婷综合视频在线观看| 日韩一区二区三区精品视频第3页| 亚洲精品一区二区久| 五月天综合激情网| 中文字幕在线播放一区| 最近免费观看高清韩国日本大全| 日本成人中文字幕| 中文字幕资源在线观看| 色综合婷婷久久| 女一区二区三区| wwwxxx亚洲| 风间由美一区二区三区| 久久久国产精品一区二区中文| 国产午夜精品一区二区三区四区| 久久高清视频免费| 亚洲国产一区二区在线播放| 中文字幕在线影视资源| 真人做人试看60分钟免费| 国产精品视频中文字幕91| 久久99久久久久| 日韩欧美1区| 久久精品ww人人做人人爽| 亚洲影院高清在线| 亚洲一区二区三区自拍| 国产精品国产三级国产专区51| 亚洲欧美激情一区二区三区| 国产精品视频一区视频二区| 国产一区三区在线播放| 国产男女无遮挡猛进猛出| 国产一级二级在线观看| 中文视频在线| 国产一区二区视频播放| 久久综合之合合综合久久| 欧美精品国产精品日韩精品| 亚洲欧美日韩成人在线| 一区二区三区精品国产| 久久久久久久97| 热草久综合在线| 国产在线视频欧美| 久久免费看av| 91久久精品国产91性色| 久久久亚洲精品石原莉奈| 日本高清视频一区二区三区| 久蕉依人在线视频| 国产精品一卡二卡三卡| 18网站在线观看| 亚洲色图一区二区三区| 亚洲图片欧洲图片日韩av| 第四色在线一区二区| 亚洲 激情 在线| 天堂av在线电影| 国产亚洲精品久久久久久久| 玖玖在线视频| 欧洲成人在线观看| 日韩欧美看国产| 精品国产伦一区二区三区观看方式| 成人污污视频在线观看| 欧美一区二区三区免费看| 97久久天天综合色天天综合色hd| 青青草免费观看视频| 色综合色综合色综合色综合色综合| 亚洲男人天堂2021| 超碰超碰人人人人精品| 国产区一区二区三| 成人激情视频网站| 亚洲精品久久嫩草网站秘色| 日本高清www| 国产18精品乱码免费看| 欧美另类一区| 国产精品亚洲产品| 国产毛片一区二区| 一区二区三区欧洲区| 快播av资源| 五月天久久777| 亚洲国产裸拍裸体视频在线观看乱了| 美女网站色免费| 国产综合福利在线| 麻豆福利视频| 都市激情久久久久久久久久久| 日韩一级精品视频在线观看| 免费一级特黄特色大片| 涩涩视频免费观看| av亚洲在线观看| av资源网在线播放| 国产美女无遮挡永久免费| 欧美日一区二区三区在线观看国产免| 国产二级片在线| 在线看的网站你懂| 国产精品12| 91桃色在线观看| 青青草国产精品视频| 国产亚洲欧洲997久久综合| 国产高清精品一区二区三区| 亚洲免费在线视频观看| 亚洲日本视频在线观看| 久久av二区| 成人在线视频成人| 天天操夜夜欢| 国产精品偷伦一区二区| www.男人的天堂.com| 欧美成人午夜影院| 国产真实有声精品录音| 日韩精品免费| 欧美亚洲综合另类| 精品理论电影在线| 亚洲一区二区三区sesese| 日本一区二区三区网站| 91在线精品播放| 精品欧美国产| 隔壁人妻偷人bd中字| eeuss影院eeuss最新直达| 五月天久久网站| 性欧美高清强烈性视频| 毛片毛片毛片毛片毛| 国产一区二区波多野结衣| 亚洲精品国产一区二区精华液| 无遮挡又色又刺激的女人视频| 91麻豆成人精品国产| 四季av中文字幕| 99久久激情| 国产97在线观看| 日韩美女一区二区三区四区| 欧美一级片在线| 欧美三级免费观看| 高清中文字幕一区二区三区| 一区二区三区国| 日本一区视频在线播放| 久久夜精品va视频免费观看| 亚洲а∨精品天堂在线| 日韩在线观看视频一区二区三区| 国产一区视频在线观看免费| 国产高清免费在线观看| 日本久久中文字幕| 性xxxx丰满孕妇xxxx另类| 在线看污网站| 亚洲欧洲成人| 一级特黄特色的免费大片视频| 欧美吞精做爰啪啪高潮| 日日橹狠狠爱欧美超碰| 性一交一乱一伧国产女士spa| 亚洲成人av综合| 亚洲一区二区乱码| 国内精品伊人久久久久影院对白| 欧美日韩在线视频首页| 久久99国产精品久久久久久久久| 丝袜熟女一区二区三区| 九色porny丨首页在线| 久久精品色播| 久本草在线中文字幕亚洲| 日本黄网站免费| 国产有码一区二区| 亚洲高清av一区二区三区| 国产免费一级片| 亚洲自拍小视频免费观看| 日本黄色动态图| 黄色免费视频观看| 天堂www在线а√天堂| 红桃视频国产一区| 日韩毛片中文字幕| 精品国产91洋老外米糕| 你懂的亚洲视频| 亚洲啊v在线观看| 黄网站app在线观看下载视频大全官网| 精品久久久久久久大神国产| 97超级在线观看免费高清完整版电视剧| 搡老岳熟女国产熟妇| 国产午夜精品美女视频明星a级| h片在线观看视频免费| 羞羞在线观看网站| 黄色成人精品网站| 午夜刺激在线| youjizzxxxx18| 黄色录像a级片| 国产成人久久精品77777| 国产一区二区三区在线观看免费视频| 麻豆网站在线| 亚洲婷婷综合网| 欧美成人免费在线观看视频| 精品1区2区3区4区| 欧美一级做性受免费大片免费| 黄色电影免费在线观看| 国产一区二区黑人欧美xxxx| 国产精品成av人在线视午夜片| 国产 日韩 欧美 精品| 91亚洲人电影| 午夜精品久久久久99热蜜桃导演| 欧美亚洲国产一区二区三区va| 91精品美女在线| 中文字幕毛片| 亚洲人成777| 成人精品中文字幕| 国产免费一级视频| 高清一级毛片视频| 极品色影院av| 亚洲国产精品99久久久久久久久| 蜜桃导航-精品导航| 亚洲裸体xxxx| 精品美女在线播放| 日韩有码一区| 亚洲精品久久一区二区三区777| 亚洲欧洲成人自拍| 成人自拍视频网| 希岛爱理av免费一区二区| 韩日精品一区| 亚洲人人夜夜澡人人爽| 久久这里有精品15一区二区三区| 激情在线观看视频| 久久国产乱子伦精品| www.久久色| 91精品国产色综合| 91精品国产麻豆国产在线观看| 精品成人a区在线观看| 国产一区二区三区天码| jiuse.com91视频| 亚洲男人天堂av在线| 欧美婷婷久久| 中文文精品字幕一区二区| 91精品一区二区三区四区| 午夜免费播放观看在线视频| 成人91免费视频| 无码国产精品一区二区免费16| 成人国产精品久久久网站| 99热这里只有精品99| 最新av中文字幕| 欧美xxxx综合视频| 欧美在线你懂的| 国模精品一区二区| 又黄又爽又色视频| 2018高清国产日本一道国产| 爱福利视频一区二区| 中文字幕日韩在线| 成人免费无码大片a毛片| 国产黄色av片| 一区二区三区国产盗摄| 国产精品自拍区| 亚洲欧美国产一区二区三区| 娇妻被老王脔到高潮失禁视频| 香港三日本三级少妇66| 四虎影视国产在线视频| 欧美另类综合| 午夜剧场在线免费观看| 日日夜夜天堂| 亚洲一区二区视频| 中文精品一区二区三区| 国产chinasex对白videos麻豆| 天天做天天爱天天综合网2021| 欧美黄色大片网站| 欧美成人xxxx| 日韩av网站在线观看| 黄网站色大毛片| 国产精品久久占久久| 免费看又黄又无码的网站| 91在线视频免费播放| 宇都宫紫苑在线播放| 中文字幕在线观看日韩| 97精品国产99久久久久久免费| 五月天网站亚洲| 人人澡人人添人人爽一区二区| 国产一级一区二区| 四虎国产精品免费观看| 国内外成人免费视频| 精品一区二区久久久久久久网站| 欧美激情在线观看视频免费| 97超碰资源站| 中国色在线观看另类| 中文字幕系列一区| 国产福利精品导航| 日韩av资源| 久久精品久久久| 亚洲人成网站精品片在线观看| 特黄国产免费播放| 国产精品短视频| 久久精品视频网站| 国产免费成人在线| 精品精品国产国产自在线| 日韩国产激情| 午夜精品久久久久久久| 一级日本黄色片| 亚洲人成在线电影| 亚州精品天堂中文字幕| 欧美一级欧美三级| 欧美黑人猛猛猛| 亚洲一区二区免费在线| 牛牛影视一区二区三区免费看| 两个人看的在线视频www| 91久久久久久久久久久久| 亚洲免费av一区| 国产中文一区| 91精品国产91久久久久福利| 中文字幕免费在线观看视频一区| 麻豆视频在线观看免费网站| 国产三级香港三韩国三级| 日韩高清成人| 91精品啪在线观看国产81旧版| 国产aⅴ夜夜欢一区二区三区| 亚洲欧美激情在线观看| 校园春色 亚洲色图| 一本久中文高清| 久久久久久久久福利| 国产精品一区二区x88av| 蜜臀av在线播放| 日韩 欧美一区二区三区| 欧美日韩福利视频| 丁香花在线观看完整版电影| 国产va免费精品高清在线观看| 日韩欧美亚洲一区二区| 亚洲欧美精品一区| 日韩在线视频精品| 日韩免费在线| 国产ktv在线视频| 性视频1819p久久| 中文字幕有码热在线视频| 少妇av在线| 性网爆门事件集合av| 久久美女高清视频| 日韩妆和欧美的一区二区| 国产视频一区在线播放| 97超碰人人爱|