我最近在复习套接字编程,不过我打算用C++的类给一些操作封装一下
服务器套接字
class server { private: int sockfd; struct sockaddr_in address;
public: server(const char ip[], unsigned int port); ~server();
public: bool run(int backlog = 5); recept accept(); bool shutdown(int option); bool close(); };
服务器accept产生的套接字 recept(招待)
class recept { private: int listen_fd; public: recept(int fd); ~recept(); public: int send(char buffer[], int length); int recv(char buffer[], int length); bool close(); bool shutdown(int option); };
客户端套接字
class client { private: int sockfd; public: client(int domain = AF_INET); ~client();
public: int field(); public: int connect(const char ip[], unsigned int port); int connect(const char path[]); int send(char buffer[], int length); int recv(char buffer[], int length); bool close(); bool shutdown(int option); };
我确定可以正常运行以后,开始着手封装select
操作
class select {
private:
map<int, callback> records_read, records_write, records_exception;
fd_set read_mask, write_mask, exception_mask;
struct timeval tv;
public:
select();
~select();
private:
int max_count;
void adjust_count(int fd);
public:
bool bind_read(int fd, callback f);
bool bind_write(int fd, callback f);
bool bind_exception(int fd, callback f);
void timeout(int second, int usecond);
void loop(); // remember to reset time and fd_set
void config_from(int option, int fd, fd_set & mask); // 想移除一个描述符的时候bind不起作用,只好从返回值下手,这个返回值就是option
};
我的本意是通过bind
系列函数,将一个描述符与一个回调函数(可以是闭包)绑定,当这个描述符发生事件时,调用callback
bool bind_read(int fd, callback f);
bool bind_write(int fd, callback f);
bool bind_exception(int fd, callback f);
最后调用一个`loop()`函数解决
void select::loop() { // for reset fd_set all_mask; FD_ZERO(&all_mask); struct timeval __tv = {tv.tv_sec, tv.tv_usec};
while(true) { read_mask = all_mask; write_mask = all_mask; exception_mask = all_mask; tv = __tv;
int n = ::select(max_count + 1, &read_mask, &write_mask, &exception_mask, &tv); if(n < 0) { perror("error in select: "); exit(-1); } else if(n == 0) { // timeout continue; } // n > 0 int fd; callback f; int option; for(pair<const int, callback> & __pair: records_read) { fd = __pair.first; f = __pair.second; if(FD_ISSET(fd, &read_mask)) { option = f(fd); config_from(option, fd, read_mask); } } for(pair<const int, callback> & __pair: records_write) { fd = __pair.first; f = __pair.second; if(FD_ISSET(fd, &write_mask)) { option = f(fd); config_from(option, fd, write_mask); } } for(pair<const int, callback> & __pair: records_exception) { fd = __pair.first; f = __pair.second; if(FD_ISSET(fd, &exception_mask)) { option = f(fd); config_from(option, fd, exception_mask); } }
} }
可是我毕竟是一个人,经验不够丰富,也不知道这个设计有没有问题 (其实测试的时候卡住了,代码写得太多,又不好排错)
我不知道有没有开源项目封装过select
,或者有哪位大佬尝试过,在这里向各位请教