Linux网络通信模型实践
Linux的网络通信模型主要有迭代模型,fork子进程模型,多线程模型和io多路转接模型,迭代模型不能支持并发请求,fork子进程模型在并发数较高时性能开销比较大,所以不介绍这两种模型。
1、创建线程池模型,同时accpet。然后accept加锁
void *threadFunc_1(void *arg) { int thrId = *((int *)arg); int connect_fd; char rcvBuf[MAXLEN]; int nCount; for(;;){ pthread_mutex_lock(&mlock); //printf("SERVER: [%d] accept.\n", thrId); if( (connect_fd = accept(socket_fd, NULL, NULL)) == -1){ printf("accept socket error: %s\n", strerror(errno)); pthread_mutex_unlock(&mlock); exit(-1); } pthread_mutex_unlock(&mlock); pthread_mutex_lock(&nlock); nCount = ++connCount; if(connCount > CONNMAX){ --connCount; pthread_mutex_unlock(&nlock); //xsend(connect_fd, replyBuf, strlen(replyBuf)); //shutdown(connect_fd, SHUT_WR); //read(connect_fd, NULL, MAXLEN); close(connect_fd); printf("Server: connection full!\n"); continue; } pthread_mutex_unlock(&nlock); printf("SERVER: [%d] new client connected, current connected count: %d\n", thrId, nCount); for(;;){ int ret = transfer(connect_fd, thrId, rcvBuf); if(ret < 0){ close(connect_fd); break; } } pthread_mutex_lock(&nlock); nCount = --connCount; pthread_mutex_unlock(&nlock); printf("SERVER: [%d] client logout, current connected count: %d\n", thrId, nCount); } return 0; }
2、主线程accpet,动态创建线程(短连接时开销太大)
for(;;){ int connect_fd; if( (connect_fd = accept(socket_fd, NULL, NULL)) == -1){ printf("accept socket error: %s\n", strerror(errno)); exit(-1); } int nCount; pthread_mutex_lock(&nlock); nCount = ++connCount; if(connCount > CONNMAX){ --connCount; pthread_mutex_unlock(&nlock); //xsend(connect_fd, replyBuf, strlen(replyBuf)); //shutdown(connect_fd, SHUT_WR); //read(connect_fd, NULL, MAXLEN); close(connect_fd); printf("Server: connection full!\n"); continue; } pthread_mutex_unlock(&nlock); printf("SERVER: new client[%d] connected, current connected count: %d\n", connect_fd, nCount); pthread_t thread; pthread_create(&thread, NULL, threadFunc_2, &connect_fd); } //..... void *threadFunc_2(void *arg) { int connect_fd = *((int *)arg); int nCount; char rcvBuf[MAXLEN]; pthread_detach(pthread_self()); for(;;){ int ret = transfer(connect_fd, -1, rcvBuf); if(ret < 0){ close(connect_fd); break; } } pthread_mutex_lock(&nlock); nCount = --connCount; pthread_mutex_unlock(&nlock); printf("SERVER: client[%d] logout, current connected count: %d\n", connect_fd, nCount); return 0; }
3、io多路转接模型(使用epoll)
void *threadFunc_3(void *arg) { pthread_detach(pthread_self()); prctl(PR_SET_NAME, "threadFunc_3", 0, 0, 0); int ret = 0; int connect_fd = 0; int epfd = epoll_create(CONNMAX); unsigned int session_count = 0; struct epoll_event ev, events[CONNMAX]; setNonBlocking(socket_fd); ev.data.fd = socket_fd; ev.events = EPOLLIN/* | EPOLLET*/; ret = epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &ev); if(ret < 0){ verbose("epoll_ctl: %s\n", strerror(errno)); } for(;;){ int nfds = epoll_wait(epfd, events, CONNMAX, -1); if(nfds == -1){ perror("threadFunc_3: epoll_wait"); goto ERREXIT; } for(int i = 0; i < nfds; i++){ if(events[i].data.fd == socket_fd){ connect_fd = accept(socket_fd, NULL, NULL); if(connect_fd == -1){ perror("threadFunc_3: accept socket error"); goto ERREXIT; } struct timeval tv; gettimeofday(&tv, NULL); unsigned long uid = (tv.tv_sec%3600)*1000000 + tv.tv_usec; EventDataSt *data = (EventDataSt *)malloc(sizeof(EventDataSt)); bzero(data, sizeof(EventDataSt)); data->socket_fd = connect_fd; data->uid = uid; setNonBlocking(connect_fd); setSocketBuffer(connect_fd); ev.data.ptr = data; ev.events = EPOLLIN/* | EPOLLET*/; ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connect_fd, &ev); if(ret < 0){ verbose("epoll_ctl: %s\n", strerror(errno)); } session_count++; //printf("SERVER: new connection[%lu]! session_count[%d]\n", uid, session_count); }else if(events[i].events & EPOLLIN){ EventDataSt *eventData = (EventDataSt *)(events[i].data.ptr); connect_fd = eventData->socket_fd; bzero(&(eventData->data), MAXLEN); eventData->len = 0; ret = xrecv(connect_fd, eventData->data, MAXLEN); if(ret <= 0){ session_count--; closeSession(epfd, connect_fd, eventData); eventData = nullptr; }else{ eventData->len = ret; ev.data.ptr = eventData; ev.events = EPOLLOUT/* | EPOLLET*/; ret = epoll_ctl(epfd, EPOLL_CTL_MOD, connect_fd, &ev); if(ret < 0){ verbose("epoll_ctl: %s\n", strerror(errno)); } char idBuf[8]; memcpy(idBuf, eventData->data, 8); } }else if(events[i].events & EPOLLOUT){ bool bClose = false; EventDataSt *eventData = (EventDataSt *)(events[i].data.ptr); connect_fd = eventData->socket_fd; { ret = xsend(connect_fd, eventData->data, eventData->len); if(ret <= 0){ bClose = true; session_count--; closeSession(epfd, connect_fd, eventData); eventData = nullptr; } } if(!bClose){ ev.data.ptr = eventData; ev.events = EPOLLIN/* | EPOLLET*/; ret = epoll_ctl(epfd, EPOLL_CTL_MOD, connect_fd, &ev); if(ret < 0){ verbose("epoll_ctl: %s\n", strerror(errno)); } } } } } ERREXIT: close(epfd); close(socket_fd); exit(EXIT_FAILURE); }
浙公网安备 33010602011771号