小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

ace第二課

 阿鼎的圖書館 2013-07-21

一個日志服務器的實現(C 網絡編程第四章程序實現及解析)

一、服務端系統流程

1、首先運行Iterator_Logging_Server::run()函數,這個函數從父類Logging_Server繼承而來。Iterator_Logging_Server類中本身并沒有寫這個函數。

2、這里會調用Iterator_Logging_Server::open()函數,這個函數在Iterator_Logging_Server類中進行了重寫,所以覆蓋了父類中的open()函數。

3、運行Logging_Server::make_log_file(),我們并沒有輸入ACE_SOCK_Stream類型參數,那么不會執(zhí)行if中的語句,而執(zhí)行else中語句。并通過return中語句來產生一個新文件。

4、在return中調用Logging_Server::open()函數。這個函數用于實現建立一個通信端點。然后返回Logging_Server::run()中繼續(xù)運行。

5、執(zhí)行Iterative_Logging_Server::handle_connections()函數。在這里進行等待客戶端的連接。待有輸入后繼續(xù)運行。

6、執(zhí)行Iterative_Logging_Server:: handle_data()函數。用入等待用戶輸入,然后將輸入寫入日志文件,這里調用了Logging_Handler:: log_record()函數,這里是一個while()循環(huán),只有輸入錯誤才會停止。

7、在Logging_Handler:: log_record()中調用Logging_Handler::recv_log_record()接受用戶的輸入,并提取。

8、在Logging_Handler:: log_record()中調用Logging_Handler::write_log_record(),將用戶的輸入寫入到文件中。

        程序的大致流程就是這樣。

 

二、服務器端源碼

1)Logging_Server.h

  1. #ifndef LOGGING_SERVER_H  
  2. #define LOGGING_SERVER_H  
  3.   
  4. #include "ace/FILE_IO.h"  
  5. #include "ace/SOCK_Acceptor.h"  
  6.   
  7. class ACE_SOCK_Streasm;  
  8.   
  9. class Logging_Server  
  10. {  
  11. public:  
  12.     virtual int run(int argc, char* argv[]);  
  13.   
  14. protected:  
  15.     virtual int open(u_short logger_port = 0);  
  16.     virtual int wait_for_multiple_events()  
  17.     {  
  18.         return 0;  
  19.     }  
  20.     virtual int handle_connections() = 0; //定義純虛函數  
  21.     virtual int handle_data(ACE_SOCK_Stream * = 0) = 0;  
  22.     int make_log_file(ACE_FILE_IO& , ACE_SOCK_Stream * = 0);  
  23.     virtual ~Logging_Server()  
  24.     {  
  25.         acceptor_.close();  
  26.     }  
  27.     ACE_SOCK_Acceptor& acceptor()  
  28.     {  
  29.         return acceptor_;  
  30.     }  
  31.   
  32. private:  
  33.     ACE_SOCK_Acceptor acceptor_;  
  34. };  
  35.   
  36. #endif  


2)Logging_Server.cpp

  1. #include "ace/FILE_Addr.h"  
  2. #include "ace/FILE_Connector.h"  
  3. #include "ace/FILE_IO.h"  
  4. #include "ace/INET_Addr.h"  
  5. #include "ace/SOCK_Stream.h"  
  6. #include "Logging_Server.h"  
  7.   
  8. //attention: second.  
  9. //僅僅是打開一個偵聽端口。  
  10. int Logging_Server::run(int argc, char* argv[])  
  11. {  
  12.     //atoi: Convert a string to integer.   
  13.     //這里建立了一個服務器被動通信端。  
  14.     if(open(argc > 1 ? atoi(argv[1]) : 888) == -1)  
  15.         return -1;  
  16.   
  17.     for(;;)  
  18.     {  
  19.         //全部返回零。  
  20.         if(wait_for_multiple_events() == -1)  
  21.             return -1;  
  22.         if(handle_connections() == -1)  
  23.             return -1;  
  24.         if(handle_data() == -1)  
  25.             return -1;  
  26.     }  
  27.     return 0;  
  28. }  
  29. // attention: first.  
  30. int Logging_Server::open(u_short logger_port)  
  31. {  
  32.     ACE::set_handle_limit();  
  33.     ACE_INET_Addr server_addr;  
  34.     int result;  
  35.     if(logger_port != 0)  
  36.         result = server_addr.set(logger_port);  //int ACE_INET_Addr::set(u_short port_number,ACE_UINT32 ip_addr = INADDR_ANY,int encode = 1,int  map = 0)    
  37.     else  
  38.         result = server_addr.set("ace_logger", ACE_UINT32(INADDR_ANY)); //int ACE_INET_Addr::set  (  const char  port_name[],ACE_UINT32  ip_addr,const char  protocol[] = "tcp")    
  39.                                                             //"ace_logger" 在 /etc/service 中定義.  
  40.     if(result == -1)  
  41.         return -1;  
  42.     //If this is 1 then we'll use the <so_reuseaddr> to reuse this address  
  43.     return acceptor_.open(server_addr, 1);   //被動建立一個通信端點。  
  44. }  
  45.   
  46. int Logging_Server::make_log_file(ACE_FILE_IO& logging_file,   
  47.                                   ACE_SOCK_Stream* logging_peer)  
  48. {  
  49.     //這里暫時不使用第二個參數  
  50.     char filename[MAXHOSTNAMELEN  sizeof(".log")];  
  51.     //建立傳輸流。  
  52.     if(logging_peer != 0)  
  53.     {  
  54.         ACE_INET_Addr logging_peer_addr;  
  55.         logging_peer->get_remote_addr(logging_peer_addr);  
  56.         //獲取表示主機名字的字符,并存于filename中。  
  57.         logging_peer_addr.get_host_name(filename, MAXHOSTNAMELEN);  
  58.         strcat(filename,"*.log");  
  59.     }  
  60.     else  
  61.         strcpy(filename, "logging_server.log");  
  62.   
  63.     ACE_FILE_Connector connector;  
  64.     //實際上是通過log_file_作為實參傳入的。這里面會對文件句柄(handler)進行設置。在后面的send_n()中,也會使用這里所設的文件句柄!  
  65.     return connector.connect(logging_file,  
  66.         ACE_FILE_Addr(filename),  
  67.         0,  
  68.         ACE_Addr::sap_any,  
  69.         0,  
  70.         O_RDWR|O_CREAT|O_APPEND,  
  71.         ACE_DEFAULT_FILE_PERMS);  
  72. }  


3)Logging_Handler.h

  1. #ifndef LOGGING_HANDLER_H  
  2. #define LOGGING_HANDLER_H  
  3.   
  4. //原來就只包含了這么兩個頭文件,這尼瑪的,讓我情保以堪啊!  
  5. #include "ace/FILE_IO.h"  
  6. #include "ace/SOCK_Stream.h"  
  7. //注意頭文件的包含  
  8. #include "ace/Message_Block.h"  
  9. #include "ace/CDR_Stream.h"  
  10. #include "ace/CDR_Base.h"  
  11. #include "ace/Log_Record.h"   
  12. #include <iostream>  
  13.   
  14.   
  15.   
  16.   
  17. class ACE_Message_Block;  
  18.   
  19. class Logging_Handler  
  20. {  
  21. protected:  
  22.     ACE_FILE_IO& log_file_;  
  23.     ACE_SOCK_Stream logging_peer_;  
  24.   
  25. public:  
  26.     Logging_Handler(ACE_FILE_IO& log_file)  
  27.         : log_file_(log_file)   
  28.     {}  
  29.   
  30.     Logging_Handler(ACE_FILE_IO& log_file,  
  31.                     ACE_HANDLE handle)  
  32.                     : log_file_(log_file)  
  33.     {  
  34.         logging_peer_.set_handle(handle);  
  35.     }  
  36.   
  37.     Logging_Handler(ACE_FILE_IO& log_file,  
  38.                     const ACE_SOCK_Stream& logging_peer)  
  39.                     : log_file_(log_file), logging_peer_(logging_peer)  
  40.     {}  
  41.   
  42.     int close()  
  43.     {  
  44.         return logging_peer_.close();  
  45.     }  
  46.   
  47.     //*&mblk 是一個對指針的引用,也可以使用**mblk 來代替,但現得相對麻煩。  
  48.     int recv_log_record(ACE_Message_Block *&mblk);  
  49.     int write_log_record(ACE_Message_Block* mblk);  
  50.     int log_record();  
  51.   
  52.     ACE_SOCK_Stream& peer()  
  53.     {  
  54.         return logging_peer_;  
  55.     }  
  56.   
  57. //  friend int operator<< (ACE_OutputCDR& cdr, const ACE_Log_Record& log_record);  
  58. //  friend int operator>> (ACE_InputCDR& cdr, ACE_Log_Record& log_record);  
  59. };  
  60.   
  61. #endif  


4)Logging_Handler.cpp

  1. #include "Logging_Handler.h"  
  2. using std::cerr;  
  3.   
  4. int Logging_Handler::recv_log_record(ACE_Message_Block *&mblk)  
  5. {  
  6.     ACE_INET_Addr peer_addr;  
  7.     logging_peer_.get_remote_addr(peer_addr);  
  8.     //  ACE_Message_Block* head = new ACE_Message_Block(BUFSIZ);  
  9.     mblk = new ACE_Message_Block(MAXHOSTNAMELEN   1);  
  10.     peer_addr.get_host_name( mblk->wr_ptr(), MAXHOSTNAMELEN );  
  11.     mblk->wr_ptr(strlen(mblk->wr_ptr())   1); //指向當前指針的下一位置  
  12.   
  13.     ACE_Message_Block *payload =                 //payload是一個臨時的變量。  
  14.         new ACE_Message_Block(ACE_DEFAULT_CDR_BUFFSIZE);  
  15.     ACE_CDR::mb_align(payload);   
  1. //首先我們要明白分幀,然后根據其來分析這個程序。其就是對幀進行了一個解編的過程。  
  2. if(logging_peer_.recv_n(payload->wr_ptr(), 8) == 8)    //這里的8位是消息頭。  
  3. {  
  4.     payload->wr_ptr(8);  //需要手動的移動到尾端,這時就是消息的內容,當然并不是data。這里面還包含有l(wèi)ength等東東。  
  5.     ACE_InputCDR cdr(payload);  
  6.   
  7.     ACE_CDR::Boolean byte_order;  
  8.     cdr >> ACE_InputCDR::to_boolean(byte_order);  //這是提取第一個字段4BYTE。在客戶端中用from_boolean(),所以這里要to_boolean()。  
  9.     cdr.reset_byte_order(byte_order);     
  1. ACE_CDR::ULong length;  
  2. cdr >> length;     //提取了length字段,第二個4BYTE。  
  3.   
  4. //這里的size()是不是針對同一個節(jié)點進行的操作呢?需要考證一下!  
  5. //在客戶端中使用了ACE_CDR::MAX_ALIGNMENT來分配空間,所以這里也一樣了。  
  6. //加8是要保存前面我們存入的8BYTE的消息頭。  
  1.         if(logging_peer_.recv_n(payload->wr_ptr(), length) > 0)  
  2.         {  
  3.             //payload是動態(tài)分配的,所以這個函數運行完成后,這個變量無效,但是這個內存還在,不會刪除。  
  4.             payload->wr_ptr(length);  
  5.             mblk->cont(payload);  
  6.             return length;  //若程序運行正常,將會以返回length結束。  
  7.         }  
  8.     }  
  9.   
  10.     //當程序運行不正常進才會運行下面的程序。  
  11.     payload->release();  
  12.     mblk->release();  
  13.     payload = mblk = 0;  
  14.     return -1;  
  15. }  
  16.   
  17. int Logging_Handler::write_log_record(ACE_Message_Block *mblk)  
  18. {  
  19.     //通過這里實現的寫入文件:  
  20.     if(log_file_.send_n(mblk) == -1) //這里原來是用“->”,申明的是一個對象而不是一個指針。  
  21.         return -1;  
  22.     if(ACE::debug())  
  23.     {  
  24.         //mblk這個鏈的第一個作為頭使用。  
  25.         ACE_InputCDR cdr(mblk->cont());  
  26.         ACE_CDR::Boolean byte_order;  
  27.         ACE_CDR::ULong length;  
  28.   
  29.         cdr >> ACE_InputCDR::to_boolean(byte_order);  
  30.         cdr.reset_byte_order(byte_order);//??  
  31.         cdr >> length;  
  32.         ACE_Log_Record log_record;  
  33.         cdr >> log_record;  
  34.         log_record.print(mblk->rd_ptr(), 1, cerr);  
  35.     }  
  36.     return mblk->total_length();  
  37. }  
  38.   
  39. int Logging_Handler::log_record()  
  40. {  
  41.     ACE_Message_Block *mblk = 0;  
  42.     if(recv_log_record(mblk) == -1)  
  43.         return -1;  
  44.     else  
  45.     {  
  46.         int result = write_log_record(mblk);  
  47.         mblk->release();  
  48.         return result == -1 ? -1 : 0 ;  
  49.     }  
  50. }  


5)Iterator_Logging_Server.h

  1. #ifndef ITERATIVE_LOGGING_SERVER_H  
  2. #define ITERATIVE_LOGGING_SERVER_H  
  3.   
  4. #include "ace/FILE_IO.h"  
  5. #include "ace/INET_Addr.h"  
  6. #include "ace/Log_Msg.h"  
  7.   
  8. #include "Logging_Server.h"  
  9. #include "Logging_Handler.h"  
  10.   
  11. class Iterative_Logging_Server : public Logging_Server  
  12. {  
  13. protected:  
  14.     ACE_FILE_IO log_file_;  
  15.     //logging_handler在這個類的構造函數中通過初始化列表進行了初始化。神奇啊。這樣也就使Iterative_Logging_Server::log_file_和Logging_Handler::logging_file_產生了聯系。所以后面可以使用send_n()。  
  16.     Logging_Handler logging_handler_;  
  17.   
  18. public:  
  19.     Iterative_Logging_Server();  
  20.   
  21.     Logging_Handler& logging_handler();  
  22.   
  23.     virtual ~Iterative_Logging_Server();  
  24.   
  25. protected:  
  26.     virtual int open(u_short logger_port);  
  27.   
  28.     virtual int handle_connections()  
  29.     {  
  30.         ACE_INET_Addr logging_peer_addr;  
  31.         if(acceptor().accept(logging_handler_.peer(), &logging_peer_addr) == -1)  
  32.             ACE_ERROR_RETURN((LM_ERROR,"%p\n","accept()"), -1);  
  33.   
  34.         ACE_DEBUG((LM_DEBUG,"Accepted connection from %s\n",  
  35.             logging_peer_addr.get_host_name()));  
  36.         return 0;  
  37.     }  
  38.   
  39.     virtual int handle_data(ACE_SOCK_Stream*)  
  40.     {  
  41.         while(logging_handler_.log_record() != -1)  
  42.             continue;  
  43.         logging_handler_.close();  
  44.         return 0;  
  45.     }  
  46. };  
  47.   
  48. #endif  

 

6)Iterator_Logging_Server.cpp

  1. #include "Iterative_Logging_Server.h"  
  2.   
  3. Iterative_Logging_Server::Iterative_Logging_Server() : logging_handler_(log_file_)  
  4. {  
  5. }  
  6.   
  7. Logging_Handler& Iterative_Logging_Server::logging_handler() // Logging_Handler& logging_handler() const  
  8. {  
  9.  return logging_handler_;  
  10. }  
  11.   
  12.   
  13. Iterative_Logging_Server::~Iterative_Logging_Server()  
  14. {  
  15.  log_file_.close();  
  16. }  
  17.   
  18.   
  19. int Iterative_Logging_Server::open(u_short logger_port)  
  20. {  
  21.  //原型是雙參,這里只傳入單參。第二個參數有一個默認值為0。  
  22.  if(make_log_file(log_file_) == -1)  
  23.   ACE_ERROR_RETURN((LM_ERROR,"%p\n","make_log_file()"), -1);  
  24.  return Logging_Server::open(logger_port);  
  25. }  

 

7)main.cpp

  1. #include "ace/Log_Msg.h"  
  2. #include "Iterative_Logging_Server.h"  
  3.   
  4. int main(int argc, char* argv[])  
  5. {  
  6.     Iterative_Logging_Server server;  
  7.   
  8.     if(server.run(argc, argv) == -1)  
  9.         ACE_ERROR_RETURN((LM_ERROR,"%p\n","server.run()"), 1);  
  10.     return 0;  
  11. }  

 

三、關于文件句柄

       很明顯,對文件的操作需要文件句柄,這里我們沒有看到任何句柄,但確實在對文件進行寫操作。除非句柄操作已封裝到了類中,所以不需要我們顯式的去操作。這樣我們可以去看一下源碼。

       去看一下“Logging_Server.cpp”這個文件中的“make_log_file()”中的最后一個操作,也就是connector.connect()實現了創(chuàng)建文件。那么也應當在這里初始化了一個句柄。去“FILE_Connector.cpp”中查看這個成員函數。

在這里創(chuàng)建了一個臨時的句柄(句柄本身是在ACE_FILE_IO中):

ACE_HANDLE handle = ACE_INVALID_HANDLE;

//。。。。。。

handle = ACE_OS::mkstemp (filename); // mkstemp() replaces "XXXXXX"

//。。。。。。

new_io.set_handle (handle); //進行句柄的設置。

在“Iterative_Logging_Server.cpp”文件中:

Iterative_Logging_Server::Iterative_Logging_Server() : logging_handler_(log_file_){}

l og_file_(ACE_FILE_IO類)對logging_handler(Logging_Handler類)進行初始化,幸運的是這里采用的是引用方式:

Logging_Handler(ACE_FILE_IO& log_file)

                : log_file_(log_file)

{}

那么在Logging_Itrator_Server中的Log_file_的變化都會反應在Logging_Handler類中。所以在我們的:

    if(log_file_.send_n(mblk) == -1)

通過這個函數對文件進行了寫入,我們可以在“FILE_IO.inl”文件中可以看其源碼中有這樣的一行:

    return ACE::write_n (this->get_handle (),

                      message_block,

                      bytes_transferred);

也就是通過write_n()進行寫入,這里便調用了get_handle()用于得到文件句柄(this是一個ACE_FILE_IO類型的指針,其繼承自ACE_FILE類)。

 消息分幀圖:

四、客戶端

1)Logging_Client.h

  1. #include "ace/OS.h"  
  2. //ACE_InputCDR,ACE_OutputCDR,ACE_CDR等類在這里頭文件里:  
  3. #include "ace/CDR_Stream.h"  
  4. #include "ace/INET_Addr.h"  
  5. #include "ace/SOCK_Connector.h"  
  6. #include "ace/SOCK_Stream.h"  
  7. #include "ace/Log_Record.h"  
  8. //ACE里自已封裝的一個流:  
  9. #include "ace/streams.h"  
  10. //原程序中少了這個頭文件:  
  11. #include "ace/Log_Msg.h"  
  12. #include <string>  
  13.   
  14. //這個未定義:  
  15. //#define MAXLOGMSGLEN 40  
  16.   
  17. class Logging_Client  
  18. {  
  19. public:  
  20.     // send <log_record> to the server  
  21.     int send(const ACE_Log_Record& log_record);  
  22.     //獲得這個流  
  23.     ACE_SOCK_Stream& peer()  
  24.     {  
  25.         return logging_peer_;  
  26.     }  
  27.       
  28.     ~Logging_Client()  
  29.     {  
  30.         logging_peer_.close();  
  31.     }  
  32.   
  33. private:  
  34.     // 流  
  35.     ACE_SOCK_Stream logging_peer_;  
  36. };  


2)Logging_Client.cpp

  1. #include "Logging_Client.h"  
  2.   
  3. int Logging_Client::send(const ACE_Log_Record &log_record)  
  4. {  
  5.     const size_t max_payload_size =  
  6.           4  
  7.           8  
  8.           4  
  9.           4  
  10.           ACE_Log_Record::MAXLOGMSGLEN  
  11.           ACE_CDR::MAX_ALIGNMENT  
  1.     ACE_OutputCDR payload(max_payload_size);  
  2.   
  3.     //插入到payload中  
  4.     payload << log_record;  
  5.     //total_length是計算begin()和end()之間的距離。也就是實際的長度,當然這里面還包含有時間等其安信息。  
  6.     ACE_CDR::ULong length = payload.total_length();  
  7.     //MAX_ALIGNMENT = 8  
  8.     ACE_OutputCDR header(ACE_CDR::MAX_ALIGNMENT   8);  
  9.     //ACE_CDR_BYTE_ORDER = 1,關于from_boolean()請追蹤。我在源碼中作了說明。  
  10.     header << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER);  
  11.     header << ACE_CDR::ULong(length);  
  12.   
  13.     iovec iov[2];  
  14.     //這時是消息頭  
  15.     //只包含BYTE-ORDER和PAYLOAD LENGTH這兩個,共8bytes。  
  16.     iov[0].iov_base = header.begin()->rd_ptr();  
  17.     iov[0].iov_len = 8;  
  18.     //在消息分幀中,只有頭兩個屬性是作為了消息頭處理。其余是作為record處理。包含了在mani中寫入的時間,ID等信息。  
  19.     //這里是實際長度  
  20.     iov[1].iov_base = payload.begin()->rd_ptr();  
  21.     iov[1].iov_len = length;  
  22.       
  23.     return logging_peer_.sendv_n(iov,2);  
  24. }  


3)main.cpp

  1. #include "Logging_Client.h"  
  2.   
  3. int main(int argc, char* argv[])  
  4. {  
  5.     u_short logger_port =   
  6.         argc > 1 ? atoi(argv[1]) : 888;  
  7.     const char* logger_host =   
  8.         argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST;//這個其實就是"localhost"  
  9.   
  10.     int result;  
  11.   
  12.     ACE_INET_Addr server_addr;  
  13.   
  14.     //端口綁定。  
  15.     if(logger_port != 0)  
  16.         result = server_addr.set(logger_port, logger_host);  
  17.     else  
  18.         result = server_addr.set("ace_logger", logger_host);  
  19.     if(result == -1)  
  20.         ACE_ERROR_RETURN((LM_ERROR,  
  21.                         "lookup %s, %p \n",  
  22.                         logger_port == 0 ? "ace_logger" : argv[1],  
  23.                         logger_host), 1);  
  24.       
  25.     ACE_SOCK_Connector connector;  
  26.     Logging_Client logging_client;  
  27.   
  28.     if(connector.connect(logging_client.peer(),  
  29.         server_addr) < 0)  
  30.         ACE_ERROR_RETURN((LM_ERROR,  
  31.                             "%p\n",  
  32.                             "connect()"),  
  33.                             1 );  
  34.   
  35.     cin.width(ACE_Log_Record::MAXLOGMSGLEN);  
  36.     for(;;)  
  37.     {  
  38.         //從stdin輸入一行數據:  
  39.         std::string user_input;  
  40.         cout << "watting for your input: ";  
  41.         getline(cin, user_input,'\n');  
  42.   
  43.         if(!cin || cin.eof())  
  44.             break;  
  45.   
  46.         //獲得時間:天  
  47.         //Informational messages (decimal 8): LM_INFO = 010,  
  48.         ACE_Time_Value now(ACE_OS::gettimeofday());  
  49.         ACE_Log_Record log_record(LM_INFO, now,  
  50.                                 ACE_OS::getpid() );  
  51.         log_record.msg_data(user_input.c_str());  
  52.   
  53.         if(logging_client.send(log_record) == -1)  
  54.             ACE_ERROR_RETURN((LM_ERROR,  
  55.                             "%p\n",  
  56.                             "logging_client.send()"),  
  57.                             1 );  
  58.         else  
  59.             cout << "send the message succesfully!" << endl;  
  60.     }  
  61.     return 0;  
  62. }  

 

       相對簡單容易看懂,故不作分析!

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多