2009-01-10 25 views
0

我正在用WinSock編寫windows客戶端 - 服務器應用程序,我有服務器類。
而初始化服務器我有這樣的代碼:如何決定在哪裏處理異常 - 在函數的作用域中還是全局異常?


class Server { 
    static const int MaxClients = 10; 
    std::vector connections; 
    CRITICAL_SECTION cs; 
    int port; 
    SOCKET ServerSocket; 
    sockaddr_in ServerAddress; 
    void init(); 
public: 
    Server(int Port); 
    void addConnection(const Client& newClient); 
    void closeConnection(int index); 
    void Listen(); 
    int size(); 
    /*virtual void ClientService(); 
    virtual void SendMsg(const std::string& msg);*/ 
    virtual ~Server(); 
}; 

void Server::init() { 
    WSADATA wsaData; 
    if(WSAStartup(MAKEWORD(2, 2), &wsaData)) 
     throw Exception("WinSock init failed"); 
    ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (ServerSocket == INVALID_SOCKET) 
     throw Exception("Socket failed to create!"); 
    ServerAddress.sin_family = AF_INET; 
    ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY); 
    ServerAddress.sin_port = htons(port); 
    if(bind(ServerSocket,(sockaddr*)&ServerAddress,sizeof(ServerAddress)) == SOCKET_ERROR) 
    { 
     throw Exception("Binding failed"); 
     closesocket(ServerSocket); 
    } 
} 

在哪裏,我需要處理異常?這裏,在init()私有方法(從構造函數中調用)還是在主函數中? 任何規則存在的地方放置處理程序的例外和它依賴於什麼?

+0

請注意,在拋出異常之後您的closesocket()調用永遠不會執行。 – 2009-01-10 19:26:58

回答

3

這取決於你是否真的要去處理例外,例如,用稍微不同的輸入重試,或者決定忽略問題並繼續進行(很少合適,但可以有用)。在這種情況下,您可能很想抓住接近其來源的例外。

在大多數情況下,您可以真正處理異常的唯一方法是記錄並中止操作(例如,在Web應用程序中向用戶提供錯誤頁面,或彈出友好的「此程序已崩潰,抱歉「對話框並退出)。在這種情況下,您的catch塊可能非常靠近堆棧的頂部 - 例如在主要方法。

4

基本規則是,你只能在該部分代碼中捕捉異常,你可以在其中實際處理處理它。通過處理它,我的意思是說,您可以根據拋出的異常採取一些操作,例如嘗試再次創建套接字,或試圖使用不同的配置。

此外,需要審查跨越圖書館邊界的例外情況。根據上下文,您可能想要捕獲它們並重新拋出其他類型的異常,例如從庫客戶機隱藏實現細節。

0

至於在引發函數的範圍內捕獲異常的問題(例如,在init()函數中) - 在引發它的範圍內捕獲異常很少有意義。從本質上講,這意味着你已經發現了一個錯誤並且知道如何處理它(並且正在處理它),但是你正在使用一個異常來執行其他任何事情,而不僅僅是將控制權交給你的函數的另一部分。

雖然可能有情況下,這可能是有意義的(雖然這將是一個代碼味道,指示功能是不夠,它需要重構複雜),邏輯處理的錯誤(因爲它被處理)應使用更常見的控制流技術,如if報表或break。即使是非常不受歡迎的goto也可能比拋出異常只能讓它在同一個函數中處理更可取。