ACE(Adaptive Communication Environment),它是一个面向对象的、跨平台的、开放源码的网络编程基础设施框架。
ACE 是由加利福尼亚大学Irvine分校的Douglas C.Schmidt 博士主导开发的,是一种跨平台可编译的网络编程API,并随后在工业界中发展、完善,它将底层的不同系统的细节透明化,为开发者提供统一的接口,从而可在不同系统上相互移植,提高代码利用率。与传统的网络编程相比,它更加规范化,极力避免工业开发中人们常会出现的错误情况,从而提高了程序的可靠性和易用性,并且拥有较高的性能优势。
读者可以从http://www.cs.wustl.edu/~schmidt/ACE.html进一步了解ACE和下载、安装。同时可以点击这里下载有关ACE的相关电子书籍。
本文实现了ACE的一个简单多线程服务器,主要是通过多线程处理并发能力。源代码请点击这里下载。
跟传统的socket编程一样,我们也需要在while循环中监听端口,并分配线程进行处理,程序的头文件定义如下:
1 #include "ace/SOCK_Stream.h" 2 #include "ace/SOCK_Acceptor.h" 3 4 class ACE_Server { 5 public: 6 int run_svc(); 7 8 protected: 9 //thread entity pointer class 10 class Thread_Args{ 11 public: 12 //the pointer of allocating the space of new thread 13 Thread_Args(ACE_Server *lsp) : ls(lsp){} 14 ACE_Server *ls; 15 ACE_SOCK_Stream peer; 16 }; 17 18 virtual int handle_connections(); 19 virtual int handle_data(ACE_SOCK_Stream* arg = 0); 20 int block_recv(ACE_SOCK_Stream* peer, char* recv_buf, size_t len); 21 void ACE_Server::getTime(char* result); 22 void ACE_Server::getLocalIp(char* result); 23 void getCalc(int param, char* result, int count, char* re_buf); 24 static ACE_THR_FUNC_RETURN thread_run(void *arg); 25 26 private: 27 ACE_SOCK_Acceptor acceptor; 28 ACE_INET_Addr server_addr; 29 30 //request catch size 31 static const int MAX_BUF = 2048; 32 //response catch size 33 static const int MAX_RESULT = 64; 34 //network port 35 static const int port = 20120; 36 };
定义好数据结构后,就可以实现具体的逻辑实现了:
1 #include "ACE_Server.h" 2 #include "ace/Thread_Manager.h" 3 #include "ace/Auto_Ptr.h" 4 5 int ACE_Server::run_svc(){ 6 7 printf("ACE_Server has been initialized.\n"); 8 if (server_addr.set(port) == -1) 9 { 10 printf("It is failed to set %d.\n", port); 11 return -1; 12 } 13 14 printf("It is listening the port 20120...\n"); 15 16 if (acceptor.open(server_addr) == -1) 17 { 18 printf("It is failed to open the acceptor.\n"); 19 return -1; 20 } 21 22 for(;;){ 23 if(handle_connections() == -1) 24 return -1; 25 } 26 return acceptor.close(); 27 } 28 29 ACE_THR_FUNC_RETURN ACE_Server::thread_run(void *arg) 30 { 31 32 auto_ptr<Thread_Args> thread_args(static_cast<Thread_Args *>(arg)); 33 34 if (thread_args->ls->handle_data(&(thread_args->peer)) == -1) 35 { 36 printf("It is failed to handle the data.\n"); 37 } 38 thread_args->peer.close(); 39 return 0; 40 } 41 42 int ACE_Server::handle_connections(){ 43 auto_ptr<Thread_Args> thread_args (new Thread_Args(this)); 44 if (acceptor.accept(thread_args->peer) == -1) 45 { 46 printf("It is failed to get the input stream.\n"); 47 return -1; 48 } 49 //the core of allocating the sub thread 50 if(ACE_Thread_Manager::instance()->spawn( 51 ACE_Server::thread_run,//run the thread_run() upon every sub thread 52 static_cast<void *> (thread_args.get()), 53 THR_DETACHED | THR_SCOPE_SYSTEM) == -1) 54 { 55 return -1; 56 } 57 //It is not necessary to wait for all of sub_threads exiting. 58 //ACE_Thread_Manager::instance()->wait(); 59 //It is necessary to release the pointer binding with thread_run(). 60 thread_args.release(); 61 return 0; 62 } 63 64 int ACE_Server::block_recv(ACE_SOCK_Stream* peer, char* recv_buf, size_t len) 65 { 66 int recvd_size = 0; 67 if (recv_buf != NULL && len > 0) 68 { 69 if((recvd_size = peer->recv(recv_buf, len, 0)) == -1) 70 printf("It is failed to receive data...\n"); 71 } 72 return recvd_size; 73 } 74 75 void ACE_Server::getTime(char* result){ 76 if (result != NULL) 77 { 78 time_t t = time(0); 79 strftime(result, MAX_RESULT, "%Y-%m-%d\n", localtime(&t)); 80 } 81 } 82 83 void ACE_Server::getLocalIp(char* result){ 84 if (result != NULL){ 85 char szhostname[32]; 86 std::string addr = ""; 87 int size = 0; 88 if(gethostname(szhostname,sizeof(szhostname))==0) 89 { 90 struct hostent* pHost; 91 pHost = gethostbyname(szhostname); 92 addr = inet_ntoa(*(struct in_addr*)pHost-> h_addr_list[0]); 93 size = addr.length(); 94 } 95 96 if (size < MAX_RESULT) 97 strncpy(result, addr.c_str(), addr.length()); 98 else 99 printf("Result is overflow."); 100 101 } 102 } 103 104 void ACE_Server::getCalc(int begin, char* result, int length, char* re_buf){ 105 int sum = 0; 106 std::string value = ""; 107 bool isValue = false; 108 if (result != NULL && re_buf != NULL && begin < length) 109 { 110 for (int i = begin; i < length && re_buf[i] != ' '; i++) 111 { 112 if (re_buf[i] == '=') 113 { 114 isValue = true; 115 continue; 116 } 117 else if (re_buf[i] == '&') 118 { 119 isValue = false; 120 sum += atoi(value.c_str()); 121 value = ""; 122 } 123 if (isValue) 124 { 125 value += re_buf[i]; 126 } 127 } 128 sum += atoi(value.c_str()); 129 value = ""; 130 } 131 sprintf(result, "%d", sum); 132 } 133 134 int ACE_Server::handle_data(ACE_SOCK_Stream * peer) 135 { 136 char* re_buf = new char[MAX_BUF]; 137 char* result = new char[MAX_RESULT]; 138 memset(re_buf, 0, MAX_BUF); 139 memset(result, 0, MAX_RESULT); 140 141 int params = 0; 142 std::string querys = ""; 143 144 peer->disable(ACE_NONBLOCK); 145 peer->get_remote_addr(server_addr); 146 147 printf("The client ip address is: %s\n", server_addr.get_host_addr()); 148 printf("The client port is: %d\n", server_addr.get_port_number()); 149 150 int count = block_recv(peer, re_buf, MAX_BUF); 151 printf("The size of receiving data is %d\n", count); 152 153 for(int i = 5; i < count && re_buf[i] != ' '; i++){ 154 if (re_buf[i] == '?') 155 { 156 params = i + 1; 157 continue; 158 } 159 if (params == 0) 160 { 161 querys += re_buf[i]; 162 } 163 } 164 if (strcmp(querys.c_str(), "at") == 0) 165 { 166 getTime(result); 167 } 168 else if(strcmp(querys.c_str(), "ip") == 0) 169 { 170 getLocalIp(result); 171 } 172 else if(strcmp(querys.c_str(), "calc") == 0) 173 { 174 getCalc(params, result, count, re_buf); 175 } 176 else if(strcmp(querys.c_str(), "json") == 0) 177 { 178 iovec iov[2]; 179 iov[0].iov_base = (char*)"HTTP/1.1 200 OK\n"; 180 iov[0].iov_len = strlen("HTTP/1.1 200 OK\n"); 181 182 std::string json = "[{\"title\":\"flowers\",\"desc\":\"the beautiful flowers.\"}]"; 183 memcpy(result, (char*)json.c_str(), json.length()+1); 184 iov[1].iov_base = (char*)json.c_str(); 185 iov[1].iov_len = json.length(); 186 187 if (peer->sendv_n(iov, 2) == -1) 188 { 189 printf("It is failed to response 200 error.\n"); 190 return -1; 191 } 192 if (peer->send_n(result, MAX_RESULT) == -1) 193 { 194 printf("It is failed to send the result.\n"); 195 } 196 } 197 else{ 198 iovec iov[1]; 199 iov[0].iov_base = (char*)"HTTP/1.1 404\n"; 200 iov[0].iov_len = strlen("HTTP/1.1 404\n"); 201 if (peer->sendv_n(iov, 1) == -1) 202 { 203 printf("It is failed to response 404 error.\n"); 204 return -1; 205 } 206 printf("The wrong query:: %s\n", re_buf); 207 } 208 printf(result); 209 printf("\n-----------------------------------------------\n"); 210 if (peer->send_n(result, MAX_RESULT) == -1) 211 { 212 printf("It is failed to send the result.\n"); 213 } 214 215 delete [] re_buf; 216 delete [] result; 217 re_buf = nullptr; 218 result = nullptr; 219 220 return 0; 221 } 222 223 int main(int argc, char *argv[]){ 224 ACE_Server server; 225 if(server.run_svc() == -1) 226 printf("It is failed to run the ACE_Server.\n"); 227 return 0; 228 }
程序运行比较简单,只要在地址栏中输入端口号+关键词即可。
如获得客户端ip地址:
服务器获得如下结果:
小结:
ACE目前在工业界运用广泛,本文只是对ACE的多线程使用的一个简单实现,更多功能仍需探索和学习。
以后如有更多关于ACE的个人理解,会积极和大家分享。