我們這裏要使用的是#include <stdexcept>
,可以參考官方文檔
先舉一個例子,比如調用recv的函數返回值處理:
int ret = recv(fd...);
if (ret > 0){}
if (ret == 0){}
if (ret == -1)
{
//EAGAIN/EWOULDBLOCK提示你的應用程序現在沒有數據可讀請稍後再試
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
break;
}
//EINTR指操作被中斷喚醒,需要重新讀
else if (errno == EINTR)
{
continue;
}
//異常斷開情況
else
{
close(fd);
break;
}
}
這裏僞代碼描述,具體處理方法可以參考我的文章epoll的ET和LT模式下,accept,recv,send寫法
重點我們關注的是ret == -1發生錯誤的情況,其中我們需要處理EAGAIN,EWOULDBLOCK,EINTR,其它錯誤這些情況,那麼首先這些返回值程序員可以不處理,或者說忘了處理,忽略了,但是我們轉爲返回異常,那麼就必須處理了,這樣的封裝有利於程序的健壯性;其次整型返回值沒有任何語義信息,而異常卻包含語義信息,有時你從類名就能夠體現出來。
現在我們對這幾個錯誤進行封裝:
class socket_again: public std::runtime_error
{
socket_again(const std::string& s):std::runtime_error(s)
{
}
};
class socket_intr: public std::runtime_error
{
socket_intr(const std::string& s):std::runtime_error(s)
{
}
};
class socket_error: public std::runtime_error
{
socket_error(const std::string& s):std::runtime_error(s)
{
}
};
現在用封裝的異常來替換上面錯誤值的處理邏輯:
int my_recv(fd...)
{
int ret = recv(fd...);
if (ret == -1)
{
//EAGAIN/EWOULDBLOCK提示你的應用程序現在沒有數據可讀請稍後再試
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
throw socket_again(strerror(errno));
}
//EINTR指操作被中斷喚醒,需要重新讀
else if (errno == EINTR)
{
throw socket_intr (strerror(errno));
}
//異常斷開情況
else
{
throw socket_error(strerror(errno));
}
}
return ret;
}
然後再調用my_recv完成所有的邏輯:
try
{
int ret = my_recv(fd...);
if (ret > 0){}
if (ret == 0){}
}
catch(socket_again& e)
{
}
catch(socket_intr& e)
{
}
catch(socket_error& e)
{
}