标签:style blog color 使用 os strong io 文件
0.春阳语录,代码嵌套三层以上就是一坨垃圾。因此良好的编程风格从封装开始。
1.封装select服务器模型
1.1 如何封装?将select需要的数据结构都封装成结构体,通过参数在函数之间传递,将固定的操作封装成相应的函数。
1.2 封装后的程序:
1.2.1 封装的头文件 select_t.h
#ifndef __SELECT_T_H__
#define __SELECT_T_H__
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)
typedef struct{
fd_set allset_;
fd_set rset_;
int clients_[FD_SETSIZE];
int maxi_;
int maxfd_;
int nready_;
int listenfd_;
void (*handle_callback_)(int, char *buf); //有用户提供回调函数
}select_t;
void select_init(select_t *sel, int listenfd);
void select_set_callback(select_t *sel, void (*handler)(int, char *buf));
void select_do_wait(select_t *sel);
void select_handle_accept(select_t *sel);
void select_handle_data(select_t *sel);
#endif
1.2.2 封装的select类函数 select_t.c
#include "select_t.h"
#include "network.h"
#include <assert.h>
//仅供本文件内部调用
void select_add_fd(select_t *sel, int fd); //将新连接的fd加入到监听集合 和 clients数组中
void select_del_fd(select_t *sel, int i); //将关闭的fd从监听集合和clients数组中基础,并关闭连接
void select_init(select_t *sel, int listenfd){
sel->listenfd_ = listenfd;
FD_ZERO(&sel->allset_);
FD_ZERO(&sel->rset_);
FD_SET(listenfd, &sel->allset_);
int i;
for(i = 0; i < FD_SETSIZE; i++){
sel->clients_[i] = -1;
}
sel->maxi_ = -1;
sel->maxfd_ = listenfd;
}
void select_set_callback(select_t *sel, void (*handler)(int, char*)){
sel->handle_callback_ = handler;
}
void select_do_wait(select_t *sel){
sel->rset_ = sel->allset_;
do{
sel->nready_ = select(sel->maxfd_ + 1, &sel->rset_, NULL, NULL, NULL);
}while(sel->nready_ == -1 && errno == EINTR);
}
void select_handle_accept(select_t *sel){
if(FD_ISSET(sel->listenfd_, &sel->rset_)){
int peerfd = accept(sel->listenfd_, NULL, NULL);
if(peerfd == -1)
ERR_EXIT("accept");
select_add_fd(sel, peerfd);
}
sel->nready_--;
}
void select_handle_data(select_t *sel){
if(sel->nready_ == 0)
return;
int i;
char recvbuf[1024] = {0};
for(i = 0; i < FD_SETSIZE; i++){
if(sel->clients_[i] == -1)
continue;
int fd = sel->clients_[i];
if(FD_ISSET(sel->clients_[i], &sel->rset_)){ //?这里用fd会出错
int ret = readline(fd, recvbuf, 1024);
if(ret == -1)
ERR_EXIT("readline");
else if(ret == 0){
printf("client closed\n");
select_del_fd(sel, i);
continue;
}
sel->handle_callback_(fd, recvbuf);
}
}
}
void select_add_fd(select_t *sel, int fd){
int i;
for(i = 0; i < FD_SETSIZE; i++){
if(sel->clients_[i] == -1){
sel->clients_[i] = fd;
if(i > sel->maxi_)
sel->maxi_ = i;
break;
}
}
if(i == FD_SETSIZE){
fprintf(stderr, "too many clients\n");
close(fd);
exit(EXIT_FAILURE);//!
}
FD_SET(fd, &sel->allset_);
if(fd > sel->maxfd_)
sel->maxfd_ = fd;
}
void select_del_fd(select_t *sel, int i){
assert(i >= 0 && i < FD_SETSIZE); //!
int fd = sel->clients_[i];
sel->clients_[i] = -1;
FD_CLR(fd, &sel->allset_);
close(fd);
}
1.2.3 封装后的mian函数 server.c
#include "network.h"
#include "select_t.h"
/*
* 服务器端使用 select 模型
*
* 这里为服务器提供处理客户请求的方法
* 服务器回调本函数
*/
void handler(int fd, char *buf){
printf("recv data:%s", buf);
writen(fd, buf, strlen(buf));
}
int main(int argc, const char *argv[])
{
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
ERR_EXIT("signal");
int listenfd = listenfd_init();
select_t sel;
select_init(&sel, listenfd);
select_set_callback(&sel, handler);
while(1){
select_do_wait(&sel);
select_handle_accept(&sel);
select_handle_data(&sel);
}
close(listenfd);
return 0;
}
2.封装poll服务器模型
2.1 封装后的头文件 poll_t.h
#ifndef __POLL_T_H__
#define __POLL_T_H__
#include <poll.h>
#include <assert.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)
typedef struct{
struct pollfd clients_[2048];
int maxi_;
int nready_;
int listenfd_;
void (*handle_callback_)(int, char*);
}poll_t;
void poll_init(poll_t *pol, int listenfd, void (*handler)(int, char*));
void poll_do_wait(poll_t *pol);
void poll_handle_accept(poll_t *pol);
void poll_handle_data(poll_t *pol);
#endif
2.2 封装的函数 poll_t.c
#include "poll_t.h"
#include "network.h"
void poll_add_fd(poll_t *pol, int fd);
void poll_del_fd(poll_t *pol, int i);
void poll_init(poll_t *pol, int listenfd, void(*handler)(int, char*)){
pol->listenfd_ = listenfd;
int i;
for(i = 0; i < 2048; i++){
pol->clients_[i].fd = -1;
}
pol->clients_[0].fd = listenfd;
pol->clients_[0].events = POLLIN;
pol->maxi_ = 0;
pol->nready_ = 0;
pol->handle_callback_ = handler;
}
void poll_do_wait(poll_t *pol){
int nready;
do{
nready = poll(pol->clients_, pol->maxi_ + 1, -1);
}while(nready == -1 && errno == EINTR);
if(nready == -1)
ERR_EXIT("poll");
pol->nready_ = nready;
}
void poll_handle_accept(poll_t *pol){
if(pol->clients_[0].revents & POLLIN){
int peerfd = accept(pol->listenfd_, NULL, NULL);
if(peerfd == -1)
ERR_EXIT("accept");
poll_add_fd(pol, peerfd);
--pol->nready_;
}
}
void poll_handle_data(poll_t *pol){
if(pol->nready_ == 0)
return;
int i;
char recvbuf[1024] = {0};
for(i = 1; i <= pol->maxi_; i++){
int peerfd = pol->clients_[i].fd;
if(peerfd == -1)
continue;
if(pol->clients_[i].revents & POLLIN){
int ret = readline(peerfd, recvbuf, 1024);
if(ret == -1)
ERR_EXIT("readline");
else if(ret == 0){
printf("client closed\n");
poll_del_fd(pol, i);
continue;
}
pol->handle_callback_(peerfd, recvbuf);
}
}
}
void poll_add_fd(poll_t *pol, int fd){
int i;
for(i = 0; i < 2048; i++){
if(pol->clients_[i].fd == -1){
pol->clients_[i].fd = fd;
pol->clients_[i].events= POLLIN;
if(i > pol->maxi_)
pol->maxi_ = i;
break;
}
}
if(i == 2048){
fprintf(stderr, "too many clients\n");
close(fd);
exit(EXIT_FAILURE);
}
}
void poll_del_fd(poll_t *pol, int i){
assert(i >= 1 && i < 2048);//
close(pol->clients_[i].fd);
pol->clients_[i].fd = -1;
}
2.3 封装后的main 函数 server.c
#include "network.h"
#include "poll_t.h"
void handler(int fd, char *buf){
printf("recv data:%s", buf);
writen(fd, buf, strlen(buf));
}
int main(int argc, const char *argv[])
{
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
ERR_EXIT("signal");
int listenfd = listenfd_init();
poll_t pol;
poll_init(&pol, listenfd, handler);
while(1){
poll_do_wait(&pol);
poll_handle_accept(&pol);
poll_handle_data(&pol);
}
close(listenfd);
return 0;
}
3.封装epoll服务器模型
3.1 封装后的头文件 epoll_t.c
#ifndef __EPOLL_T_H__
#define __EPOLL_T_H__
#include <sys/epoll.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)
typedef struct{
int epollfd_;
struct epoll_event events_[2048];
int listenfd_;
int nready_;
void (*handle_callback_)(int, char*);
}epoll_t;
void epoll_init(epoll_t *epo, int listenfd, void (*handler)(int, char*));
void epoll_do_wait(epoll_t *epo);
void epoll_handle(epoll_t *epo);
void epoll_close(epoll_t *epo);
#endif
3.2 封装后的epoll类函数 epoll_t.c
#include "epoll_t.h"
#include "network.h"
void epoll_handle_accept(epoll_t *epo);
void epoll_handle_data(epoll_t *epo, int peerfd);
void epoll_add_fd(epoll_t *epo, int fd);
void epoll_del_fd(epoll_t *epo, int fd);
void epoll_init(epoll_t *epo, int listenfd, void(*handler)(int, char*)){
if((epo->epollfd_ = epoll_create(2048)) == -1)
ERR_EXIT("epoll_create");
epo->listenfd_ = listenfd;
epoll_add_fd(epo, listenfd);
epo->nready_ = 0;
epo->handle_callback_ = handler;
}
void epoll_do_wait(epoll_t *epo){
int nready;
do{
nready = epoll_wait(epo->epollfd_, epo->events_, 2048, -1);
}while(nready == -1 && errno == EINTR);
if(nready == -1)
ERR_EXIT("epoll_wait");
epo->nready_ = nready;
}
void epoll_handle(epoll_t *epo){
int i;
for(i = 0 ; i < epo->nready_; i++){
int fd = epo->events_[i].data.fd;
if(fd == epo->listenfd_){
epoll_handle_accept(epo);
}
else
epoll_handle_data(epo, fd);
}
}
void epoll_handle_accept(epoll_t *epo){
int peerfd = accept(epo->listenfd_, NULL, NULL);
if(peerfd == -1)
ERR_EXIT("accept");
epoll_add_fd(epo, peerfd);
}
void epoll_handle_data(epoll_t *epo, int peerfd){
char recvbuf[1024] = {0};
int ret = readline(peerfd, recvbuf, 1024);
if(ret == -1)
ERR_EXIT("readline");
else if(ret == 0){
printf("client closed\n");
epoll_del_fd(epo, peerfd);
return;
}
epo->handle_callback_(peerfd, recvbuf);
}
void epoll_close(epoll_t *epo){
close(epo->epollfd_);
close(epo->listenfd_);
}
void epoll_add_fd(epoll_t *epo, int fd){
struct epoll_event ev;
ev.data.fd = fd;
ev.events = EPOLLIN;
if(epoll_ctl(epo->epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1)
ERR_EXIT("epoll_ctl");
}
void epoll_del_fd(epoll_t *epo, int fd){
struct epoll_event ev;
ev.data.fd = fd;
if(epoll_ctl(epo->epollfd_, EPOLL_CTL_DEL, fd, &ev) == -1)
ERR_EXIT("epoll_ctl");
}
3.3 封装后的main函数 server.c
#include "network.h"
#include "epoll_t.h"
void handler(int fd, char *buf){
printf("recv data:%s", buf);
writen(fd, buf, strlen(buf));
}
int main(int argc, const char *argv[])
{
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
ERR_EXIT("signal");
int listenfd = listenfd_init();
epoll_t epo;
epoll_init(&epo, listenfd, handler);
while(1){
epoll_do_wait(&epo);
epoll_handle(&epo);
}
epoll_close(&epo);
return 0;
}
4.总结
封装对一个程序的编写,调试来说都是至关重要的,封装后的代码可读性明显大大提高,因此,以后在写程序时,要注意这一点。此外,从封装这三种模型来看,epoll显然更简单方便,因此,以后在写服务器的时候要改select为epoll。
0731------Linux网络编程----------论封装的乐趣(select、poll、epoll 服务器模型的封装),布布扣,bubuko.com
0731------Linux网络编程----------论封装的乐趣(select、poll、epoll 服务器模型的封装)
标签:style blog color 使用 os strong io 文件
原文地址:http://www.cnblogs.com/monicalee/p/3883564.html