儘量使用非阻塞socket服務器
int flags, s;
flags = fcntl (fd, F_GETFL, 0);
if (flags == -1){
close(fd);
return -1;
}
flags |= O_NONBLOCK;
s = fcntl (fd, F_SETFL, flags);
if (s == -1){
close(fd);
return -1;
}
socket
使用效率高效的epoll機制獲取多個socket上的IN/OUT事件函數
非阻塞socket鏈接服務端時,不必定當即鏈接得上服務器oop
經過判斷connect函數的返回值和錯誤號作進一步跟蹤性能
int ret = ::connect(this->fd, (struct sockaddr*)&(server_addr), sizeof(server_addr));
if(ret == 0){
this->on_connected();
}else if(ret < 0 && errno != EINPROGRESS){
//error
}else{
on_connecting();
}this
IN/OUT事件時若是是connecting須要判斷socket狀態,socket reset發生時也會產生事件,而後才進入有效的讀寫
server
if(this->connect_status == 1){//connecting
int status = 0;
socklen_t slen;
if(getsockopt(this->fd, SOL_SOCKET, SO_ERROR, (void*)&status, &slen) < 0){
this->on_epollhup();
return;
}
if(status != 0){
this->on_epollhup();
return;
}
on_connected();
}
事件
讀寫發生錯誤時,經過錯誤碼判斷是錯誤仍是數據讀完或者緩衝區滿了,發生錯誤則按socket斷開處理rem
錯誤代碼包括:SIGPIP, EAGAIN 等, EAGAIN表示讀完或者緩衝區滿,等待下一次事件處理讀或者寫
get
爲了達到更高的性能,epoll使用EPOLLET(邊沿觸發)機制,可是若是事件發生時,無數據可寫時,下一次有數據時
則不會發生OUT事件,所以能夠記錄一個寫空轉標識write_nil_loop,epoll_wait事件以前判斷是否有數據發送而且發生write_nil_loop,若是有,則從新登記epoll事件
if(worker->is_write_nil_loop() && (events & EPOLLOUT)){
epoll->remove(worker);
epoll->add(worker, events);
}else if(worker->get_events_mask() != events){
epoll->modify(worker, events);
}
同時,讀取數據時,儘量將數據讀完,直到recv返回值-1,errno== EAGAIN,其餘錯誤按照出錯處理