├── .gitignore ├── CmakeLists.txt ├── LICENSE ├── README.md ├── README_cn.md ├── src ├── opensocket.cpp ├── opensocket.h ├── socket_os.c ├── socket_os.h ├── wepoll.c └── wepoll.h └── test ├── helloworld.cpp ├── httpclient.cpp ├── httpserver.cpp ├── open ├── openthread.cpp └── openthread.h ├── server.cpp ├── udp.cpp └── worker.h /.gitignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /CmakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | CMAKE_MINIMUM_REQUIRED(VERSION 3.12.1) 3 | PROJECT(opensocket) 4 | 5 | include_directories(src) 6 | include_directories(test) 7 | 8 | if(CMAKE_SYSTEM_NAME MATCHES "Windows") 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") 10 | else() 11 | link_libraries(pthread) 12 | endif() 13 | 14 | 15 | set(SRC 16 | src/wepoll.h 17 | src/wepoll.c 18 | src/socket_os.h 19 | src/socket_os.c 20 | src/opensocket.h 21 | src/opensocket.cpp 22 | 23 | test/worker.h 24 | test/open/openthread.h 25 | test/open/openthread.cpp 26 | ) 27 | 28 | add_executable(helloworld ${SRC} test/helloworld.cpp) 29 | add_executable(httpclient ${SRC} test/httpclient.cpp) 30 | add_executable(httpserver ${SRC} test/httpserver.cpp) 31 | add_executable(server ${SRC} test/server.cpp) 32 | #add_executable(udp ${SRC} test/udp.cpp) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenSocket 2 | OpenSocket is a super simple and easy-to-use cross-platform high-performance network concurrency library. 3 | 4 | **Linux and Android use epoll, iOS and Mac use kqueue, Windows use IOCP(wepoll).other systems use select.** 5 | 6 | Combined with OpenThread, you can easily build high-performance concurrent servers on any platform (including mobile platforms). 7 | 8 | OpenSocket is designed for all platforms with no other dependencies and only 4 source files, making it easy for beginners to play with C++ high-performance network concurrency development. 9 | 10 | **The OpenLinyou project designs a cross-platform server framework. Write code in VS or XCode and run it on Linux without any changes, even on Android and iOS.** 11 | OpenLinyou:https://github.com/openlinyou 12 | OpenThread:https://github.com/openlinyou/openthread 13 | https://gitee.com/linyouhappy/openthread 14 | 15 | ## Cross-platform support 16 | Linux and Android use epoll, iOS and Mac use kqueue, Windows use IOCP(wepoll).other systems use select. 17 | 18 | ## Compilation and execution 19 | Please install the cmake tool. With cmake you can build a VS or XCode project and compile and run it on VS or XCode. 20 | Source code:https://github.com/openlinyou/opensocket 21 | ``` 22 | # Clone the project 23 | git clone https://github.com/openlinyou/opensocket 24 | cd ./opensocket 25 | # Create a build project directory 26 | mkdir build 27 | cd build 28 | cmake .. 29 | # If it's win32, opensocket.sln will appear in this directory. Click it to start VS for coding and debugging. 30 | make 31 | ./helloworld 32 | ./httpclient 33 | ./httpserver 34 | # Visit with browser: http://127.0.0.1:8888 35 | ./server 36 | ``` 37 | 38 | ## All source files 39 | + src/socket_os.h 40 | + src/socket_os.c 41 | + src/opensocket.h 42 | + src/opensocket.cpp 43 | + src/wepoll.h(only win32) 44 | + src/wepoll.c(only win32) 45 | 46 | ## Technical features 47 | The technical features of OpenSocket: 48 | 1. Cross-platform design, providing a unified socket interface for Linux, supporting Android and iOS. 49 | 2. Linux and Android use epoll, iOS and Mac use kqueue, Windows use IOCP(wepoll).other systems use select. 50 | 3. Supports IPv6, small and miniaturized; used with OpenThread to easily build an Actor Model framework. 51 | 52 | 53 | ## 1.Helloworld 54 | Using OpenThread can achieve three major modes of multithreading: Await mode, Factory mode and Actor mode. Design this demo using Actor mode. 55 | ```C++ 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include "opensocket.h" 61 | #include "open/openthread.h" 62 | using namespace open; 63 | 64 | const std::string TestServerIp_ = "0.0.0.0"; 65 | const std::string TestClientIp_ = "127.0.0.1"; 66 | const int TestServerPort_ = 8888; 67 | OpenSocket openSocket_; 68 | 69 | struct ProtoBuffer 70 | { 71 | bool isSocket_; 72 | int acceptFd_; 73 | std::string addr_; 74 | std::shared_ptr data_; 75 | ProtoBuffer() : 76 | isSocket_(0), acceptFd_(0) {} 77 | }; 78 | 79 | static void SocketFunc(const OpenSocketMsg* msg) 80 | { 81 | if (!msg) return; 82 | if (msg->uid_ < 0) 83 | { 84 | delete msg; return; 85 | } 86 | auto proto = std::shared_ptr(new ProtoBuffer); 87 | proto->isSocket_ = true; 88 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 89 | bool ret = OpenThread::Send((int)msg->uid_, proto); 90 | if (!ret) 91 | { 92 | printf("SocketFunc dispatch faild pid = %lld\n", msg->uid_); 93 | } 94 | } 95 | 96 | // Listen 97 | static int listen_fd_ = 0; 98 | void ListenThread(OpenThreadMsg& msg) 99 | { 100 | int pid = msg.pid(); 101 | auto& pname = msg.name(); 102 | assert(pname == "listen"); 103 | if (msg.state_ == OpenThread::START) 104 | { 105 | while (OpenThread::ThreadId("accept") < 0) OpenThread::Sleep(100); 106 | listen_fd_ = openSocket_.listen((uintptr_t)pid, TestServerIp_, TestServerPort_, 64); 107 | if (listen_fd_ < 0) 108 | { 109 | printf("Listen::START faild listen_fd_ = %d\n", listen_fd_); 110 | assert(false); 111 | } 112 | openSocket_.start((uintptr_t)pid, listen_fd_); 113 | } 114 | else if (msg.state_ == OpenThread::RUN) 115 | { 116 | const ProtoBuffer* proto = msg.data(); 117 | if (!proto || !proto->isSocket_ || !proto->data_) return; 118 | auto& socketMsg = proto->data_; 119 | switch (socketMsg->type_) 120 | { 121 | case OpenSocket::ESocketAccept: 122 | { 123 | printf("Listen::RUN [%s]ESocketAccept: new client. acceptFd:%d, client:%s\n", pname.c_str(), socketMsg->ud_, socketMsg->info()); 124 | auto proto = std::shared_ptr(new ProtoBuffer); 125 | proto->addr_ = socketMsg->info(); 126 | proto->isSocket_ = false; 127 | proto->acceptFd_ = socketMsg->ud_; 128 | bool ret = OpenThread::Send("accept", proto); 129 | assert(ret); 130 | } 131 | break; 132 | case OpenSocket::ESocketClose: 133 | printf("Listen::RUN [%s]ESocketClose:linten close, listenFd:%d\n", pname.c_str(), socketMsg->fd_); 134 | break; 135 | case OpenSocket::ESocketError: 136 | printf("Listen::RUN [%s]ESocketError:%s\n", pname.c_str(), socketMsg->info()); 137 | break; 138 | case OpenSocket::ESocketWarning: 139 | printf("Listen::RUN [%s]ESocketWarning:%s\n", pname.c_str(), socketMsg->info()); 140 | break; 141 | case OpenSocket::ESocketOpen: 142 | printf("Listen::RUN [%s]ESocketOpen:linten open, listenFd:%d\n", pname.c_str(), socketMsg->fd_); 143 | break; 144 | case OpenSocket::ESocketUdp: 145 | case OpenSocket::ESocketData: 146 | assert(false); 147 | break; 148 | default: 149 | break; 150 | } 151 | } 152 | else if (msg.state_ == OpenThread::STOP) 153 | { 154 | openSocket_.close(pid, listen_fd_); 155 | } 156 | } 157 | 158 | // Accept 159 | void AcceptThread(OpenThreadMsg& msg) 160 | { 161 | int pid = msg.pid(); 162 | auto& pname = msg.name(); 163 | assert(pname == "accept"); 164 | if (msg.state_ == OpenThread::START) 165 | { 166 | } 167 | else if (msg.state_ == OpenThread::RUN) 168 | { 169 | const ProtoBuffer* proto = msg.data(); 170 | if (!proto) return; 171 | if (!proto->isSocket_) 172 | { 173 | printf("Accept::RUN [%s]open accept client:%s\n", pname.c_str(), proto->addr_.c_str()); 174 | openSocket_.start(pid, proto->acceptFd_); 175 | } 176 | else 177 | { 178 | if (!proto->data_) return; 179 | auto& socketMsg = proto->data_; 180 | switch (socketMsg->type_) 181 | { 182 | case OpenSocket::ESocketData: 183 | { 184 | //recevie from client 185 | { 186 | auto size = socketMsg->size(); 187 | auto data = socketMsg->data(); 188 | assert(size >= 4); 189 | int len = *(int*)data; 190 | std::string buffer; 191 | buffer.append(data + 4, len); 192 | assert(buffer == "Waiting for you!"); 193 | } 194 | 195 | //response to client 196 | { 197 | char buffer[256] = { 0 }; 198 | std::string tmp = "Of Course,I Still Love You!"; 199 | *(int*)buffer = (int)tmp.size(); 200 | memcpy(buffer + 4, tmp.data(), tmp.size()); 201 | openSocket_.send(socketMsg->fd_, buffer, (int)(4 + tmp.size())); 202 | } 203 | } 204 | break; 205 | case OpenSocket::ESocketOpen: 206 | printf("Accept::RUN [%s]ESocketClose:accept client open, acceptFd:%d\n", pname.c_str(), socketMsg->fd_); 207 | break; 208 | case OpenSocket::ESocketClose: 209 | printf("Accept::RUN [%s]ESocketClose:accept client close, acceptFd:%d\n", pname.c_str(), socketMsg->fd_); 210 | break; 211 | case OpenSocket::ESocketError: 212 | printf("Accept::RUN [%s]ESocketError:accept client %s\n", pname.c_str(), socketMsg->info()); 213 | break; 214 | case OpenSocket::ESocketWarning: 215 | printf("Accept::RUN [%s]ESocketWarning:%s\n", pname.c_str(), socketMsg->info()); 216 | break; 217 | case OpenSocket::ESocketAccept: 218 | case OpenSocket::ESocketUdp: 219 | assert(false); 220 | break; 221 | default: 222 | break; 223 | } 224 | } 225 | } 226 | } 227 | //client 228 | static int client_fd_ = 0; 229 | void ClientThread(OpenThreadMsg& msg) 230 | { 231 | int pid = msg.pid(); 232 | auto& pname = msg.name(); 233 | assert(pname == "client"); 234 | if (msg.state_ == OpenThread::START) 235 | { 236 | while (OpenThread::ThreadId("accept") < 0) OpenThread::Sleep(100); 237 | client_fd_ = openSocket_.connect(pid, TestClientIp_, TestServerPort_); 238 | } 239 | else if (msg.state_ == OpenThread::RUN) 240 | { 241 | const ProtoBuffer* proto = msg.data(); 242 | if (!proto || !proto->isSocket_ || !proto->data_) return; 243 | auto& socketMsg = proto->data_; 244 | switch (socketMsg->type_) 245 | { 246 | case OpenSocket::ESocketData: 247 | { 248 | //recevie from client 249 | auto size = socketMsg->size(); 250 | auto data = socketMsg->data(); 251 | assert(size >= 4); 252 | int len = *(int*)data; 253 | std::string buffer; 254 | buffer.append(data + 4, len); 255 | assert(buffer == "Of Course,I Still Love You!"); 256 | openSocket_.close(pid, socketMsg->fd_); 257 | OpenThread::StopAll(); 258 | } 259 | break; 260 | case OpenSocket::ESocketOpen: 261 | { 262 | assert(client_fd_ == socketMsg->fd_); 263 | printf("Client::RUN [%s]ESocketClose:Client client open, clientFd:%d\n", pname.c_str(), socketMsg->fd_); 264 | char buffer[256] = {0}; 265 | std::string tmp = "Waiting for you!"; 266 | *(int*)buffer = (int)tmp.size(); 267 | memcpy(buffer + 4, tmp.data(), tmp.size()); 268 | openSocket_.send(client_fd_, buffer, (int)(4 + tmp.size())); 269 | } 270 | break; 271 | case OpenSocket::ESocketClose: 272 | printf("Client::RUN [%s]ESocketClose:Client client close, clientFd:%d\n", pname.c_str(), socketMsg->fd_); 273 | break; 274 | case OpenSocket::ESocketError: 275 | printf("Client::RUN [%s]ESocketError:Client client %s\n", pname.c_str(), socketMsg->info()); 276 | break; 277 | case OpenSocket::ESocketWarning: 278 | printf("Client::RUN [%s]ESocketWarning:Client %s\n", pname.c_str(), socketMsg->info()); 279 | break; 280 | case OpenSocket::ESocketAccept: 281 | case OpenSocket::ESocketUdp: 282 | assert(false); 283 | break; 284 | default: 285 | break; 286 | } 287 | } 288 | } 289 | int main() 290 | { 291 | // create and start thread 292 | OpenThread::Create("listen", ListenThread); 293 | OpenThread::Create("accept", AcceptThread); 294 | OpenThread::Create("client", ClientThread); 295 | // run OpenSocket 296 | openSocket_.run(SocketFunc); 297 | OpenThread::ThreadJoinAll(); 298 | printf("Pause\n"); 299 | return getchar(); 300 | } 301 | 302 | ``` 303 | 304 | ## 2.HttpClient 305 | Designing a high-concurrency HttpClient using OpenThread’s Worker mode. 306 | ```C++ 307 | #include 308 | #include 309 | #include 310 | #include 311 | #include 312 | #include "open/openthread.h" 313 | #include "opensocket.h" 314 | using namespace open; 315 | 316 | ////////////HttpRequest////////////////////// 317 | class HttpRequest 318 | { 319 | std::string url_; 320 | public: 321 | std::map headers_; 322 | int port_; 323 | std::string host_; 324 | std::string ip_; 325 | std::string path_; 326 | std::string method_; 327 | std::string body_; 328 | HttpRequest() :port_(80) {} 329 | std::string& operator[](const std::string& key) { return headers_[key]; } 330 | void setUrl(const std::string& url); 331 | inline void operator=(const std::string& url) { setUrl(url); } 332 | 333 | struct HttpResponse 334 | { 335 | int code_; 336 | int clen_; 337 | std::string head_; 338 | std::string body_; 339 | //std::multimap headers_; 340 | std::map headers_; 341 | std::string& operator[](const std::string& key) { return headers_[key]; } 342 | 343 | HttpResponse():code_(0), clen_(0) {} 344 | void parseHeader(); 345 | bool pushData(const char* data, size_t size); 346 | }; 347 | HttpResponse response_; 348 | OpenSync openSync_; 349 | }; 350 | 351 | ////////////Proto////////////////////// 352 | struct SocketProto : public OpenThreadProto 353 | { 354 | std::shared_ptr data_; 355 | static inline int ProtoType() { return 1; } 356 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 357 | }; 358 | 359 | struct TaskProto : public OpenThreadProto 360 | { 361 | int fd_; 362 | OpenSync openSync_; 363 | std::shared_ptr request_; 364 | static inline int ProtoType() { return 2; } 365 | virtual inline int protoType() const { return TaskProto::ProtoType(); } 366 | TaskProto() :fd_(0) {} 367 | }; 368 | 369 | ////////////App////////////////////// 370 | class App 371 | { 372 | static void SocketFunc(const OpenSocketMsg* msg) 373 | { 374 | if (!msg) return; 375 | if (msg->uid_ >= 0) 376 | { 377 | auto proto = std::shared_ptr(new SocketProto); 378 | proto->srcPid_ = -1; 379 | proto->srcName_ = "OpenSocket"; 380 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 381 | if (!OpenThread::Send((int)msg->uid_, proto)) 382 | printf("SocketFunc dispatch faild pid = %lld\n", msg->uid_); 383 | } 384 | else delete msg; 385 | } 386 | public: 387 | static App Instance_; 388 | OpenSocket openSocket_; 389 | App() { openSocket_.run(App::SocketFunc); } 390 | }; 391 | App App::Instance_; 392 | 393 | 394 | ////////////HttpClient////////////////////// 395 | class HttpClient : public OpenThreadWorker 396 | { 397 | //Factory 398 | class Factory 399 | { 400 | const std::vector vectWorker_; 401 | public: 402 | Factory() 403 | :vectWorker_({ 404 | new HttpClient("HttpClient1"), 405 | new HttpClient("HttpClient2"), 406 | new HttpClient("HttpClient3"), 407 | new HttpClient("HttpClient4"), 408 | }) {} 409 | HttpClient* getWorker() 410 | { 411 | if (vectWorker_.empty()) return 0; 412 | return vectWorker_[std::rand() % vectWorker_.size()]; 413 | } 414 | }; 415 | static Factory Instance_; 416 | 417 | // HttpClient 418 | HttpClient(const std::string& name) 419 | :OpenThreadWorker(name) 420 | { 421 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&HttpClient::onSocketProto); 422 | registers(TaskProto::ProtoType(), (OpenThreadHandle)&HttpClient::onTaskProto); 423 | start(); 424 | } 425 | ~HttpClient() 426 | { 427 | for (auto iter = mapFdToTask_.begin(); iter != mapFdToTask_.end(); iter++) 428 | iter->second.openSync_.wakeup(); 429 | } 430 | 431 | private: 432 | void onTaskProto(TaskProto& proto) 433 | { 434 | auto& request = proto.request_; 435 | proto.fd_ = App::Instance_.openSocket_.connect(pid(), request->ip_, request->port_); 436 | request->response_.code_ = -1; 437 | request->response_.head_.clear(); 438 | request->response_.body_.clear(); 439 | mapFdToTask_[proto.fd_] = proto; 440 | } 441 | void onSendHttp(const std::shared_ptr& data) 442 | { 443 | auto iter = mapFdToTask_.find(data->fd_); 444 | if (iter == mapFdToTask_.end()) 445 | { 446 | App::Instance_.openSocket_.close(pid(), data->fd_); 447 | return; 448 | } 449 | auto& task = iter->second; 450 | auto& request = task.request_; 451 | std::string buffer = request->method_ + " " + request->path_ + " HTTP/1.1 \r\n"; 452 | auto iter1 = request->headers_.begin(); 453 | for (; iter1 != request->headers_.end(); iter1++) 454 | { 455 | buffer.append(iter1->first + ": " + iter1->second + "\r\n"); 456 | } 457 | if (!request->body_.empty()) 458 | { 459 | buffer.append("Content-Length:" + std::to_string(request->body_.size()) + "\r\n\r\n"); 460 | buffer.append(request->body_); 461 | buffer.append("\r\n"); 462 | } 463 | else 464 | { 465 | buffer.append("\r\n"); 466 | } 467 | App::Instance_.openSocket_.send(task.fd_, buffer.data(), (int)buffer.size()); 468 | } 469 | void onReadHttp(const std::shared_ptr& data) 470 | { 471 | auto iter = mapFdToTask_.find(data->fd_); 472 | if (iter == mapFdToTask_.end()) 473 | { 474 | App::Instance_.openSocket_.close(pid(), data->fd_); 475 | return; 476 | } 477 | auto& task = iter->second; 478 | auto& response = task.request_->response_; 479 | if (response.pushData(data->data(), data->size())) 480 | { 481 | App::Instance_.openSocket_.close(pid(), data->fd_); 482 | } 483 | } 484 | void onCloseHttp(const std::shared_ptr& data) 485 | { 486 | auto iter = mapFdToTask_.find(data->fd_); 487 | if (iter != mapFdToTask_.end()) 488 | { 489 | iter->second.openSync_.wakeup(); 490 | mapFdToTask_.erase(iter); 491 | } 492 | } 493 | void onSocketProto(const SocketProto& proto) 494 | { 495 | const auto& msg = proto.data_; 496 | switch (msg->type_) 497 | { 498 | case OpenSocket::ESocketData: 499 | onReadHttp(msg); 500 | break; 501 | case OpenSocket::ESocketClose: 502 | onCloseHttp(msg); 503 | break; 504 | case OpenSocket::ESocketError: 505 | printf("[%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 506 | onCloseHttp(msg); 507 | break; 508 | case OpenSocket::ESocketWarning: 509 | printf("[%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 510 | break; 511 | case OpenSocket::ESocketOpen: 512 | onSendHttp(msg); 513 | break; 514 | case OpenSocket::ESocketAccept: 515 | case OpenSocket::ESocketUdp: 516 | assert(false); 517 | break; 518 | default: 519 | break; 520 | } 521 | } 522 | std::map mapFdToTask_; 523 | public: 524 | static bool Http(std::shared_ptr& request) 525 | { 526 | if (request->ip_.empty()) 527 | { 528 | assert(false); 529 | return false; 530 | } 531 | request->response_.code_ = -1; 532 | auto worker = Instance_.getWorker(); 533 | if (!worker) return false; 534 | auto proto = std::shared_ptr(new TaskProto); 535 | proto->request_ = request; 536 | bool ret = OpenThread::Send(worker->pid(), proto); 537 | assert(ret); 538 | proto->openSync_.await(); 539 | return ret; 540 | } 541 | }; 542 | HttpClient::Factory HttpClient::Instance_; 543 | 544 | int main() 545 | { 546 | auto request = std::shared_ptr(new HttpRequest); 547 | //Stock Market Latest Dragon and Tiger List 548 | request->setUrl("http://reportdocs.static.szse.cn/files/text/jy/jy230308.txt"); 549 | request->method_ = "GET"; 550 | 551 | (*request)["Host"] = "reportdocs.static.szse.cn"; 552 | (*request)["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"; 553 | (*request)["Accept-Encoding"] = "gzip,deflate"; 554 | (*request)["Accept-Language"] = "zh-CN,zh;q=0.9"; 555 | (*request)["Cache-Control"] = "max-age=0"; 556 | (*request)["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"; 557 | (*request)["Upgrade-Insecure-Requests"] = "1"; 558 | 559 | HttpClient::Http(request); 560 | auto& response = request->response_; 561 | printf("code:%d, header:%s\n", response.code_, response.head_.c_str()); 562 | return getchar(); 563 | } 564 | 565 | 566 | void HttpRequest::setUrl(const std::string& url) 567 | { 568 | if (url.empty()) return; 569 | url_ = url; 570 | int len = (int)url.length(); 571 | char* ptr = (char*)url.c_str(); 572 | if (len >= 8) 573 | { 574 | if (memcmp(ptr, "http://", strlen("http://")) == 0) 575 | ptr += strlen("http://"); 576 | else if (memcmp(ptr, "https://", strlen("https://")) == 0) 577 | ptr += strlen("https://"); 578 | } 579 | const char* tmp = strstr(ptr, "/"); 580 | path_.clear(); 581 | if (tmp != 0) 582 | { 583 | path_.append(tmp); 584 | host_.clear(); 585 | host_.append(ptr, tmp - ptr); 586 | } 587 | else 588 | { 589 | host_ = ptr; 590 | } 591 | port_ = 80; 592 | ip_.clear(); 593 | ptr = (char*)host_.c_str(); 594 | tmp = strstr(ptr, ":"); 595 | if (tmp != 0) 596 | { 597 | ip_.append(ptr, tmp - ptr); 598 | tmp += 1; 599 | port_ = atoi(tmp); 600 | } 601 | else 602 | { 603 | ip_ = ptr; 604 | } 605 | ip_ = OpenSocket::DomainNameToIp(ip_); 606 | } 607 | 608 | 609 | void HttpRequest::HttpResponse::parseHeader() 610 | { 611 | if (!headers_.empty() || head_.size() < 12) return; 612 | std::string line; 613 | const char* ptr = strstr(head_.c_str(), "\r\n"); 614 | if (!ptr) return; 615 | code_ = 0; 616 | clen_ = 0; 617 | line.append(head_.c_str(), ptr - head_.c_str()); 618 | for (size_t i = 0; i < line.size(); i++) 619 | { 620 | if (line[i] == ' ') 621 | { 622 | while (i < line.size() && line[i] == ' ') ++i; 623 | code_ = std::atoi(line.data() + i); 624 | break; 625 | } 626 | } 627 | if (code_ <= 0) return; 628 | line.clear(); 629 | int k = -1; 630 | int j = -1; 631 | std::string key; 632 | std::string value; 633 | for (size_t i = ptr - head_.c_str() + 2; i < head_.size() - 1; i++) 634 | { 635 | if (head_[i] == '\r' && head_[i + 1] == '\n') 636 | { 637 | if (j > 0) 638 | { 639 | k = 0; 640 | while (k < line.size() && line[k] == ' ') ++k; 641 | while (k >= 0 && line.back() == ' ') line.pop_back(); 642 | value = line.data() + j + 1; 643 | while (j >= 0 && line[j] == ' ') j--; 644 | key.clear(); 645 | key.append(line.data(), j); 646 | for (size_t x = 0; x < key.size(); x++) 647 | key[x] = std::tolower(key[x]); 648 | headers_[key] = value; 649 | } 650 | ++i; 651 | j = -1; 652 | line.clear(); 653 | continue; 654 | } 655 | line.push_back(head_[i]); 656 | if (j < 0 && line.back() == ':') 657 | { 658 | j = (int)line.size() - 1; 659 | } 660 | } 661 | clen_ = std::atoi(headers_["content-length"].c_str()); 662 | } 663 | 664 | bool HttpRequest::HttpResponse::pushData(const char* data, size_t size) 665 | { 666 | if (code_ == -1) 667 | { 668 | head_.append(data, size); 669 | const char* ptr = strstr(head_.data(), "\r\n\r\n"); 670 | if (!ptr) return false; 671 | code_ = 0; 672 | body_.append(ptr + 4); 673 | head_.resize(ptr - head_.data() + 2); 674 | parseHeader(); 675 | } 676 | else 677 | { 678 | body_.append(data, size); 679 | } 680 | if (clen_ > 0) 681 | { 682 | if (clen_ >= body_.size()) 683 | { 684 | body_.resize(clen_); 685 | return true; 686 | } 687 | } 688 | else if (body_.size() > 2) 689 | { 690 | if (body_[body_.size() - 2] == '\r' && body_.back() == '\n') 691 | { 692 | body_.pop_back(); 693 | body_.pop_back(); 694 | return true; 695 | } 696 | } 697 | return false; 698 | } 699 | ``` 700 | 701 | ## 3.HttpServer 702 | Create 5 threads: 1 thread is encapsulated as a Listener and the other 4 threads are encapsulated as Accepters. 703 | 704 | The Listener is responsible for listening to socket connections. After listening to the socket, it sends the fd to one of the Accepters; After receiving the socket’s fd from the Listener, the Accepter opens the socket and connects with the client’s socket connection. 705 | 706 | After receiving an Http message from this simple Http server, it responds with an Http message and then closes the socket to complete an Http short connection operation. 707 | 708 | OpenSocket is a wrapper for poll; only one OpenSocket object needs to be created per process. Since Windows uses select scheme, number of sockets cannot exceed 64. 709 | 710 | ```C++ 711 | #include 712 | #include 713 | #include 714 | #include 715 | #include 716 | #include "opensocket.h" 717 | #include "open/openthread.h" 718 | using namespace open; 719 | 720 | const std::string TestServerIp_ = "0.0.0.0"; 721 | const int TestServerPort_ = 8888; 722 | 723 | //msgType == 1 724 | struct SocketProto : public OpenThreadProto 725 | { 726 | std::shared_ptr data_; 727 | static inline int ProtoType() { return 1; } 728 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 729 | }; 730 | 731 | //msgType == 2 732 | struct RegisterProto : public OpenThreadProto 733 | { 734 | int srcPid_; 735 | static inline int ProtoType() { return 2; } 736 | virtual inline int protoType() const { return RegisterProto::ProtoType(); } 737 | RegisterProto() :srcPid_(-1) {} 738 | }; 739 | 740 | //msgType == 3 741 | struct NewClientProto : public OpenThreadProto 742 | { 743 | int accept_fd_; 744 | std::string addr_; 745 | static inline int ProtoType() { return 3; } 746 | virtual inline int protoType() const { return NewClientProto::ProtoType(); } 747 | NewClientProto() : accept_fd_(-1) {} 748 | }; 749 | 750 | ////////////App////////////////////// 751 | class App 752 | { 753 | static void SocketFunc(const OpenSocketMsg* msg) 754 | { 755 | if (!msg) return; 756 | if (msg->uid_ >= 0) 757 | { 758 | auto proto = std::shared_ptr(new SocketProto); 759 | proto->srcPid_ = -1; 760 | proto->srcName_ = "OpenSocket"; 761 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 762 | if (!OpenThread::Send((int)msg->uid_, proto)) 763 | printf("SocketFunc dispatch faild pid = %lld\n", msg->uid_); 764 | } 765 | else 766 | { 767 | delete msg; 768 | } 769 | } 770 | public: 771 | static App Instance_; 772 | OpenSocket openSocket_; 773 | App() { openSocket_.run(App::SocketFunc); } 774 | }; 775 | App App::Instance_; 776 | 777 | ////////////Listener////////////////////// 778 | class Listener : public OpenThreadWorker 779 | { 780 | int listen_fd_; 781 | unsigned int balance_; 782 | std::set setSlaveId_; 783 | std::vector vectSlaveId_; 784 | public: 785 | Listener(const std::string& name) 786 | :OpenThreadWorker(name), 787 | listen_fd_(-1) 788 | { 789 | balance_ = 0; 790 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Listener::onSocketProto); 791 | registers(RegisterProto::ProtoType(), (OpenThreadHandle)&Listener::onRegisterProto); 792 | } 793 | virtual ~Listener() {} 794 | virtual void onStart() 795 | { 796 | listen_fd_ = App::Instance_.openSocket_.listen((uintptr_t)pid(), TestServerIp_, TestServerPort_, 64); 797 | if (listen_fd_ < 0) 798 | { 799 | printf("Listener::onStart faild listen_fd_ = %d\n", listen_fd_); 800 | assert(false); 801 | } 802 | App::Instance_.openSocket_.start((uintptr_t)pid(), listen_fd_); 803 | printf("HTTP: %s:%d\n", TestServerIp_.c_str(), TestServerPort_); 804 | } 805 | void onRegisterProto(const RegisterProto& proto) 806 | { 807 | if (proto.srcPid_ >= 0) 808 | { 809 | if (setSlaveId_.find(proto.srcPid_) == setSlaveId_.end()) 810 | { 811 | setSlaveId_.insert(proto.srcPid_); 812 | vectSlaveId_.push_back(proto.srcPid_); 813 | printf("Hello OpenSocket HttpServer, srcPid = %d\n", proto.srcPid_); 814 | } 815 | } 816 | } 817 | // new client socket dispatch to Accept 818 | void notifyToSlave(int accept_fd, const std::string& addr) 819 | { 820 | if (!vectSlaveId_.empty()) 821 | { 822 | auto proto = std::shared_ptr(new NewClientProto); 823 | proto->accept_fd_ = accept_fd; 824 | proto->addr_ = addr; 825 | if (balance_ >= vectSlaveId_.size()) 826 | { 827 | balance_ = 0; 828 | } 829 | int slaveId = vectSlaveId_[balance_++]; 830 | if (OpenThread::Send(slaveId, proto)) 831 | { 832 | return; 833 | } 834 | printf("Listener::notifyToSlave send faild pid = %d\n", slaveId); 835 | } 836 | App::Instance_.openSocket_.close(pid_, accept_fd); 837 | } 838 | void onSocketProto(const SocketProto& proto) 839 | { 840 | const auto& msg = proto.data_; 841 | switch (msg->type_) 842 | { 843 | case OpenSocket::ESocketAccept: 844 | // linsten new client socket 845 | notifyToSlave(msg->ud_, msg->data()); 846 | printf("Listener::onSocket [%s]ESocketAccept:acceptFd = %d\n", ThreadName((int)msg->uid_).c_str(), msg->ud_); 847 | break; 848 | case OpenSocket::ESocketClose: 849 | break; 850 | case OpenSocket::ESocketError: 851 | printf("Listener::onSocket [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 852 | break; 853 | case OpenSocket::ESocketWarning: 854 | printf("Listener::onSocket [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 855 | break; 856 | case OpenSocket::ESocketOpen: 857 | break; 858 | case OpenSocket::ESocketUdp: 859 | case OpenSocket::ESocketData: 860 | assert(false); 861 | break; 862 | default: 863 | break; 864 | } 865 | } 866 | }; 867 | 868 | ////////////HttpRequest////////////////////// 869 | struct HttpRequest 870 | { 871 | int fd_; 872 | std::string addr_; 873 | 874 | std::string method_; 875 | std::string url_; 876 | 877 | int code_; 878 | int clen_; 879 | std::string head_; 880 | std::string body_; 881 | std::map headers_; 882 | HttpRequest() :fd_(-1), code_(-1), clen_(-1) {} 883 | 884 | //GET /xx/xx HTTP/x.x 885 | bool parseHeader(); 886 | bool pushData(const char* data, size_t size); 887 | }; 888 | 889 | ////////////Accepter////////////////////// 890 | class Accepter : public OpenThreadWorker 891 | { 892 | int listenId_; 893 | std::map mapClient_; 894 | public: 895 | Accepter(const std::string& name) 896 | :OpenThreadWorker(name), 897 | listenId_(-1) 898 | { 899 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Accepter::onSocketProto); 900 | registers(NewClientProto::ProtoType(), (OpenThreadHandle)&Accepter::onNewClientProto); 901 | } 902 | virtual ~Accepter() {} 903 | virtual void onStart() 904 | { 905 | while (listenId_ < 0) 906 | { 907 | listenId_ = ThreadId("listener"); 908 | OpenThread::Sleep(1000); 909 | } 910 | auto proto = std::shared_ptr(new RegisterProto); 911 | proto->srcPid_ = pid(); 912 | if (OpenThread::Send(listenId_, proto)) 913 | return; 914 | printf("Accepter::onStart send faild pid = %d\n", listenId_); 915 | } 916 | void onNewClientProto(const NewClientProto& proto) 917 | { 918 | int accept_fd = proto.accept_fd_; 919 | if (accept_fd >= 0) 920 | { 921 | auto iter = mapClient_.find(accept_fd); 922 | if (iter != mapClient_.end()) 923 | { 924 | assert(false); 925 | mapClient_.erase(iter); 926 | App::Instance_.openSocket_.close(pid(), accept_fd); 927 | return; 928 | } 929 | auto& client = mapClient_[accept_fd]; 930 | client.fd_ = accept_fd; 931 | client.addr_ = proto.addr_; 932 | App::Instance_.openSocket_.start(pid_, accept_fd); 933 | } 934 | } 935 | //GET /xx/xx HTTP/x.x 936 | void onReadHttp(const std::shared_ptr msg) 937 | { 938 | auto iter = mapClient_.find(msg->fd_); 939 | if (iter == mapClient_.end()) 940 | { 941 | App::Instance_.openSocket_.close(pid_, msg->fd_); 942 | return; 943 | } 944 | auto& request = iter->second; 945 | if (!request.pushData(msg->data(), msg->size())) 946 | { 947 | //Header too large.close connet. 948 | if (request.head_.size() > 1024) 949 | App::Instance_.openSocket_.close(pid_, msg->fd_); 950 | return; 951 | } 952 | printf("new client:url = %s\n", request.url_.c_str()); 953 | std::string content; 954 | content.append("
It's work!

" + request.addr_ + "request:" + request.url_); 955 | std::string buffer = "HTTP/1.1 200 OK\r\ncontent-length:" + std::to_string(content.size()) + "\r\n\r\n" + content; 956 | App::Instance_.openSocket_.send(msg->fd_, buffer.data(), (int)buffer.size()); 957 | } 958 | virtual void onSocketProto(const SocketProto& proto) 959 | { 960 | const auto& msg = proto.data_; 961 | switch (msg->type_) 962 | { 963 | case OpenSocket::ESocketData: 964 | onReadHttp(msg); 965 | break; 966 | case OpenSocket::ESocketClose: 967 | mapClient_.erase(msg->fd_); 968 | break; 969 | case OpenSocket::ESocketError: 970 | mapClient_.erase(msg->fd_); 971 | printf("Accepter::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 972 | break; 973 | case OpenSocket::ESocketWarning: 974 | printf("Accepter::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 975 | break; 976 | case OpenSocket::ESocketOpen: 977 | { 978 | auto iter = mapClient_.find(msg->fd_); 979 | if (iter == mapClient_.end()) 980 | { 981 | App::Instance_.openSocket_.close(pid_, msg->fd_); 982 | return; 983 | } 984 | } 985 | break; 986 | case OpenSocket::ESocketAccept: 987 | case OpenSocket::ESocketUdp: 988 | assert(false); 989 | break; 990 | default: 991 | break; 992 | } 993 | } 994 | }; 995 | int main() 996 | { 997 | printf("start server==>>\n"); 998 | std::vector vectServer = { 999 | new Listener("listener"), 1000 | new Accepter("accepter1"), 1001 | new Accepter("accepter2"), 1002 | new Accepter("accepter3"), 1003 | new Accepter("accepter4") 1004 | }; 1005 | for (size_t i = 0; i < vectServer.size(); ++i) 1006 | vectServer[i]->start(); 1007 | 1008 | printf("wait close==>>\n"); 1009 | OpenThread::ThreadJoinAll(); 1010 | for (size_t i = 0; i < vectServer.size(); ++i) 1011 | delete vectServer[i]; 1012 | vectServer.clear(); 1013 | 1014 | printf("Pause\n"); 1015 | return getchar(); 1016 | } 1017 | 1018 | 1019 | bool HttpRequest::parseHeader() 1020 | { 1021 | if (!headers_.empty() || head_.size() < 12) return true; 1022 | std::string line; 1023 | const char* ptr = strstr(head_.c_str(), "\r\n"); 1024 | if (!ptr) return false; 1025 | clen_ = -1; 1026 | line.append(head_.c_str(), ptr - head_.c_str()); 1027 | 1028 | int state = 0; 1029 | method_.clear(); 1030 | url_.clear(); 1031 | for (size_t k = 0; k < line.size(); ++k) 1032 | { 1033 | if (state == 0) 1034 | { 1035 | if (line[k] != ' ') 1036 | { 1037 | method_.push_back(line[k]); 1038 | continue; 1039 | } 1040 | state = 1; 1041 | while (k < line.size() && line[k] == ' ') ++k; 1042 | if (line[k] != ' ') --k; 1043 | } 1044 | else 1045 | { 1046 | if (line[k] != ' ') 1047 | { 1048 | url_.push_back(line[k]); 1049 | continue; 1050 | } 1051 | break; 1052 | } 1053 | } 1054 | 1055 | line.clear(); 1056 | int k = -1; 1057 | int j = -1; 1058 | std::string key; 1059 | std::string value; 1060 | for (size_t i = ptr - head_.c_str() + 2; i < head_.size() - 1; i++) 1061 | { 1062 | if (head_[i] == '\r' && head_[i + 1] == '\n') 1063 | { 1064 | if (j > 0) 1065 | { 1066 | k = 0; 1067 | while (k < line.size() && line[k] == ' ') ++k; 1068 | while (k >= 0 && line.back() == ' ') line.pop_back(); 1069 | value = line.data() + j + 1; 1070 | while (j >= 0 && line[j] == ' ') j--; 1071 | key.clear(); 1072 | key.append(line.data(), j); 1073 | for (size_t x = 0; x < key.size(); x++) 1074 | key[x] = std::tolower(key[x]); 1075 | headers_[key] = value; 1076 | } 1077 | ++i; 1078 | j = -1; 1079 | line.clear(); 1080 | continue; 1081 | } 1082 | line.push_back(head_[i]); 1083 | if (j < 0 && line.back() == ':') 1084 | { 1085 | j = (int)line.size() - 1; 1086 | } 1087 | } 1088 | clen_ = std::atoi(headers_["content-length"].c_str()); 1089 | return true; 1090 | } 1091 | 1092 | bool HttpRequest::pushData(const char* data, size_t size) 1093 | { 1094 | if (code_ == -1) 1095 | { 1096 | head_.append(data, size); 1097 | const char* ptr = strstr(head_.data(), "\r\n\r\n"); 1098 | if (!ptr) return false; 1099 | code_ = 0; 1100 | body_.append(ptr + 4); 1101 | head_.resize(ptr - head_.data() + 2); 1102 | if (!parseHeader()) return false; 1103 | } 1104 | else 1105 | { 1106 | body_.append(data, size); 1107 | } 1108 | if (clen_ >= 0) 1109 | { 1110 | if (clen_ == 0 && clen_ == body_.size()) 1111 | { 1112 | return true; 1113 | } 1114 | if (clen_ >= body_.size()) 1115 | { 1116 | body_.resize(clen_); 1117 | return true; 1118 | } 1119 | } 1120 | else if (body_.size() > 2) 1121 | { 1122 | if (body_[body_.size() - 2] == '\r' && body_.back() == '\n') 1123 | { 1124 | body_.pop_back(); 1125 | body_.pop_back(); 1126 | return true; 1127 | } 1128 | } 1129 | return false; 1130 | } 1131 | ``` 1132 | 1133 | ## 4.Socket TCP communication 1134 | he Listener is responsible for listening to socket connection events and sending socket connection events to the Accepter. 1135 | 1136 | The Accepter is responsible for receiving socket connection events sent by the Listener and communicating with the socket. 1137 | 1138 | Client is a client cluster that can be used to perform stress tests on the server. 1139 | 1140 | ```C++ 1141 | #include 1142 | #include 1143 | #include 1144 | #include 1145 | #include 1146 | #include "opensocket.h" 1147 | #include "open/openthread.h" 1148 | using namespace open; 1149 | 1150 | const std::string TestServerIp_ = "0.0.0.0"; 1151 | const std::string TestClientIp_ = "127.0.0.1"; 1152 | const int TestServerPort_ = 8888; 1153 | 1154 | //proto 1155 | struct SocketProto : public OpenThreadProto 1156 | { 1157 | std::shared_ptr data_; 1158 | static inline int ProtoType() { return 1; } 1159 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 1160 | }; 1161 | 1162 | class ProtoBuffer : public OpenThreadProto 1163 | { 1164 | std::shared_ptr data_; 1165 | public: 1166 | int msgId_; 1167 | ProtoBuffer() 1168 | : OpenThreadProto() 1169 | , msgId_(0) 1170 | , data_(0) {} 1171 | virtual ~ProtoBuffer() {} 1172 | template 1173 | inline T& data() 1174 | { 1175 | T* t = 0; 1176 | if (data_) 1177 | { 1178 | t = dynamic_cast((T*)data_.get()); 1179 | if (data_.get() == t) return *t; 1180 | data_.reset(); 1181 | } 1182 | t = new T; 1183 | data_ = std::shared_ptr(t); 1184 | return *t; 1185 | } 1186 | template 1187 | inline T& data() const 1188 | { 1189 | if (data_) 1190 | { 1191 | T* t = dynamic_cast((T*)data_.get()); 1192 | if (data_.get() == t) return *t; 1193 | } 1194 | assert(false); 1195 | static T t; 1196 | return t; 1197 | } 1198 | static inline int ProtoType() { return (int)(uintptr_t) & (ProtoType); } 1199 | virtual inline int protoType() const { return ProtoBuffer::ProtoType(); } 1200 | }; 1201 | 1202 | ////////////App////////////////////// 1203 | class App 1204 | { 1205 | static void SocketFunc(const OpenSocketMsg* msg) 1206 | { 1207 | if (!msg) return; 1208 | if (msg->uid_ >= 0) 1209 | { 1210 | auto proto = std::shared_ptr(new SocketProto); 1211 | proto->srcPid_ = -1; 1212 | proto->srcName_ = "OpenSocket"; 1213 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 1214 | if (!OpenThread::Send((int)msg->uid_, proto)) 1215 | printf("SocketFunc dispatch faild pid = %lld\n", msg->uid_); 1216 | return; 1217 | } 1218 | delete msg; 1219 | } 1220 | public: 1221 | static App Instance_; 1222 | OpenSocket openSocket_; 1223 | App() { openSocket_.run(App::SocketFunc); } 1224 | }; 1225 | App App::Instance_; 1226 | 1227 | 1228 | enum EMsgId 1229 | { 1230 | new_accept, 1231 | new_client, 1232 | test_client 1233 | }; 1234 | 1235 | 1236 | ////////////Listener////////////////////// 1237 | struct DataNewClient 1238 | { 1239 | int accept_fd_; 1240 | std::string addr_; 1241 | DataNewClient() :accept_fd_(-1) {} 1242 | }; 1243 | class Listener : public OpenThreadWorker 1244 | { 1245 | std::set setSlaveId_; 1246 | std::vector vectSlaveId_; 1247 | int listen_fd_; 1248 | unsigned int balance_; 1249 | bool isOpening_; 1250 | public: 1251 | Listener(const std::string& name) 1252 | :OpenThreadWorker(name), 1253 | listen_fd_(-1) 1254 | { 1255 | isOpening_ = false; 1256 | balance_ = 0; 1257 | 1258 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Listener::onSocketProto); 1259 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Listener::onProtoBuffer); 1260 | } 1261 | virtual ~Listener() {} 1262 | virtual void onStart() 1263 | { 1264 | listen_fd_ = App::Instance_.openSocket_.listen((uintptr_t)pid(), TestServerIp_, TestServerPort_, 64); 1265 | if (listen_fd_ < 0) 1266 | { 1267 | printf("Listener::onStart faild listen_fd_ = %d\n", listen_fd_); 1268 | assert(false); 1269 | } 1270 | App::Instance_.openSocket_.start((uintptr_t)pid(), listen_fd_); 1271 | } 1272 | private: 1273 | void onProtoBuffer(const ProtoBuffer& proto) 1274 | { 1275 | if (proto.msgId_ == new_accept) 1276 | { 1277 | auto msg = proto.data(); 1278 | assert(msg == "listen success!"); 1279 | if (proto.srcPid() >= 0) 1280 | { 1281 | if (setSlaveId_.find(proto.srcPid()) == setSlaveId_.end()) 1282 | { 1283 | setSlaveId_.insert(proto.srcPid()); 1284 | vectSlaveId_.push_back(proto.srcPid()); 1285 | printf("Hello OpenSocket, srcPid = %d\n", proto.srcPid()); 1286 | } 1287 | } 1288 | } 1289 | } 1290 | void notify(int accept_fd, const std::string& addr) 1291 | { 1292 | if (!vectSlaveId_.empty()) 1293 | { 1294 | auto proto = std::shared_ptr(new ProtoBuffer); 1295 | proto->msgId_ = new_client; 1296 | auto& msg = proto->data(); 1297 | msg.accept_fd_ = accept_fd; 1298 | msg.addr_ = addr; 1299 | if (balance_ >= vectSlaveId_.size()) 1300 | { 1301 | balance_ = 0; 1302 | } 1303 | int slaveId = vectSlaveId_[balance_++]; 1304 | bool ret = send(slaveId, proto); 1305 | if (ret) return; 1306 | } 1307 | App::Instance_.openSocket_.close(pid_, accept_fd); 1308 | } 1309 | virtual void onSocketProto(const SocketProto& proto) 1310 | { 1311 | const auto msg = proto.data_; 1312 | switch (msg->type_) 1313 | { 1314 | case OpenSocket::ESocketAccept: 1315 | notify(msg->ud_, msg->data()); 1316 | printf("Listener::onStart [%s]ESocketAccept:acceptFd = %d\n", ThreadName((int)msg->uid_).c_str(), msg->ud_); 1317 | break; 1318 | case OpenSocket::ESocketClose: 1319 | isOpening_ = false; 1320 | break; 1321 | case OpenSocket::ESocketError: 1322 | printf("Listener::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1323 | break; 1324 | case OpenSocket::ESocketWarning: 1325 | printf("Listener::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1326 | break; 1327 | case OpenSocket::ESocketOpen: 1328 | isOpening_ = true; 1329 | break; 1330 | case OpenSocket::ESocketUdp: 1331 | case OpenSocket::ESocketData: 1332 | assert(false); 1333 | break; 1334 | default: 1335 | break; 1336 | } 1337 | } 1338 | }; 1339 | 1340 | ////////////Accepter////////////////////// 1341 | struct ServerClient 1342 | { 1343 | int fd_; 1344 | std::string addr_; 1345 | std::string buffer_; 1346 | ServerClient() :fd_(-1) {} 1347 | }; 1348 | class Accepter : public OpenThreadWorker 1349 | { 1350 | int listenId_; 1351 | std::map mapClient_; 1352 | public: 1353 | Accepter(const std::string& name) 1354 | :OpenThreadWorker(name), 1355 | listenId_(-1) 1356 | { 1357 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Accepter::onSocketProto); 1358 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Accepter::onProtoBuffer); 1359 | } 1360 | virtual ~Accepter() {} 1361 | 1362 | virtual void onStart() 1363 | { 1364 | while (listenId_ < 0) 1365 | { 1366 | listenId_ = ThreadId("listener"); 1367 | OpenThread::Sleep(1000); 1368 | } 1369 | auto root = std::shared_ptr(new ProtoBuffer); 1370 | root->msgId_ = new_accept; 1371 | auto& data = root->data(); 1372 | data = "listen success!"; 1373 | send(listenId_, root); 1374 | } 1375 | private: 1376 | void onProtoBuffer(const ProtoBuffer& proto) 1377 | { 1378 | if (proto.msgId_ == new_client) 1379 | { 1380 | auto msg = proto.data(); 1381 | int accept_fd = msg.accept_fd_; 1382 | if (accept_fd >= 0) 1383 | { 1384 | auto iter = mapClient_.find(accept_fd); 1385 | if (iter != mapClient_.end()) 1386 | { 1387 | assert(false); 1388 | mapClient_.erase(iter); 1389 | App::Instance_.openSocket_.close(pid(), accept_fd); 1390 | return; 1391 | } 1392 | 1393 | auto& client = mapClient_[accept_fd]; 1394 | client.fd_ = accept_fd; 1395 | client.addr_ = msg.addr_; 1396 | App::Instance_.openSocket_.start(pid_, accept_fd); 1397 | } 1398 | } 1399 | } 1400 | 1401 | void onRead(const std::shared_ptr& msg) 1402 | { 1403 | auto iter = mapClient_.find(msg->fd_); 1404 | if (iter == mapClient_.end()) 1405 | { 1406 | App::Instance_.openSocket_.close(pid_, msg->fd_); 1407 | return; 1408 | } 1409 | auto& client = iter->second; 1410 | client.buffer_.append(msg->data(), msg->size()); 1411 | auto& buffer = client.buffer_; 1412 | if (buffer.empty()) 1413 | return; 1414 | 1415 | std::string data = "[" + name_ + "]" + client.addr_ + ":" + buffer; 1416 | client.buffer_.clear(); 1417 | App::Instance_.openSocket_.send(client.fd_, data.data(), (int)data.size()); 1418 | } 1419 | 1420 | virtual void onSocketProto(const SocketProto& proto) 1421 | { 1422 | const auto msg = proto.data_; 1423 | switch (msg->type_) 1424 | { 1425 | case OpenSocket::ESocketData: 1426 | onRead(msg); 1427 | break; 1428 | case OpenSocket::ESocketClose: 1429 | mapClient_.erase(msg->fd_); 1430 | break; 1431 | case OpenSocket::ESocketError: 1432 | mapClient_.erase(msg->fd_); 1433 | printf("Accepter::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1434 | break; 1435 | case OpenSocket::ESocketWarning: 1436 | printf("Accepter::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1437 | break; 1438 | case OpenSocket::ESocketOpen: 1439 | { 1440 | auto iter = mapClient_.find(msg->fd_); 1441 | if (iter == mapClient_.end()) 1442 | { 1443 | App::Instance_.openSocket_.close(pid_, msg->fd_); 1444 | return; 1445 | } 1446 | } 1447 | break; 1448 | case OpenSocket::ESocketAccept: 1449 | case OpenSocket::ESocketUdp: 1450 | assert(false); 1451 | break; 1452 | default: 1453 | break; 1454 | } 1455 | } 1456 | }; 1457 | 1458 | struct TestMsg 1459 | { 1460 | int count_; 1461 | TestMsg() :count_(0) {} 1462 | }; 1463 | struct User 1464 | { 1465 | int fd_; 1466 | int userId_; 1467 | std::string buffer_; 1468 | }; 1469 | class Client : public OpenThreadWorker 1470 | { 1471 | std::map mapUser_; 1472 | public: 1473 | Client(const std::string& name) 1474 | :OpenThreadWorker(name) 1475 | { 1476 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Client::onSocketProto); 1477 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Client::onProtoBuffer); 1478 | } 1479 | virtual ~Client() {} 1480 | virtual void onStart() 1481 | { 1482 | } 1483 | private: 1484 | void onProtoBuffer(const ProtoBuffer& proto) 1485 | { 1486 | if (proto.msgId_ == test_client) 1487 | { 1488 | auto msg = proto.data(); 1489 | int count = msg.count_; 1490 | int fd = 0; 1491 | for (int i = 0; i < count; i++) 1492 | { 1493 | fd = App::Instance_.openSocket_.connect(pid_, TestClientIp_, TestServerPort_); 1494 | if (fd < 0) 1495 | { 1496 | printf("Client::start_test faild fd = %d\n", fd); 1497 | assert(0); 1498 | } 1499 | auto& user = mapUser_[fd]; 1500 | user.fd_ = fd; 1501 | user.userId_ = pid_ + i * 1000; 1502 | printf("Client::start_test[%s] fd = %d \n", name().c_str(), fd); 1503 | } 1504 | } 1505 | } 1506 | void onRead(const std::shared_ptr& msg) 1507 | { 1508 | auto iter = mapUser_.find(msg->fd_); 1509 | if (iter == mapUser_.end()) 1510 | { 1511 | App::Instance_.openSocket_.close(pid_, msg->fd_); 1512 | return; 1513 | } 1514 | auto& user = iter->second; 1515 | user.buffer_.append(msg->data(), msg->size()); 1516 | printf("Client::onRead[%s:%d]:%s\n", name().c_str(), user.userId_, user.buffer_.c_str()); 1517 | user.buffer_.clear(); 1518 | OpenSocket::Sleep(500); 1519 | std::string data = "Hello OpenSocket!"; 1520 | App::Instance_.openSocket_.send(user.fd_, data.data(), (int)data.size()); 1521 | } 1522 | virtual void onSocketProto(const SocketProto& proto) 1523 | { 1524 | const auto msg = proto.data_; 1525 | switch (msg->type_) 1526 | { 1527 | case OpenSocket::ESocketData: 1528 | onRead(msg); 1529 | break; 1530 | case OpenSocket::ESocketClose: 1531 | mapUser_.erase(msg->fd_); 1532 | break; 1533 | case OpenSocket::ESocketError: 1534 | mapUser_.erase(msg->fd_); 1535 | printf("Client::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1536 | break; 1537 | case OpenSocket::ESocketWarning: 1538 | printf("Client::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 1539 | break; 1540 | case OpenSocket::ESocketOpen: 1541 | { 1542 | auto iter = mapUser_.find(msg->fd_); 1543 | if (iter == mapUser_.end()) 1544 | { 1545 | App::Instance_.openSocket_.close(pid_, msg->fd_); 1546 | return; 1547 | } 1548 | std::string buffer = "Hello OpenSocket!"; 1549 | App::Instance_.openSocket_.send(msg->fd_, buffer.data(), (int)buffer.size()); 1550 | } 1551 | break; 1552 | case OpenSocket::ESocketAccept: 1553 | case OpenSocket::ESocketUdp: 1554 | assert(false); 1555 | break; 1556 | default: 1557 | break; 1558 | } 1559 | } 1560 | }; 1561 | 1562 | int main() 1563 | { 1564 | std::vector vectWorker; 1565 | 1566 | printf("start server==>>\n"); 1567 | //server 1568 | std::vector vectServer = 1569 | { 1570 | new Listener("listener"), 1571 | new Accepter("accepter1"), 1572 | new Accepter("accepter2"), 1573 | new Accepter("accepter3"), 1574 | new Accepter("accepter4") 1575 | }; 1576 | for (size_t i = 0; i < vectServer.size(); i++) 1577 | { 1578 | vectWorker.push_back(vectServer[i]); 1579 | vectServer[i]->start(); 1580 | } 1581 | 1582 | printf("slepp 3000 ms==>>\n"); 1583 | //wait server start. 1584 | OpenThread::Sleep(3000); 1585 | 1586 | printf("start client==>>\n"); 1587 | //client 1588 | std::vector vectClient = 1589 | { 1590 | new Client("client1"), 1591 | new Client("client2"), 1592 | new Client("client3"), 1593 | new Client("client4"), 1594 | }; 1595 | for (size_t i = 0; i < vectClient.size(); i++) 1596 | { 1597 | vectWorker.push_back(vectClient[i]); 1598 | vectClient[i]->start(); 1599 | } 1600 | 1601 | auto proto = std::shared_ptr(new ProtoBuffer); 1602 | proto->msgId_ = test_client; 1603 | auto& data = proto->data(); 1604 | data.count_ = 10; 1605 | // 1606 | for (size_t i = 0; i < vectClient.size(); i++) 1607 | { 1608 | vectClient[i]->send(vectClient[i]->pid(), proto); 1609 | } 1610 | 1611 | printf("wait close==>>\n"); 1612 | //wait all worker 1613 | OpenThread::ThreadJoinAll(); 1614 | for (size_t i = 0; i < vectWorker.size(); i++) 1615 | { 1616 | delete vectWorker[i]; 1617 | } 1618 | vectWorker.clear(); 1619 | printf("Pause\n"); 1620 | return getchar(); 1621 | } 1622 | ``` 1623 | 1624 | ## 3.Socket UDP communication 1625 | A UDP demo is not currently provided; it will only be considered if someone requests it. 1626 | -------------------------------------------------------------------------------- /src/opensocket.h: -------------------------------------------------------------------------------- 1 | #ifndef OPEN_SOCKET_HEADER_H 2 | #define OPEN_SOCKET_HEADER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define UDP_ADDRESS_SIZE 19 // ipv6 128bit + port 16bit + 1 byte type 10 | 11 | namespace open 12 | { 13 | 14 | class OpenSocket 15 | { 16 | public: 17 | enum EMsgType 18 | { 19 | ESocketData, 20 | ESocketClose, 21 | ESocketOpen, 22 | ESocketAccept, 23 | ESocketError, 24 | ESocketUdp, 25 | ESocketWarning, 26 | }; 27 | class Msg 28 | { 29 | public: 30 | EMsgType type_; 31 | int fd_; 32 | uintptr_t uid_; 33 | int ud_; 34 | char* buffer_; 35 | size_t size_; 36 | char* option_; 37 | 38 | inline const char* info() const { return buffer_; } 39 | inline const char* data() const { return buffer_; } 40 | inline size_t size() const { return size_; } 41 | Msg(); 42 | ~Msg(); 43 | }; 44 | enum EInfoType 45 | { 46 | EInfoUnknow, 47 | EInfoListen, 48 | EInfoTcp, 49 | EInfoUdp, 50 | EInfoBing 51 | }; 52 | struct Info 53 | { 54 | int id_; 55 | EInfoType type_; 56 | uint64_t opaque_; 57 | uint64_t read_; 58 | uint64_t write_; 59 | uint64_t rtime_; 60 | uint64_t wtime_; 61 | int64_t wbuffer_; 62 | std::string name_; 63 | Info() :id_(0), 64 | opaque_(0), 65 | read_(0), 66 | write_(0), 67 | rtime_(0), 68 | wtime_(0), 69 | wbuffer_(0), 70 | type_(EInfoUnknow){} 71 | void clear() 72 | { 73 | id_ = 0; 74 | opaque_ = 0; 75 | read_ = 0; 76 | write_ = 0; 77 | rtime_ = 0; 78 | wtime_ = 0; 79 | wbuffer_ = 0; 80 | type_ = EInfoUnknow; 81 | name_.clear(); 82 | } 83 | }; 84 | OpenSocket(); 85 | ~OpenSocket(); 86 | 87 | bool run(void (*cb)(const Msg*)); 88 | int send(int fd, const void* buffer, int sz); 89 | int sendLowpriority(int fd, const void* buffer, int sz); 90 | void nodelay(int fd); 91 | 92 | //tcp part 93 | int listen(uintptr_t uid, const std::string& host, int port, int backlog); 94 | int connect(uintptr_t uid, const std::string& host, int port); 95 | int bind(uintptr_t uid, int fd); 96 | void close(uintptr_t uid, int fd); 97 | void shutdown(uintptr_t uid, int fd); 98 | void start(uintptr_t uid, int fd); 99 | 100 | //udp part 101 | int udp(uintptr_t uid, const char* addr, int port); 102 | int udpConnect(int fd, const char* addr, int port); 103 | int udpSend(int fd, const char* address, const void* buffer, int sz); 104 | static int UDPAddress(const char* address, std::string& ip, int& port); 105 | 106 | void socketInfo(std::vector& vectInfo); 107 | inline bool isRunning() { return isRunning_; } 108 | 109 | static void Sleep(int64_t milliSecond); 110 | static const std::string DomainNameToIp(const std::string& domain); 111 | static OpenSocket& Instance() { return Instance_; } 112 | static void Start(void (*cb)(const Msg*)); 113 | private: 114 | int poll(); 115 | void forwardMsg(EMsgType type, bool padding, struct socket_message* result); 116 | static void* ThreadSocket(void* p); 117 | 118 | void (*cb_)(const Msg*); 119 | bool isRunning_; 120 | bool isClose_; 121 | void* socket_server_; 122 | static OpenSocket Instance_; 123 | }; 124 | 125 | typedef OpenSocket::Msg OpenSocketMsg; 126 | 127 | }; 128 | 129 | #endif //OPEN_SOCKET_HEADER_H 130 | -------------------------------------------------------------------------------- /src/socket_os.c: -------------------------------------------------------------------------------- 1 | #include "socket_os.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | //////////////poll////////////// 8 | 9 | #if defined(__linux__) 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | bool sp_invalid(int efd) { 21 | return efd == -1; 22 | } 23 | 24 | int sp_create() { 25 | return epoll_create(1024); 26 | } 27 | 28 | void sp_release(int efd) { 29 | close(efd); 30 | } 31 | 32 | int sp_add(int efd, int sock, void* ud) { 33 | struct epoll_event ev; 34 | ev.events = EPOLLIN; 35 | ev.data.ptr = ud; 36 | if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev) == -1) { 37 | return 1; 38 | } 39 | return 0; 40 | } 41 | 42 | void sp_del(int efd, int sock) { 43 | epoll_ctl(efd, EPOLL_CTL_DEL, sock, NULL); 44 | } 45 | 46 | void sp_write(int efd, int sock, void* ud, bool enable) { 47 | struct epoll_event ev; 48 | ev.events = EPOLLIN | (enable ? EPOLLOUT : 0); 49 | ev.data.ptr = ud; 50 | epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev); 51 | } 52 | 53 | int sp_wait(int efd, struct event* e, const int max) { 54 | struct epoll_event ev[max]; 55 | int n = epoll_wait(efd, ev, max, -1); 56 | int i = 0; 57 | unsigned flag = 0; 58 | for (i = 0; i < n; ++i) { 59 | e[i].s = ev[i].data.ptr; 60 | flag = ev[i].events; 61 | e[i].write = (flag & EPOLLOUT) != 0; 62 | e[i].read = (flag & (EPOLLIN | EPOLLHUP)) != 0; 63 | e[i].error = (flag & EPOLLERR) != 0; 64 | e[i].eof = false; 65 | } 66 | return n; 67 | } 68 | 69 | void sp_nonblocking(int fd) { 70 | int flag = fcntl(fd, F_GETFL, 0); 71 | if (-1 == flag) { 72 | return; 73 | } 74 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 75 | } 76 | 77 | 78 | #elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 79 | 80 | #define _CRT_SECURE_NO_WARNINGS 81 | #include 82 | #include 83 | #define O_NONBLOCK 1 84 | #define F_SETFL 0 85 | #define F_GETFL 1 86 | 87 | static inline int fcntl(SOCKET fd, int cmd, long arg) { 88 | if (cmd == F_GETFL) return 0; 89 | if (cmd == F_SETFL && arg == O_NONBLOCK) { 90 | u_long ulOption = 1; 91 | ioctlsocket(fd, FIONBIO, &ulOption); 92 | } 93 | return 1; 94 | } 95 | 96 | bool sp_invalid(poll_fd efd) { 97 | return efd == 0; 98 | } 99 | 100 | poll_fd sp_create() { 101 | return epoll_create(1024); 102 | } 103 | 104 | void sp_release(poll_fd efd) { 105 | epoll_close(efd); 106 | } 107 | 108 | int sp_add(poll_fd efd, SOCKET sock, void* ud) { 109 | struct epoll_event ev; 110 | ev.events = EPOLLIN; 111 | ev.data.ptr = ud; 112 | if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev) == -1) { 113 | return 1; 114 | } 115 | return 0; 116 | } 117 | 118 | void sp_del(poll_fd efd, SOCKET sock) { 119 | epoll_ctl(efd, EPOLL_CTL_DEL, sock, NULL); 120 | } 121 | 122 | void sp_write(poll_fd efd, SOCKET sock, void* ud, bool enable) { 123 | struct epoll_event ev; 124 | ev.events = EPOLLIN | (enable ? EPOLLOUT : 0); 125 | ev.data.ptr = ud; 126 | epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev); 127 | } 128 | 129 | int sp_wait(poll_fd efd, struct event* e, const int max) { 130 | struct epoll_event* ev = (struct epoll_event*)malloc(sizeof(struct epoll_event) * max); 131 | if (!ev) return 0; 132 | int n = epoll_wait(efd, ev, max, -1); 133 | int i = 0; 134 | unsigned flag = 0; 135 | for (i = 0; i < n; ++i) { 136 | e[i].s = ev[i].data.ptr; 137 | flag = ev[i].events; 138 | e[i].write = (flag & EPOLLOUT) != 0; 139 | e[i].read = (flag & (EPOLLIN | EPOLLHUP)) != 0; 140 | e[i].error = (flag & EPOLLERR) != 0; 141 | e[i].eof = false; 142 | } 143 | free(ev); 144 | return n; 145 | } 146 | 147 | void sp_nonblocking(SOCKET fd) { 148 | int flag = fcntl(fd, F_GETFL, 0); 149 | if (-1 == flag) { 150 | return; 151 | } 152 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 153 | } 154 | 155 | #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 156 | 157 | #include 158 | #include 159 | #include 160 | #include 161 | #include 162 | #include 163 | #include 164 | #include 165 | 166 | bool sp_invalid(int kfd) { 167 | return kfd == -1; 168 | } 169 | 170 | int sp_create() { 171 | return kqueue(); 172 | } 173 | 174 | void sp_release(int kfd) { 175 | close(kfd); 176 | } 177 | 178 | void sp_del(int kfd, int sock) { 179 | struct kevent ke; 180 | EV_SET(&ke, sock, EVFILT_READ, EV_DELETE, 0, 0, NULL); 181 | kevent(kfd, &ke, 1, NULL, 0, NULL); 182 | EV_SET(&ke, sock, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 183 | kevent(kfd, &ke, 1, NULL, 0, NULL); 184 | } 185 | 186 | int sp_add(int kfd, int sock, void* ud) { 187 | struct kevent ke; 188 | EV_SET(&ke, sock, EVFILT_READ, EV_ADD, 0, 0, ud); 189 | if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 190 | return 1; 191 | } 192 | EV_SET(&ke, sock, EVFILT_WRITE, EV_ADD, 0, 0, ud); 193 | if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 194 | EV_SET(&ke, sock, EVFILT_READ, EV_DELETE, 0, 0, NULL); 195 | kevent(kfd, &ke, 1, NULL, 0, NULL); 196 | return 1; 197 | } 198 | EV_SET(&ke, sock, EVFILT_WRITE, EV_DISABLE, 0, 0, ud); 199 | if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 200 | sp_del(kfd, sock); 201 | return 1; 202 | } 203 | return 0; 204 | } 205 | 206 | void sp_write(int kfd, int sock, void* ud, bool enable) { 207 | struct kevent ke; 208 | EV_SET(&ke, sock, EVFILT_WRITE, enable ? EV_ENABLE : EV_DISABLE, 0, 0, ud); 209 | if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 210 | // todo: check error 211 | } 212 | } 213 | 214 | int sp_wait(int kfd, struct event* e, int max) { 215 | struct kevent ev[max]; 216 | int n = kevent(kfd, NULL, 0, ev, max, NULL); 217 | int i = 0; 218 | bool eof = false; 219 | unsigned filter = 0; 220 | for (i = 0; i < n; ++i) { 221 | e[i].s = ev[i].udata; 222 | filter = ev[i].filter; 223 | eof = (ev[i].flags & EV_EOF) != 0; 224 | e[i].write = (filter == EVFILT_WRITE) && (!eof); 225 | e[i].read = (filter == EVFILT_READ) && (!eof); 226 | e[i].error = (ev[i].flags & EV_ERROR) != 0; 227 | e[i].eof = eof; 228 | } 229 | return n; 230 | } 231 | 232 | void sp_nonblocking(int fd) { 233 | int flag = fcntl(fd, F_GETFL, 0); 234 | if (-1 == flag) { 235 | return; 236 | } 237 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 238 | } 239 | 240 | #else 241 | 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | #include 249 | #include 250 | #include 251 | #include 252 | #include 253 | #include 254 | #include 255 | 256 | struct fd_ctx 257 | { 258 | int fd; 259 | void* ud; 260 | bool write; 261 | }; 262 | 263 | struct sp_ctx 264 | { 265 | fd_set read_fds; 266 | fd_set write_fds; 267 | fd_set except_fds; 268 | int used_size; 269 | struct fd_ctx fd_ctxs[FD_SETSIZE]; 270 | }; 271 | 272 | struct sp_ctx* ctx = NULL; 273 | bool sp_invalid(int efd) { 274 | return efd == -1; 275 | } 276 | 277 | int sp_create() { 278 | if (ctx != NULL) { 279 | return -1; 280 | } 281 | ctx = (struct sp_ctx*)malloc(sizeof(struct sp_ctx)); 282 | if (ctx) 283 | { 284 | memset(ctx, 0, sizeof(struct sp_ctx)); 285 | int i = 0; 286 | for (; i < FD_SETSIZE; ++i) { 287 | ctx->fd_ctxs[i].fd = -1; 288 | } 289 | } 290 | return 0; 291 | } 292 | 293 | void sp_release(int efd) { 294 | free(ctx); 295 | ctx = NULL; 296 | } 297 | 298 | int sp_add(int efd, int sock, void* ud) { 299 | if (ctx->used_size >= FD_SETSIZE) { 300 | fprintf(stderr, "[error]sp_add: select limit FD_SETSIZE:%d/%d \n", ctx->used_size, FD_SETSIZE); 301 | assert(0); 302 | return -1; 303 | } 304 | int i = 0; 305 | for (; i < FD_SETSIZE; ++i) { 306 | if (ctx->fd_ctxs[i].fd < 0) { 307 | ctx->fd_ctxs[i].ud = ud; 308 | ctx->fd_ctxs[i].fd = sock; 309 | ctx->fd_ctxs[i].write = false; 310 | ctx->used_size++; 311 | return 0; 312 | } 313 | } 314 | fprintf(stderr, "[error]sp_add: select limit FD_SETSIZE:%d \n", ctx->used_size); 315 | assert(0); 316 | return -1; 317 | } 318 | 319 | void sp_del(int efd, int sock) { 320 | int i = 0; 321 | for (; i < FD_SETSIZE; ++i) { 322 | if (ctx->fd_ctxs[i].fd == sock) { 323 | ctx->fd_ctxs[i].ud = NULL; 324 | ctx->fd_ctxs[i].fd = -1; 325 | ctx->fd_ctxs[i].write = false; 326 | ctx->used_size--; 327 | return; 328 | } 329 | } 330 | fprintf(stderr, "[warn]sp_del no exist sock:%d \n", sock); 331 | } 332 | 333 | void sp_write(int efd, int sock, void* ud, bool enable) { 334 | int i = 0; 335 | for (; i < FD_SETSIZE; ++i) { 336 | if (ctx->fd_ctxs[i].fd == sock) { 337 | ctx->fd_ctxs[i].ud = ud; 338 | ctx->fd_ctxs[i].write = enable; 339 | return; 340 | } 341 | } 342 | fprintf(stderr, "[warn]sp_write no exist sock:%d \n", sock); 343 | // assert(false); 344 | } 345 | 346 | int sp_wait(int efd, struct event* e, int max) { 347 | FD_ZERO(&ctx->read_fds); 348 | FD_ZERO(&ctx->write_fds); 349 | FD_ZERO(&ctx->except_fds); 350 | 351 | struct fd_ctx* fdctx; 352 | int i = 0; 353 | int idx = 0; 354 | for (; i < FD_SETSIZE; ++i) { 355 | fdctx = &ctx->fd_ctxs[i]; 356 | if (fdctx->fd >= 0) { 357 | FD_SET(fdctx->fd, &ctx->read_fds); 358 | FD_SET(fdctx->fd, &ctx->except_fds); 359 | if (fdctx->write) { 360 | FD_SET(fdctx->fd, &ctx->write_fds); 361 | } 362 | idx++; 363 | if (idx >= ctx->used_size) { 364 | break; 365 | } 366 | } 367 | } 368 | struct timeval tv = { 2019030810, 0 }; 369 | int ret = select(FD_SETSIZE, &ctx->read_fds, &ctx->write_fds, &ctx->except_fds, (struct timeval*)&tv); 370 | if (ret == 0) { 371 | return 0; 372 | } 373 | if (ret < 0) { 374 | fprintf(stderr, "[error]sp_wait select errno[%d]%s \n", errno, strerror(errno)); 375 | return 0; 376 | } 377 | i = 0; 378 | idx = 0; 379 | bool is_event = false; 380 | struct event* evt; 381 | int sz = 0; 382 | for (; i < FD_SETSIZE; ++i) { 383 | fdctx = &ctx->fd_ctxs[i]; 384 | if (fdctx->fd > 0) { 385 | sz++; 386 | evt = &e[idx]; 387 | if (FD_ISSET(fdctx->fd, &ctx->read_fds)) { 388 | evt->s = fdctx->ud; 389 | evt->read = true; 390 | is_event = true; 391 | } 392 | if (FD_ISSET(fdctx->fd, &ctx->write_fds)) { 393 | evt->s = fdctx->ud; 394 | evt->write = true; 395 | is_event = true; 396 | } 397 | if (FD_ISSET(fdctx->fd, &ctx->except_fds)) { 398 | evt->s = fdctx->ud; 399 | evt->error = true; 400 | evt->read = true; 401 | is_event = true; 402 | } 403 | if (is_event) { 404 | idx++; 405 | is_event = false; 406 | if (idx >= max) break; 407 | } 408 | if (sz >= ctx->used_size) { 409 | break; 410 | } 411 | } 412 | } 413 | return idx; 414 | } 415 | 416 | void sp_nonblocking(int fd) { 417 | int flag = fcntl(fd, F_GETFL, 0); 418 | if (-1 == flag) { 419 | return; 420 | } 421 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 422 | } 423 | 424 | #endif 425 | //////////////poll////////////// 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | //////////////socket////////////// 437 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 438 | #pragma comment(lib, "ws2_32.lib") 439 | 440 | int write(fd, buffer, sz) { return 0; } 441 | int read(fd, buffer, sz) { return 0; } 442 | int close(fd, buffer, sz) { return 0; } 443 | 444 | int socket_write(int fd, const void* buffer, size_t sz) 445 | { 446 | int ret = socket_send(fd, (const char*)buffer, (int)sz, 0); 447 | if (ret == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) 448 | return write(fd, buffer, sz); 449 | return ret; 450 | } 451 | 452 | int socket_read(int fd, void* buffer, size_t sz) 453 | { 454 | int ret = socket_recv(fd, (char*)buffer, (int)sz, 0); 455 | if (ret == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) 456 | return read(fd, buffer, (int)sz); 457 | return ret; 458 | } 459 | 460 | int socket_close(int fd) 461 | { 462 | int ret = closesocket(fd); 463 | if (ret == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) 464 | return close(fd); 465 | return ret; 466 | } 467 | 468 | int socket_connect(SOCKET s, const struct sockaddr* name, int namelen) 469 | { 470 | int ret = connect(s, name, namelen); 471 | if (ret == SOCKET_ERROR) { 472 | errno = WSAGetLastError(); 473 | if (errno == WSAEWOULDBLOCK) 474 | errno = EINPROGRESS; 475 | } 476 | return ret; 477 | } 478 | 479 | int socket_send(SOCKET s, const char* buffer, int sz, int flag) 480 | { 481 | int ret = send(s, buffer, sz, flag); 482 | if (ret == SOCKET_ERROR) { 483 | errno = WSAGetLastError(); 484 | if (errno == WSAEWOULDBLOCK) 485 | errno = EAGAIN; 486 | } 487 | return ret; 488 | } 489 | 490 | int socket_recv(SOCKET s, char* buffer, int sz, int flag) 491 | { 492 | int ret = recv(s, buffer, sz, flag); 493 | if (ret == SOCKET_ERROR) { 494 | errno = WSAGetLastError(); 495 | if (errno == WSAEWOULDBLOCK) 496 | errno = EAGAIN; 497 | } 498 | return ret; 499 | } 500 | 501 | int socket_getsockopt(SOCKET s, int level, int optname, void* optval, int* optlen) 502 | { 503 | return getsockopt(s, level, optname, (char*)optval, optlen); 504 | } 505 | 506 | int socket_setsockopt(SOCKET s, int level, int optname, const void* optval, int optlen) 507 | { 508 | return setsockopt(s, level, optname, (char*)optval, optlen); 509 | } 510 | 511 | int socket_recvfrom(SOCKET s, void* buf, int len, int flags, struct sockaddr* from, int* fromlen) 512 | { 513 | int ret = recvfrom(s, (char*)buf, len, flags, from, fromlen); 514 | if (ret == SOCKET_ERROR) { 515 | errno = WSAGetLastError(); 516 | if (errno == WSAEWOULDBLOCK) 517 | errno = EAGAIN; 518 | if (errno == WSAECONNRESET) 519 | errno = EAGAIN; 520 | } 521 | return ret; 522 | } 523 | 524 | int socket_start() 525 | { 526 | WORD wVersionRq = MAKEWORD(2, 0); 527 | WSADATA wsaData; 528 | int err = WSAStartup(wVersionRq, &wsaData); 529 | if (err != 0) 530 | { 531 | printf("Error initializing ws2_32.dll"); 532 | assert(0); 533 | return -1; 534 | } 535 | if ((LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) 536 | { 537 | WSACleanup(); 538 | printf("Error initializing ws2_32.dll"); 539 | assert(0); 540 | return -1; 541 | } 542 | return 0; 543 | } 544 | 545 | int socket_stop() 546 | { 547 | WSACleanup(); 548 | return 0; 549 | } 550 | 551 | int socket_pipe(int fds[2]) 552 | { 553 | int err = socket_start(); 554 | if (err != 0) 555 | { 556 | return err; 557 | } 558 | struct sockaddr_in name; 559 | int namelen = sizeof(name); 560 | SOCKET server = INVALID_SOCKET; 561 | SOCKET client1 = INVALID_SOCKET; 562 | SOCKET client2 = INVALID_SOCKET; 563 | 564 | memset(&name, 0, sizeof(name)); 565 | name.sin_family = AF_INET; 566 | name.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 567 | name.sin_port = 0; 568 | 569 | server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 570 | if (server == INVALID_SOCKET) 571 | goto failed; 572 | 573 | int yes = 1; 574 | if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) == SOCKET_ERROR) 575 | goto failed; 576 | 577 | if (bind(server, (struct sockaddr*)&name, namelen) == SOCKET_ERROR) 578 | goto failed; 579 | 580 | if (listen(server, 5) == SOCKET_ERROR) 581 | goto failed; 582 | 583 | if (getsockname(server, (struct sockaddr*)&name, &namelen) == SOCKET_ERROR) 584 | goto failed; 585 | 586 | client1 = socket(AF_INET, SOCK_STREAM, 0); 587 | if (client1 == INVALID_SOCKET) 588 | goto failed; 589 | 590 | if (connect(client1, (struct sockaddr*)&name, namelen) == SOCKET_ERROR) 591 | goto failed; 592 | 593 | client2 = accept(server, (struct sockaddr*)&name, &namelen); 594 | if (client2 == INVALID_SOCKET) 595 | goto failed; 596 | 597 | // closesocket(server); 598 | fds[0] = (int)client1; 599 | fds[1] = (int)client2; 600 | return 0; 601 | 602 | failed: 603 | if (server != INVALID_SOCKET) 604 | closesocket(server); 605 | 606 | if (client1 != INVALID_SOCKET) 607 | closesocket(client1); 608 | 609 | if (client2 != INVALID_SOCKET) 610 | closesocket(client2); 611 | return -1; 612 | } 613 | 614 | #else 615 | 616 | //int socket_pipe(int fds[2]) 617 | //{ 618 | // int err = socket_start(); 619 | // if (err != 0) 620 | // { 621 | // return err; 622 | // } 623 | // struct sockaddr_in name; 624 | // int namelen = sizeof(name); 625 | // int INVALID_SOCKET = -1; 626 | // int SOCKET_ERROR = -1; 627 | // int server = INVALID_SOCKET; 628 | // int client1 = INVALID_SOCKET; 629 | // int client2 = INVALID_SOCKET; 630 | // 631 | // memset(&name, 0, sizeof(name)); 632 | // name.sin_family = AF_INET; 633 | // name.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 634 | // name.sin_port = 0; 635 | // 636 | // server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 637 | // if (server == INVALID_SOCKET) 638 | // goto failed; 639 | // 640 | // int yes = 1; 641 | // if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) == SOCKET_ERROR) 642 | // goto failed; 643 | // 644 | // if (bind(server, (struct sockaddr*)&name, namelen) == SOCKET_ERROR) 645 | // goto failed; 646 | // 647 | // if (listen(server, 5) == SOCKET_ERROR) 648 | // goto failed; 649 | // 650 | // if (getsockname(server, (struct sockaddr*)&name, &namelen) == SOCKET_ERROR) 651 | // goto failed; 652 | // 653 | // client1 = socket(AF_INET, SOCK_STREAM, 0); 654 | // if (client1 == INVALID_SOCKET) 655 | // goto failed; 656 | // 657 | // if (connect(client1, (struct sockaddr*)&name, namelen) == SOCKET_ERROR) 658 | // goto failed; 659 | // 660 | // client2 = accept(server, (struct sockaddr*)&name, &namelen); 661 | // if (client2 == INVALID_SOCKET) 662 | // goto failed; 663 | // 664 | // // closesocket(server); 665 | // fds[0] = (int)client1; 666 | // fds[1] = (int)client2; 667 | // return 0; 668 | // 669 | //failed: 670 | // if (server != INVALID_SOCKET) 671 | // close(server); 672 | // 673 | // if (client1 != INVALID_SOCKET) 674 | // close(client1); 675 | // 676 | // if (client2 != INVALID_SOCKET) 677 | // close(client2); 678 | // return -1; 679 | //} 680 | 681 | #endif 682 | 683 | 684 | 685 | //////////////socket////////////// 686 | 687 | 688 | 689 | -------------------------------------------------------------------------------- /src/socket_os.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_OS_h 2 | #define SOCKET_OS_h 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | 11 | 12 | //////////////poll////////////// 13 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 14 | 15 | #include "wepoll.h" 16 | #include 17 | #include 18 | 19 | struct event { 20 | void* s; 21 | bool read; 22 | bool write; 23 | bool error; 24 | bool eof; 25 | }; 26 | typedef HANDLE poll_fd; 27 | extern bool sp_invalid(poll_fd fd); 28 | extern poll_fd sp_create(); 29 | extern void sp_release(poll_fd fd); 30 | extern int sp_add(poll_fd fd, SOCKET sock, void* ud); 31 | extern void sp_del(poll_fd fd, SOCKET sock); 32 | extern void sp_write(poll_fd, SOCKET sock, void* ud, bool enable); 33 | extern int sp_wait(poll_fd, struct event* e, int max); 34 | extern void sp_nonblocking(SOCKET sock); 35 | 36 | #else 37 | 38 | struct event { 39 | void* s; 40 | bool read; 41 | bool write; 42 | bool error; 43 | bool eof; 44 | }; 45 | typedef int poll_fd; 46 | 47 | extern bool sp_invalid(poll_fd fd); 48 | extern poll_fd sp_create(); 49 | extern void sp_release(poll_fd fd); 50 | extern int sp_add(poll_fd fd, int sock, void* ud); 51 | extern void sp_del(poll_fd fd, int sock); 52 | extern void sp_write(poll_fd, int sock, void* ud, bool enable); 53 | extern int sp_wait(poll_fd, struct event* e, int max); 54 | extern void sp_nonblocking(int sock); 55 | 56 | #endif 57 | 58 | // ////////////poll////////////// 59 | 60 | 61 | 62 | 63 | 64 | // ////////////atomic////////////// 65 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 66 | 67 | static inline bool __sync_bool_compare_and_swap(long* ptr, int oval, int nval) { 68 | return oval == InterlockedCompareExchange(ptr, nval, oval) ? 1 : 0; 69 | } 70 | 71 | static inline long __sync_add_and_fetch(long* ptr, long n) { 72 | InterlockedAdd(ptr, n); 73 | return *ptr; 74 | } 75 | 76 | static inline long __sync_sub_and_fetch(long* ptr, long n) { 77 | InterlockedAdd(ptr, -n); 78 | return *ptr; 79 | } 80 | 81 | static inline long __sync_and_and_fetch(long* ptr, long n) { 82 | InterlockedAnd(ptr, n); 83 | return *ptr; 84 | } 85 | 86 | #define ATOM_CAS(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 87 | #define ATOM_CAS_POINTER(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 88 | // #define ATOM_FINC(ptr) __sync_fetch_and_add(ptr, 1) 89 | // #define ATOM_FDEC(ptr) __sync_fetch_and_sub(ptr, 1) 90 | #define ATOM_INC(ptr) __sync_add_and_fetch(ptr, 1) 91 | #define ATOM_DEC(ptr) __sync_sub_and_fetch(ptr, 1) 92 | #define ATOM_ADD(ptr,n) __sync_add_and_fetch(ptr, n) 93 | #define ATOM_SUB(ptr,n) __sync_sub_and_fetch(ptr, n) 94 | #define ATOM_AND(ptr,n) __sync_and_and_fetch(ptr, n) 95 | 96 | #else 97 | 98 | #define ATOM_CAS(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 99 | #define ATOM_CAS_POINTER(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 100 | #define ATOM_INC(ptr) __sync_add_and_fetch(ptr, 1) 101 | #define ATOM_FINC(ptr) __sync_fetch_and_add(ptr, 1) 102 | #define ATOM_DEC(ptr) __sync_sub_and_fetch(ptr, 1) 103 | #define ATOM_FDEC(ptr) __sync_fetch_and_sub(ptr, 1) 104 | #define ATOM_ADD(ptr,n) __sync_add_and_fetch(ptr, n) 105 | #define ATOM_SUB(ptr,n) __sync_sub_and_fetch(ptr, n) 106 | #define ATOM_AND(ptr,n) __sync_and_and_fetch(ptr, n) 107 | 108 | #endif 109 | // ////////////atomic////////////// 110 | 111 | 112 | //////////////spinlock////////////// 113 | 114 | #define SPIN_INIT(q) spinlock_init(&(q)->lock); 115 | #define SPIN_LOCK(q) spinlock_lock(&(q)->lock); 116 | #define SPIN_UNLOCK(q) spinlock_unlock(&(q)->lock); 117 | #define SPIN_DESTROY(q) spinlock_destroy(&(q)->lock); 118 | 119 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 120 | 121 | #include 122 | #include 123 | 124 | struct spinlock { 125 | CRITICAL_SECTION lock; 126 | }; 127 | 128 | static inline void spinlock_init(struct spinlock *lock) { 129 | BOOL ret = InitializeCriticalSectionAndSpinCount(&lock->lock, 4000); 130 | if (!ret) 131 | { 132 | assert(false); 133 | } 134 | } 135 | 136 | static inline void spinlock_lock(struct spinlock *lock) { 137 | EnterCriticalSection(&lock->lock); 138 | } 139 | 140 | static inline int spinlock_trylock(struct spinlock *lock) { 141 | return TryEnterCriticalSection(&lock->lock); 142 | } 143 | 144 | static inline void spinlock_unlock(struct spinlock *lock) { 145 | LeaveCriticalSection(&lock->lock); 146 | } 147 | 148 | static inline void spinlock_destroy(struct spinlock *lock) { 149 | DeleteCriticalSection(&lock->lock); 150 | } 151 | 152 | #else 153 | 154 | #ifndef USE_PTHREAD_LOCK 155 | 156 | struct spinlock { 157 | int lock; 158 | }; 159 | 160 | static inline void spinlock_init(struct spinlock *lock) { 161 | lock->lock = 0; 162 | } 163 | 164 | static inline void spinlock_lock(struct spinlock *lock) { 165 | while (__sync_lock_test_and_set(&lock->lock,1)) {} 166 | } 167 | 168 | static inline int spinlock_trylock(struct spinlock *lock) { 169 | return __sync_lock_test_and_set(&lock->lock,1) == 0; 170 | } 171 | 172 | static inline void spinlock_unlock(struct spinlock *lock) { 173 | __sync_lock_release(&lock->lock); 174 | } 175 | 176 | static inline void spinlock_destroy(struct spinlock *lock) { 177 | (void) lock; 178 | } 179 | 180 | #else 181 | 182 | #include 183 | 184 | struct spinlock { 185 | pthread_mutex_t lock; 186 | }; 187 | 188 | static inline void spinlock_init(struct spinlock *lock) { 189 | pthread_mutex_init(&lock->lock, NULL); 190 | } 191 | 192 | static inline void spinlock_lock(struct spinlock *lock) { 193 | pthread_mutex_lock(&lock->lock); 194 | } 195 | 196 | static inline int spinlock_trylock(struct spinlock *lock) { 197 | return pthread_mutex_trylock(&lock->lock) == 0; 198 | } 199 | 200 | static inline void spinlock_unlock(struct spinlock *lock) { 201 | pthread_mutex_unlock(&lock->lock); 202 | } 203 | 204 | static inline void spinlock_destroy(struct spinlock *lock) { 205 | pthread_mutex_destroy(&lock->lock); 206 | } 207 | 208 | #endif 209 | 210 | #endif 211 | 212 | //////////////spinlock////////////// 213 | 214 | 215 | 216 | 217 | // ////////////socket////////////// 218 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 219 | #define _CRT_SECURE_NO_WARNINGS 220 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 221 | #include /* must always be included before ws2tcpip.h */ 222 | #include /* for struct sock_addr used in zookeeper.h */ 223 | #undef near 224 | 225 | int socket_write(int fd, const void* buffer, size_t sz); 226 | int socket_read(int fd, void* buffer, size_t sz); 227 | int socket_close(int fd); 228 | int socket_connect(SOCKET s, const struct sockaddr* name, int namelen); 229 | int socket_send(SOCKET s, const char* buffer, int sz, int flag); 230 | int socket_recv(SOCKET s, char* buffer, int sz, int flag); 231 | 232 | int socket_recvfrom(SOCKET s, void* buf, int len, int flags, struct sockaddr* from, int* fromlen); 233 | int socket_start(); 234 | int socket_stop(); 235 | 236 | int socket_getsockopt(SOCKET s, int level, int optname, void* optval, int* optlen); 237 | int socket_setsockopt(SOCKET s, int level, int optname, const void* optval, int optlen); 238 | int socket_pipe(int fds[2]); 239 | 240 | #else 241 | 242 | #include 243 | #include 244 | #include 245 | #include 246 | //static inline int socket_write(int fd, const void* buffer, size_t sz) { 247 | // return write(fd, buffer, sz); 248 | //} 249 | // 250 | //static inline int socket_read(int fd, void* buffer, size_t sz) { 251 | // return read(fd, buffer, sz); 252 | //} 253 | 254 | static inline int socket_close(int fd) { 255 | return close(fd); 256 | } 257 | 258 | //static inline int socket_connect(int s, const struct sockaddr* name, int namelen) { 259 | // return connect(s, name, namelen); 260 | //} 261 | // 262 | //static inline int socket_send(int s, const char* buffer, int sz, int flag) { 263 | // return send(s, buffer, sz, flag); 264 | //} 265 | // 266 | //static inline int socket_recv(int s, char* buffer, int sz, int flag) { 267 | // return recv(s, buffer, sz, flag); 268 | //} 269 | // 270 | //static inline int socket_recvfrom(int s, void* buf, int len, int flags, struct sockaddr* from, socklen_t* fromlen) { 271 | // return recvfrom(s, buf, len, flags, from, fromlen); 272 | //} 273 | #define socket_write write 274 | #define socket_read read 275 | //#define socket_close close 276 | 277 | #define socket_connect connect 278 | #define socket_send send 279 | #define socket_recv recv 280 | #define socket_recvfrom recvfrom 281 | 282 | #define socket_getsockopt getsockopt 283 | #define socket_setsockopt setsockopt 284 | 285 | #define socket_pipe pipe 286 | //int socket_pipe(int fds[2]); 287 | 288 | inline int socket_start() { return 0; } 289 | inline int socket_stop() { return 0; } 290 | 291 | #endif 292 | 293 | // ////////////socket////////////// 294 | 295 | 296 | 297 | 298 | #ifdef __cplusplus 299 | } 300 | #endif 301 | 302 | #endif //SOCKET_OS_h 303 | -------------------------------------------------------------------------------- /src/wepoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wepoll - epoll for Windows 3 | * https://github.com/piscisaureus/wepoll 4 | * 5 | * Copyright 2012-2020, Bert Belder 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are 10 | * met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 33 | 34 | 35 | #ifndef WEPOLL_H_ 36 | #define WEPOLL_H_ 37 | 38 | #ifndef WEPOLL_EXPORT 39 | #define WEPOLL_EXPORT 40 | #endif 41 | 42 | #include 43 | 44 | enum EPOLL_EVENTS { 45 | EPOLLIN = (int) (1U << 0), 46 | EPOLLPRI = (int) (1U << 1), 47 | EPOLLOUT = (int) (1U << 2), 48 | EPOLLERR = (int) (1U << 3), 49 | EPOLLHUP = (int) (1U << 4), 50 | EPOLLRDNORM = (int) (1U << 6), 51 | EPOLLRDBAND = (int) (1U << 7), 52 | EPOLLWRNORM = (int) (1U << 8), 53 | EPOLLWRBAND = (int) (1U << 9), 54 | EPOLLMSG = (int) (1U << 10), /* Never reported. */ 55 | EPOLLRDHUP = (int) (1U << 13), 56 | EPOLLONESHOT = (int) (1U << 31) 57 | }; 58 | 59 | #define EPOLLIN (1U << 0) 60 | #define EPOLLPRI (1U << 1) 61 | #define EPOLLOUT (1U << 2) 62 | #define EPOLLERR (1U << 3) 63 | #define EPOLLHUP (1U << 4) 64 | #define EPOLLRDNORM (1U << 6) 65 | #define EPOLLRDBAND (1U << 7) 66 | #define EPOLLWRNORM (1U << 8) 67 | #define EPOLLWRBAND (1U << 9) 68 | #define EPOLLMSG (1U << 10) 69 | #define EPOLLRDHUP (1U << 13) 70 | #define EPOLLONESHOT (1U << 31) 71 | 72 | #define EPOLL_CTL_ADD 1 73 | #define EPOLL_CTL_MOD 2 74 | #define EPOLL_CTL_DEL 3 75 | 76 | typedef void* HANDLE; 77 | typedef uintptr_t SOCKET; 78 | 79 | typedef union epoll_data { 80 | void* ptr; 81 | int fd; 82 | uint32_t u32; 83 | uint64_t u64; 84 | SOCKET sock; /* Windows specific */ 85 | HANDLE hnd; /* Windows specific */ 86 | } epoll_data_t; 87 | 88 | struct epoll_event { 89 | uint32_t events; /* Epoll events and flags */ 90 | epoll_data_t data; /* User data variable */ 91 | }; 92 | 93 | #ifdef __cplusplus 94 | extern "C" { 95 | #endif 96 | 97 | WEPOLL_EXPORT HANDLE epoll_create(int size); 98 | WEPOLL_EXPORT HANDLE epoll_create1(int flags); 99 | 100 | WEPOLL_EXPORT int epoll_close(HANDLE ephnd); 101 | 102 | WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd, 103 | int op, 104 | SOCKET sock, 105 | struct epoll_event* event); 106 | 107 | WEPOLL_EXPORT int epoll_wait(HANDLE ephnd, 108 | struct epoll_event* events, 109 | int maxevents, 110 | int timeout); 111 | 112 | #ifdef __cplusplus 113 | } /* extern "C" */ 114 | #endif 115 | 116 | #endif /* WEPOLL_H_ */ 117 | 118 | #endif -------------------------------------------------------------------------------- /test/helloworld.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "opensocket.h" 6 | #include "open/openthread.h" 7 | using namespace open; 8 | 9 | const std::string TestServerIp_ = "0.0.0.0"; 10 | const std::string TestClientIp_ = "127.0.0.1"; 11 | const int TestServerPort_ = 8888; 12 | 13 | struct ProtoBuffer 14 | { 15 | bool isSocket_; 16 | int acceptFd_; 17 | std::string addr_; 18 | std::shared_ptr data_; 19 | ProtoBuffer() : 20 | isSocket_(0), acceptFd_(0) {} 21 | }; 22 | 23 | static void SocketFunc(const OpenSocketMsg* msg) 24 | { 25 | if (!msg) return; 26 | if (msg->uid_ < 0) 27 | { 28 | delete msg; return; 29 | } 30 | auto proto = std::shared_ptr(new ProtoBuffer); 31 | proto->isSocket_ = true; 32 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 33 | bool ret = OpenThread::Send((int)msg->uid_, proto); 34 | if (!ret) 35 | { 36 | printf("SocketFunc dispatch faild pid = %d\n", (int)msg->uid_); 37 | } 38 | } 39 | 40 | // Listen 41 | static int listen_fd_ = 0; 42 | void ListenThread(OpenThreadMsg& msg) 43 | { 44 | int pid = msg.pid(); 45 | auto& pname = msg.name(); 46 | assert(pname == "listen"); 47 | if (msg.state_ == OpenThread::START) 48 | { 49 | while (OpenThread::ThreadId("accept") < 0) OpenThread::Sleep(100); 50 | listen_fd_ = OpenSocket::Instance().listen((uintptr_t)pid, TestServerIp_, TestServerPort_, 64); 51 | if (listen_fd_ < 0) 52 | { 53 | printf("Listen::START faild listen_fd_ = %d\n", listen_fd_); 54 | assert(false); 55 | } 56 | OpenSocket::Instance().start((uintptr_t)pid, listen_fd_); 57 | } 58 | else if (msg.state_ == OpenThread::RUN) 59 | { 60 | const ProtoBuffer* proto = msg.data(); 61 | if (!proto || !proto->isSocket_ || !proto->data_) return; 62 | auto& socketMsg = proto->data_; 63 | switch (socketMsg->type_) 64 | { 65 | case OpenSocket::ESocketAccept: 66 | { 67 | printf("Listen::RUN [%s]ESocketAccept: new client. acceptFd:%d, client:%s\n", pname.c_str(), socketMsg->ud_, socketMsg->info()); 68 | auto proto = std::shared_ptr(new ProtoBuffer); 69 | proto->addr_ = socketMsg->info(); 70 | proto->isSocket_ = false; 71 | proto->acceptFd_ = socketMsg->ud_; 72 | bool ret = OpenThread::Send("accept", proto); 73 | assert(ret); 74 | } 75 | break; 76 | case OpenSocket::ESocketClose: 77 | printf("Listen::RUN [%s]ESocketClose:linten close, listenFd:%d\n", pname.c_str(), socketMsg->fd_); 78 | break; 79 | case OpenSocket::ESocketError: 80 | printf("Listen::RUN [%s]ESocketError:%s\n", pname.c_str(), socketMsg->info()); 81 | break; 82 | case OpenSocket::ESocketWarning: 83 | printf("Listen::RUN [%s]ESocketWarning:%s\n", pname.c_str(), socketMsg->info()); 84 | break; 85 | case OpenSocket::ESocketOpen: 86 | printf("Listen::RUN [%s]ESocketOpen:linten open, listenFd:%d\n", pname.c_str(), socketMsg->fd_); 87 | break; 88 | case OpenSocket::ESocketUdp: 89 | case OpenSocket::ESocketData: 90 | assert(false); 91 | break; 92 | default: 93 | break; 94 | } 95 | } 96 | else if (msg.state_ == OpenThread::STOP) 97 | { 98 | OpenSocket::Instance().close(pid, listen_fd_); 99 | } 100 | } 101 | 102 | // Accept 103 | void AcceptThread(OpenThreadMsg& msg) 104 | { 105 | int pid = msg.pid(); 106 | auto& pname = msg.name(); 107 | assert(pname == "accept"); 108 | if (msg.state_ == OpenThread::START) 109 | { 110 | } 111 | else if (msg.state_ == OpenThread::RUN) 112 | { 113 | const ProtoBuffer* proto = msg.data(); 114 | if (!proto) return; 115 | if (!proto->isSocket_) 116 | { 117 | printf("Accept::RUN [%s]open accept client:%s\n", pname.c_str(), proto->addr_.c_str()); 118 | OpenSocket::Instance().start(pid, proto->acceptFd_); 119 | } 120 | else 121 | { 122 | if (!proto->data_) return; 123 | auto& socketMsg = proto->data_; 124 | switch (socketMsg->type_) 125 | { 126 | case OpenSocket::ESocketData: 127 | { 128 | //recevie from client 129 | { 130 | auto size = socketMsg->size(); 131 | auto data = socketMsg->data(); 132 | assert(size >= 4); 133 | int len = *(int*)data; 134 | std::string buffer; 135 | buffer.append(data + 4, len); 136 | assert(buffer == "Waiting for you!"); 137 | } 138 | 139 | //response to client 140 | { 141 | char buffer[256] = { 0 }; 142 | std::string tmp = "Of Course,I Still Love You!"; 143 | *(int*)buffer = (int)tmp.size(); 144 | memcpy(buffer + 4, tmp.data(), tmp.size()); 145 | OpenSocket::Instance().send(socketMsg->fd_, buffer, (int)(4 + tmp.size())); 146 | } 147 | } 148 | break; 149 | case OpenSocket::ESocketOpen: 150 | printf("Accept::RUN [%s]ESocketClose:accept client open, acceptFd:%d\n", pname.c_str(), socketMsg->fd_); 151 | break; 152 | case OpenSocket::ESocketClose: 153 | printf("Accept::RUN [%s]ESocketClose:accept client close, acceptFd:%d\n", pname.c_str(), socketMsg->fd_); 154 | break; 155 | case OpenSocket::ESocketError: 156 | printf("Accept::RUN [%s]ESocketError:accept client %s\n", pname.c_str(), socketMsg->info()); 157 | break; 158 | case OpenSocket::ESocketWarning: 159 | printf("Accept::RUN [%s]ESocketWarning:%s\n", pname.c_str(), socketMsg->info()); 160 | break; 161 | case OpenSocket::ESocketAccept: 162 | case OpenSocket::ESocketUdp: 163 | assert(false); 164 | break; 165 | default: 166 | break; 167 | } 168 | } 169 | } 170 | } 171 | //client 172 | static int client_fd_ = 0; 173 | void ClientThread(OpenThreadMsg& msg) 174 | { 175 | int pid = msg.pid(); 176 | auto& pname = msg.name(); 177 | assert(pname == "client"); 178 | if (msg.state_ == OpenThread::START) 179 | { 180 | while (OpenThread::ThreadId("accept") < 0) OpenThread::Sleep(100); 181 | client_fd_ = OpenSocket::Instance().connect(pid, TestClientIp_, TestServerPort_); 182 | } 183 | else if (msg.state_ == OpenThread::RUN) 184 | { 185 | const ProtoBuffer* proto = msg.data(); 186 | if (!proto || !proto->isSocket_ || !proto->data_) return; 187 | auto& socketMsg = proto->data_; 188 | switch (socketMsg->type_) 189 | { 190 | case OpenSocket::ESocketData: 191 | { 192 | //recevie from client 193 | auto size = socketMsg->size(); 194 | auto data = socketMsg->data(); 195 | assert(size >= 4); 196 | int len = *(int*)data; 197 | std::string buffer; 198 | buffer.append(data + 4, len); 199 | assert(buffer == "Of Course,I Still Love You!"); 200 | OpenSocket::Instance().close(pid, socketMsg->fd_); 201 | 202 | OpenThread::StopAll(); 203 | } 204 | break; 205 | case OpenSocket::ESocketOpen: 206 | { 207 | assert(client_fd_ == socketMsg->fd_); 208 | printf("Client::RUN [%s]ESocketClose:Client client open, clientFd:%d\n", pname.c_str(), socketMsg->fd_); 209 | char buffer[256] = {0}; 210 | std::string tmp = "Waiting for you!"; 211 | *(int*)buffer = (int)tmp.size(); 212 | memcpy(buffer + 4, tmp.data(), tmp.size()); 213 | OpenSocket::Instance().send(client_fd_, buffer, (int)(4 + tmp.size())); 214 | } 215 | break; 216 | case OpenSocket::ESocketClose: 217 | printf("Client::RUN [%s]ESocketClose:Client client close, clientFd:%d\n", pname.c_str(), socketMsg->fd_); 218 | break; 219 | case OpenSocket::ESocketError: 220 | printf("Client::RUN [%s]ESocketError:Client client %s\n", pname.c_str(), socketMsg->info()); 221 | break; 222 | case OpenSocket::ESocketWarning: 223 | printf("Client::RUN [%s]ESocketWarning:Client %s\n", pname.c_str(), socketMsg->info()); 224 | break; 225 | case OpenSocket::ESocketAccept: 226 | case OpenSocket::ESocketUdp: 227 | assert(false); 228 | break; 229 | default: 230 | break; 231 | } 232 | 233 | } 234 | } 235 | int main() 236 | { 237 | // create and start thread 238 | OpenThread::Create("listen", ListenThread); 239 | OpenThread::Create("accept", AcceptThread); 240 | OpenThread::Create("client", ClientThread); 241 | 242 | // run OpenSocket 243 | OpenSocket::Start(SocketFunc); 244 | 245 | OpenThread::ThreadJoinAll(); 246 | printf("Pause\n"); 247 | return getchar(); 248 | } 249 | -------------------------------------------------------------------------------- /test/httpclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "open/openthread.h" 7 | #include "opensocket.h" 8 | using namespace open; 9 | 10 | ////////////HttpRequest////////////////////// 11 | class HttpRequest 12 | { 13 | std::string url_; 14 | public: 15 | std::map headers_; 16 | int port_; 17 | std::string host_; 18 | std::string ip_; 19 | std::string path_; 20 | std::string method_; 21 | std::string body_; 22 | HttpRequest() :port_(80) {} 23 | std::string& operator[](const std::string& key) { return headers_[key]; } 24 | void setUrl(const std::string& url); 25 | inline void operator=(const std::string& url) { setUrl(url); } 26 | 27 | struct HttpResponse 28 | { 29 | int code_; 30 | int clen_; 31 | std::string head_; 32 | std::string body_; 33 | //std::multimap headers_; 34 | std::map headers_; 35 | std::string& operator[](const std::string& key) { return headers_[key]; } 36 | 37 | HttpResponse():code_(0), clen_(0) {} 38 | void parseHeader(); 39 | bool pushData(const char* data, size_t size); 40 | }; 41 | HttpResponse response_; 42 | OpenSync openSync_; 43 | }; 44 | 45 | ////////////Proto////////////////////// 46 | struct SocketProto : public OpenThreadProto 47 | { 48 | std::shared_ptr data_; 49 | static inline int ProtoType() { return 1; } 50 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 51 | }; 52 | 53 | struct TaskProto : public OpenThreadProto 54 | { 55 | int fd_; 56 | OpenSync openSync_; 57 | std::shared_ptr request_; 58 | static inline int ProtoType() { return 2; } 59 | virtual inline int protoType() const { return TaskProto::ProtoType(); } 60 | TaskProto() :fd_(0) {} 61 | }; 62 | 63 | ////////////App////////////////////// 64 | class App 65 | { 66 | static void SocketFunc(const OpenSocketMsg* msg) 67 | { 68 | if (!msg) return; 69 | if (msg->uid_ >= 0) 70 | { 71 | auto proto = std::shared_ptr(new SocketProto); 72 | proto->srcPid_ = -1; 73 | proto->srcName_ = "OpenSocket"; 74 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 75 | if (!OpenThread::Send((int)msg->uid_, proto)) 76 | printf("SocketFunc dispatch faild pid = %d\n", (int)msg->uid_); 77 | } 78 | else delete msg; 79 | } 80 | public: 81 | static App Instance_; 82 | App() { OpenSocket::Start(App::SocketFunc); } 83 | }; 84 | App App::Instance_; 85 | 86 | 87 | ////////////HttpClient////////////////////// 88 | class HttpClient : public OpenThreadWorker 89 | { 90 | //Factory 91 | class Factory 92 | { 93 | const std::vector vectWorker_; 94 | public: 95 | Factory() 96 | :vectWorker_({ 97 | new HttpClient("HttpClient1"), 98 | new HttpClient("HttpClient2"), 99 | new HttpClient("HttpClient3"), 100 | new HttpClient("HttpClient4"), 101 | }) {} 102 | HttpClient* getWorker() 103 | { 104 | if (vectWorker_.empty()) return 0; 105 | return vectWorker_[std::rand() % vectWorker_.size()]; 106 | } 107 | }; 108 | static Factory Instance_; 109 | 110 | // HttpClient 111 | HttpClient(const std::string& name) 112 | :OpenThreadWorker(name) 113 | { 114 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&HttpClient::onSocketProto); 115 | registers(TaskProto::ProtoType(), (OpenThreadHandle)&HttpClient::onTaskProto); 116 | start(); 117 | } 118 | ~HttpClient() 119 | { 120 | for (auto iter = mapFdToTask_.begin(); iter != mapFdToTask_.end(); iter++) 121 | iter->second.openSync_.wakeup(); 122 | } 123 | 124 | private: 125 | void onTaskProto(TaskProto& proto) 126 | { 127 | auto& request = proto.request_; 128 | proto.fd_ = OpenSocket::Instance().connect(pid(), request->ip_, request->port_); 129 | request->response_.code_ = -1; 130 | request->response_.head_.clear(); 131 | request->response_.body_.clear(); 132 | mapFdToTask_[proto.fd_] = proto; 133 | } 134 | void onSendHttp(const std::shared_ptr& data) 135 | { 136 | auto iter = mapFdToTask_.find(data->fd_); 137 | if (iter == mapFdToTask_.end()) 138 | { 139 | OpenSocket::Instance().close(pid(), data->fd_); 140 | return; 141 | } 142 | auto& task = iter->second; 143 | auto& request = task.request_; 144 | std::string buffer = request->method_ + " " + request->path_ + " HTTP/1.1 \r\n"; 145 | auto iter1 = request->headers_.begin(); 146 | for (; iter1 != request->headers_.end(); iter1++) 147 | { 148 | buffer.append(iter1->first + ": " + iter1->second + "\r\n"); 149 | } 150 | if (!request->body_.empty()) 151 | { 152 | buffer.append("Content-Length:" + std::to_string(request->body_.size()) + "\r\n\r\n"); 153 | buffer.append(request->body_); 154 | buffer.append("\r\n"); 155 | } 156 | else 157 | { 158 | buffer.append("\r\n"); 159 | } 160 | OpenSocket::Instance().send(task.fd_, buffer.data(), (int)buffer.size()); 161 | } 162 | void onReadHttp(const std::shared_ptr& data) 163 | { 164 | auto iter = mapFdToTask_.find(data->fd_); 165 | if (iter == mapFdToTask_.end()) 166 | { 167 | OpenSocket::Instance().close(pid(), data->fd_); 168 | return; 169 | } 170 | auto& task = iter->second; 171 | auto& response = task.request_->response_; 172 | if (response.pushData(data->data(), data->size())) 173 | { 174 | OpenSocket::Instance().close(pid(), data->fd_); 175 | } 176 | } 177 | void onCloseHttp(const std::shared_ptr& data) 178 | { 179 | auto iter = mapFdToTask_.find(data->fd_); 180 | if (iter != mapFdToTask_.end()) 181 | { 182 | iter->second.openSync_.wakeup(); 183 | mapFdToTask_.erase(iter); 184 | } 185 | } 186 | void onSocketProto(const SocketProto& proto) 187 | { 188 | const auto& msg = proto.data_; 189 | switch (msg->type_) 190 | { 191 | case OpenSocket::ESocketData: 192 | onReadHttp(msg); 193 | break; 194 | case OpenSocket::ESocketClose: 195 | onCloseHttp(msg); 196 | break; 197 | case OpenSocket::ESocketError: 198 | printf("[%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 199 | onCloseHttp(msg); 200 | break; 201 | case OpenSocket::ESocketWarning: 202 | printf("[%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 203 | break; 204 | case OpenSocket::ESocketOpen: 205 | onSendHttp(msg); 206 | break; 207 | case OpenSocket::ESocketAccept: 208 | case OpenSocket::ESocketUdp: 209 | assert(false); 210 | break; 211 | default: 212 | break; 213 | } 214 | } 215 | std::map mapFdToTask_; 216 | public: 217 | static bool Http(std::shared_ptr& request) 218 | { 219 | if (request->ip_.empty()) 220 | { 221 | assert(false); 222 | return false; 223 | } 224 | request->response_.code_ = -1; 225 | auto worker = Instance_.getWorker(); 226 | if (!worker) return false; 227 | auto proto = std::shared_ptr(new TaskProto); 228 | proto->request_ = request; 229 | bool ret = OpenThread::Send(worker->pid(), proto); 230 | assert(ret); 231 | proto->openSync_.await(); 232 | return ret; 233 | } 234 | }; 235 | HttpClient::Factory HttpClient::Instance_; 236 | 237 | int main() 238 | { 239 | auto request = std::shared_ptr(new HttpRequest); 240 | //Stock Market Latest Dragon and Tiger List 241 | request->setUrl("http://reportdocs.static.szse.cn/files/text/jy/jy230308.txt"); 242 | request->method_ = "GET"; 243 | 244 | (*request)["Host"] = "reportdocs.static.szse.cn"; 245 | (*request)["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"; 246 | (*request)["Accept-Encoding"] = "gzip,deflate"; 247 | (*request)["Accept-Language"] = "zh-CN,zh;q=0.9"; 248 | (*request)["Cache-Control"] = "max-age=0"; 249 | (*request)["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"; 250 | (*request)["Upgrade-Insecure-Requests"] = "1"; 251 | 252 | HttpClient::Http(request); 253 | auto& response = request->response_; 254 | printf("code:%d, header:%s\n", response.code_, response.head_.c_str()); 255 | return getchar(); 256 | } 257 | 258 | 259 | void HttpRequest::setUrl(const std::string& url) 260 | { 261 | if (url.empty()) return; 262 | url_ = url; 263 | int len = (int)url.length(); 264 | char* ptr = (char*)url.c_str(); 265 | if (len >= 8) 266 | { 267 | if (memcmp(ptr, "http://", strlen("http://")) == 0) 268 | ptr += strlen("http://"); 269 | else if (memcmp(ptr, "https://", strlen("https://")) == 0) 270 | ptr += strlen("https://"); 271 | } 272 | const char* tmp = strstr(ptr, "/"); 273 | path_.clear(); 274 | if (tmp != 0) 275 | { 276 | path_.append(tmp); 277 | host_.clear(); 278 | host_.append(ptr, tmp - ptr); 279 | } 280 | else 281 | { 282 | host_ = ptr; 283 | } 284 | port_ = 80; 285 | ip_.clear(); 286 | ptr = (char*)host_.c_str(); 287 | tmp = strstr(ptr, ":"); 288 | if (tmp != 0) 289 | { 290 | ip_.append(ptr, tmp - ptr); 291 | tmp += 1; 292 | port_ = atoi(tmp); 293 | } 294 | else 295 | { 296 | ip_ = ptr; 297 | } 298 | ip_ = OpenSocket::DomainNameToIp(ip_); 299 | } 300 | 301 | 302 | void HttpRequest::HttpResponse::parseHeader() 303 | { 304 | if (!headers_.empty() || head_.size() < 12) return; 305 | std::string line; 306 | const char* ptr = strstr(head_.c_str(), "\r\n"); 307 | if (!ptr) return; 308 | code_ = 0; 309 | clen_ = 0; 310 | line.append(head_.c_str(), ptr - head_.c_str()); 311 | for (size_t i = 0; i < line.size(); i++) 312 | { 313 | if (line[i] == ' ') 314 | { 315 | while (i < line.size() && line[i] == ' ') ++i; 316 | code_ = std::atoi(line.data() + i); 317 | break; 318 | } 319 | } 320 | if (code_ <= 0) return; 321 | line.clear(); 322 | int k = -1; 323 | int j = -1; 324 | std::string key; 325 | std::string value; 326 | for (size_t i = ptr - head_.c_str() + 2; i < head_.size() - 1; i++) 327 | { 328 | if (head_[i] == '\r' && head_[i + 1] == '\n') 329 | { 330 | if (j > 0) 331 | { 332 | k = 0; 333 | while (k < line.size() && line[k] == ' ') ++k; 334 | while (k >= 0 && line.back() == ' ') line.pop_back(); 335 | value = line.data() + j + 1; 336 | while (j >= 0 && line[j] == ' ') j--; 337 | key.clear(); 338 | key.append(line.data(), j); 339 | for (size_t x = 0; x < key.size(); x++) 340 | key[x] = std::tolower(key[x]); 341 | headers_[key] = value; 342 | } 343 | ++i; 344 | j = -1; 345 | line.clear(); 346 | continue; 347 | } 348 | line.push_back(head_[i]); 349 | if (j < 0 && line.back() == ':') 350 | { 351 | j = (int)line.size() - 1; 352 | } 353 | } 354 | clen_ = std::atoi(headers_["content-length"].c_str()); 355 | } 356 | 357 | bool HttpRequest::HttpResponse::pushData(const char* data, size_t size) 358 | { 359 | if (code_ == -1) 360 | { 361 | head_.append(data, size); 362 | const char* ptr = strstr(head_.data(), "\r\n\r\n"); 363 | if (!ptr) return false; 364 | code_ = 0; 365 | body_.append(ptr + 4); 366 | head_.resize(ptr - head_.data() + 2); 367 | parseHeader(); 368 | } 369 | else 370 | { 371 | body_.append(data, size); 372 | } 373 | if (clen_ > 0) 374 | { 375 | if (clen_ >= body_.size()) 376 | { 377 | body_.resize(clen_); 378 | return true; 379 | } 380 | } 381 | else if (body_.size() > 2) 382 | { 383 | if (body_[body_.size() - 2] == '\r' && body_.back() == '\n') 384 | { 385 | body_.pop_back(); 386 | body_.pop_back(); 387 | return true; 388 | } 389 | } 390 | return false; 391 | } -------------------------------------------------------------------------------- /test/httpserver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "opensocket.h" 7 | #include "open/openthread.h" 8 | using namespace open; 9 | 10 | const std::string TestServerIp_ = "0.0.0.0"; 11 | const int TestServerPort_ = 8888; 12 | 13 | //msgType == 1 14 | struct SocketProto : public OpenThreadProto 15 | { 16 | std::shared_ptr data_; 17 | static inline int ProtoType() { return 1; } 18 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 19 | }; 20 | 21 | //msgType == 2 22 | struct RegisterProto : public OpenThreadProto 23 | { 24 | int srcPid_; 25 | static inline int ProtoType() { return 2; } 26 | virtual inline int protoType() const { return RegisterProto::ProtoType(); } 27 | RegisterProto() :srcPid_(-1) {} 28 | }; 29 | 30 | //msgType == 3 31 | struct NewClientProto : public OpenThreadProto 32 | { 33 | int accept_fd_; 34 | std::string addr_; 35 | static inline int ProtoType() { return 3; } 36 | virtual inline int protoType() const { return NewClientProto::ProtoType(); } 37 | NewClientProto() : accept_fd_(-1) {} 38 | }; 39 | 40 | ////////////App////////////////////// 41 | class App 42 | { 43 | static void SocketFunc(const OpenSocketMsg* msg) 44 | { 45 | if (!msg) return; 46 | if (msg->uid_ >= 0) 47 | { 48 | auto proto = std::shared_ptr(new SocketProto); 49 | proto->srcPid_ = -1; 50 | proto->srcName_ = "OpenSocket"; 51 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 52 | if (!OpenThread::Send((int)msg->uid_, proto)) 53 | printf("SocketFunc dispatch faild pid = %d\n", (int)msg->uid_); 54 | } 55 | else 56 | { 57 | delete msg; 58 | } 59 | } 60 | public: 61 | static App Instance_; 62 | App() { OpenSocket::Start(App::SocketFunc); } 63 | }; 64 | App App::Instance_; 65 | 66 | ////////////Listener////////////////////// 67 | class Listener : public OpenThreadWorker 68 | { 69 | int listen_fd_; 70 | unsigned int balance_; 71 | std::set setSlaveId_; 72 | std::vector vectSlaveId_; 73 | public: 74 | Listener(const std::string& name) 75 | :OpenThreadWorker(name), 76 | listen_fd_(-1) 77 | { 78 | balance_ = 0; 79 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Listener::onSocketProto); 80 | registers(RegisterProto::ProtoType(), (OpenThreadHandle)&Listener::onRegisterProto); 81 | } 82 | virtual ~Listener() {} 83 | virtual void onStart() 84 | { 85 | listen_fd_ = OpenSocket::Instance().listen((uintptr_t)pid(), TestServerIp_, TestServerPort_, 64); 86 | if (listen_fd_ < 0) 87 | { 88 | printf("Listener::onStart faild listen_fd_ = %d\n", listen_fd_); 89 | assert(false); 90 | } 91 | OpenSocket::Instance().start((uintptr_t)pid(), listen_fd_); 92 | printf("HTTP: %s:%d\n", TestServerIp_.c_str(), TestServerPort_); 93 | } 94 | void onRegisterProto(const RegisterProto& proto) 95 | { 96 | if (proto.srcPid_ >= 0) 97 | { 98 | if (setSlaveId_.find(proto.srcPid_) == setSlaveId_.end()) 99 | { 100 | setSlaveId_.insert(proto.srcPid_); 101 | vectSlaveId_.push_back(proto.srcPid_); 102 | printf("Hello OpenSocket HttpServer, srcPid = %d\n", proto.srcPid_); 103 | } 104 | } 105 | } 106 | // new client socket dispatch to Accept 107 | void notifyToSlave(int accept_fd, const std::string& addr) 108 | { 109 | if (!vectSlaveId_.empty()) 110 | { 111 | auto proto = std::shared_ptr(new NewClientProto); 112 | proto->accept_fd_ = accept_fd; 113 | proto->addr_ = addr; 114 | if (balance_ >= vectSlaveId_.size()) 115 | { 116 | balance_ = 0; 117 | } 118 | int slaveId = vectSlaveId_[balance_++]; 119 | if (OpenThread::Send(slaveId, proto)) 120 | { 121 | return; 122 | } 123 | printf("Listener::notifyToSlave send faild pid = %d\n", slaveId); 124 | } 125 | OpenSocket::Instance().close(pid_, accept_fd); 126 | } 127 | void onSocketProto(const SocketProto& proto) 128 | { 129 | const auto& msg = proto.data_; 130 | switch (msg->type_) 131 | { 132 | case OpenSocket::ESocketAccept: 133 | // linsten new client socket 134 | notifyToSlave(msg->ud_, msg->data()); 135 | printf("Listener::onSocket [%s]ESocketAccept:acceptFd = %d\n", ThreadName((int)msg->uid_).c_str(), msg->ud_); 136 | break; 137 | case OpenSocket::ESocketClose: 138 | break; 139 | case OpenSocket::ESocketError: 140 | printf("Listener::onSocket [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 141 | break; 142 | case OpenSocket::ESocketWarning: 143 | printf("Listener::onSocket [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 144 | break; 145 | case OpenSocket::ESocketOpen: 146 | break; 147 | case OpenSocket::ESocketUdp: 148 | case OpenSocket::ESocketData: 149 | assert(false); 150 | break; 151 | default: 152 | break; 153 | } 154 | } 155 | }; 156 | 157 | ////////////HttpRequest////////////////////// 158 | struct HttpRequest 159 | { 160 | int fd_; 161 | std::string addr_; 162 | 163 | std::string method_; 164 | std::string url_; 165 | 166 | int code_; 167 | int clen_; 168 | std::string head_; 169 | std::string body_; 170 | std::map headers_; 171 | HttpRequest() :fd_(-1), code_(-1), clen_(-1) {} 172 | 173 | //GET /xx/xx HTTP/x.x 174 | bool parseHeader(); 175 | bool pushData(const char* data, size_t size); 176 | }; 177 | 178 | ////////////Accepter////////////////////// 179 | class Accepter : public OpenThreadWorker 180 | { 181 | int listenId_; 182 | std::map mapClient_; 183 | public: 184 | Accepter(const std::string& name) 185 | :OpenThreadWorker(name), 186 | listenId_(-1) 187 | { 188 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Accepter::onSocketProto); 189 | registers(NewClientProto::ProtoType(), (OpenThreadHandle)&Accepter::onNewClientProto); 190 | } 191 | virtual ~Accepter() {} 192 | virtual void onStart() 193 | { 194 | while (listenId_ < 0) 195 | { 196 | listenId_ = ThreadId("listener"); 197 | OpenThread::Sleep(1000); 198 | } 199 | auto proto = std::shared_ptr(new RegisterProto); 200 | proto->srcPid_ = pid(); 201 | if (OpenThread::Send(listenId_, proto)) 202 | return; 203 | printf("Accepter::onStart send faild pid = %d\n", listenId_); 204 | } 205 | void onNewClientProto(const NewClientProto& proto) 206 | { 207 | int accept_fd = proto.accept_fd_; 208 | if (accept_fd >= 0) 209 | { 210 | auto iter = mapClient_.find(accept_fd); 211 | if (iter != mapClient_.end()) 212 | { 213 | assert(false); 214 | mapClient_.erase(iter); 215 | OpenSocket::Instance().close(pid(), accept_fd); 216 | return; 217 | } 218 | auto& client = mapClient_[accept_fd]; 219 | client.fd_ = accept_fd; 220 | client.addr_ = proto.addr_; 221 | OpenSocket::Instance().start(pid_, accept_fd); 222 | } 223 | } 224 | //GET /xx/xx HTTP/x.x 225 | void onReadHttp(const std::shared_ptr msg) 226 | { 227 | auto iter = mapClient_.find(msg->fd_); 228 | if (iter == mapClient_.end()) 229 | { 230 | OpenSocket::Instance().close(pid_, msg->fd_); 231 | return; 232 | } 233 | auto& request = iter->second; 234 | if (!request.pushData(msg->data(), msg->size())) 235 | { 236 | //Header too large.close connet. 237 | if (request.head_.size() > 1024) 238 | OpenSocket::Instance().close(pid_, msg->fd_); 239 | return; 240 | } 241 | printf("new client:url = %s\n", request.url_.c_str()); 242 | std::string content; 243 | content.append("
It's work!

" + request.addr_ + "request:" + request.url_); 244 | std::string buffer = "HTTP/1.1 200 OK\r\ncontent-length:" + std::to_string(content.size()) + "\r\n\r\n" + content; 245 | OpenSocket::Instance().send(msg->fd_, buffer.data(), (int)buffer.size()); 246 | } 247 | virtual void onSocketProto(const SocketProto& proto) 248 | { 249 | const auto& msg = proto.data_; 250 | switch (msg->type_) 251 | { 252 | case OpenSocket::ESocketData: 253 | onReadHttp(msg); 254 | break; 255 | case OpenSocket::ESocketClose: 256 | mapClient_.erase(msg->fd_); 257 | break; 258 | case OpenSocket::ESocketError: 259 | mapClient_.erase(msg->fd_); 260 | printf("Accepter::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 261 | break; 262 | case OpenSocket::ESocketWarning: 263 | printf("Accepter::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 264 | break; 265 | case OpenSocket::ESocketOpen: 266 | { 267 | auto iter = mapClient_.find(msg->fd_); 268 | if (iter == mapClient_.end()) 269 | { 270 | OpenSocket::Instance().close(pid_, msg->fd_); 271 | return; 272 | } 273 | } 274 | break; 275 | case OpenSocket::ESocketAccept: 276 | case OpenSocket::ESocketUdp: 277 | assert(false); 278 | break; 279 | default: 280 | break; 281 | } 282 | } 283 | }; 284 | int main() 285 | { 286 | printf("start server==>>\n"); 287 | std::vector vectServer = { 288 | new Listener("listener"), 289 | new Accepter("accepter1"), 290 | new Accepter("accepter2"), 291 | new Accepter("accepter3"), 292 | new Accepter("accepter4") 293 | }; 294 | for (size_t i = 0; i < vectServer.size(); ++i) 295 | vectServer[i]->start(); 296 | 297 | printf("wait close==>>\n"); 298 | OpenThread::ThreadJoinAll(); 299 | for (size_t i = 0; i < vectServer.size(); ++i) 300 | delete vectServer[i]; 301 | vectServer.clear(); 302 | 303 | printf("Pause\n"); 304 | return getchar(); 305 | } 306 | 307 | 308 | bool HttpRequest::parseHeader() 309 | { 310 | if (!headers_.empty() || head_.size() < 12) return true; 311 | std::string line; 312 | const char* ptr = strstr(head_.c_str(), "\r\n"); 313 | if (!ptr) return false; 314 | clen_ = -1; 315 | line.append(head_.c_str(), ptr - head_.c_str()); 316 | 317 | int state = 0; 318 | method_.clear(); 319 | url_.clear(); 320 | for (size_t k = 0; k < line.size(); ++k) 321 | { 322 | if (state == 0) 323 | { 324 | if (line[k] != ' ') 325 | { 326 | method_.push_back(line[k]); 327 | continue; 328 | } 329 | state = 1; 330 | while (k < line.size() && line[k] == ' ') ++k; 331 | if (line[k] != ' ') --k; 332 | } 333 | else 334 | { 335 | if (line[k] != ' ') 336 | { 337 | url_.push_back(line[k]); 338 | continue; 339 | } 340 | break; 341 | } 342 | } 343 | 344 | line.clear(); 345 | int k = -1; 346 | int j = -1; 347 | std::string key; 348 | std::string value; 349 | for (size_t i = ptr - head_.c_str() + 2; i < head_.size() - 1; i++) 350 | { 351 | if (head_[i] == '\r' && head_[i + 1] == '\n') 352 | { 353 | if (j > 0) 354 | { 355 | k = 0; 356 | while (k < line.size() && line[k] == ' ') ++k; 357 | while (k >= 0 && line.back() == ' ') line.pop_back(); 358 | value = line.data() + j + 1; 359 | while (j >= 0 && line[j] == ' ') j--; 360 | key.clear(); 361 | key.append(line.data(), j); 362 | for (size_t x = 0; x < key.size(); x++) 363 | key[x] = std::tolower(key[x]); 364 | headers_[key] = value; 365 | } 366 | ++i; 367 | j = -1; 368 | line.clear(); 369 | continue; 370 | } 371 | line.push_back(head_[i]); 372 | if (j < 0 && line.back() == ':') 373 | { 374 | j = (int)line.size() - 1; 375 | } 376 | } 377 | clen_ = std::atoi(headers_["content-length"].c_str()); 378 | return true; 379 | } 380 | 381 | bool HttpRequest::pushData(const char* data, size_t size) 382 | { 383 | if (code_ == -1) 384 | { 385 | head_.append(data, size); 386 | const char* ptr = strstr(head_.data(), "\r\n\r\n"); 387 | if (!ptr) return false; 388 | code_ = 0; 389 | body_.append(ptr + 4); 390 | head_.resize(ptr - head_.data() + 2); 391 | if (!parseHeader()) return false; 392 | } 393 | else 394 | { 395 | body_.append(data, size); 396 | } 397 | if (clen_ >= 0) 398 | { 399 | if (clen_ == 0 && clen_ == body_.size()) 400 | { 401 | return true; 402 | } 403 | if (clen_ >= body_.size()) 404 | { 405 | body_.resize(clen_); 406 | return true; 407 | } 408 | } 409 | else if (body_.size() > 2) 410 | { 411 | if (body_[body_.size() - 2] == '\r' && body_.back() == '\n') 412 | { 413 | body_.pop_back(); 414 | body_.pop_back(); 415 | return true; 416 | } 417 | } 418 | return false; 419 | } -------------------------------------------------------------------------------- /test/open/openthread.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2023-, openlinyou, 3 | * 4 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 5 | * copies of the Software, and permit persons to whom the Software is 6 | * furnished to do so, under the terms of the COPYING file. 7 | ***************************************************************************/ 8 | #include "openthread.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | #else 32 | #include 33 | #include 34 | #endif 35 | 36 | namespace open 37 | { 38 | 39 | OpenThread& OpenThread::Msg::thread() const 40 | { 41 | if (thread_) return *thread_; 42 | assert(false); 43 | static OpenThread emptyThread("NULL"); 44 | return emptyThread; 45 | } 46 | 47 | const int OpenThread::Msg::pid() const 48 | { 49 | if (thread_) 50 | { 51 | return thread_->pid_; 52 | } 53 | return -1; 54 | } 55 | const std::string& OpenThread::Msg::name() const 56 | { 57 | if (thread_) 58 | { 59 | return thread_->name_; 60 | } 61 | static const std::string empty; 62 | return empty; 63 | } 64 | 65 | // SafeQueue 66 | OpenThread::SafeQueue::SafeQueue() 67 | { 68 | head_.next_ = 0; 69 | tail_ = &head_; 70 | writeId_ = 0; 71 | readId_ = 0; 72 | } 73 | 74 | OpenThread::SafeQueue::~SafeQueue() 75 | { 76 | clear(); 77 | assert(vectCache_.empty()); 78 | } 79 | 80 | void OpenThread::SafeQueue::clear() 81 | { 82 | popAll(); 83 | for (size_t i = 0; i < vectCache_.size(); i++) 84 | { 85 | if (vectCache_[i]->id_ != readId_) 86 | { 87 | assert(false); 88 | } 89 | ++readId_; 90 | delete vectCache_[i]; 91 | } 92 | vectCache_.clear(); 93 | readId_ = 0; 94 | writeId_ = 0; 95 | } 96 | 97 | void OpenThread::SafeQueue::popAll() 98 | { 99 | //spinLock_.lock(); 100 | Node* node = head_.next_; 101 | head_.next_ = 0; 102 | tail_ = &head_; 103 | //spinLock_.unlock(); 104 | if (node) 105 | { 106 | assert(vectCache_.empty()); 107 | Node* tmpNode = 0; 108 | while (node) 109 | { 110 | vectCache_.push_back(node); 111 | tmpNode = node->next_; 112 | node->next_ = 0; 113 | node = tmpNode; 114 | } 115 | } 116 | } 117 | 118 | void OpenThread::SafeQueue::popAll(std::queue& queueCache) 119 | { 120 | popAll(); 121 | if (vectCache_.empty()) 122 | { 123 | return; 124 | } 125 | for (size_t i = 0; i < vectCache_.size(); i++) 126 | { 127 | if (vectCache_[i]->id_ != readId_) 128 | { 129 | assert(false); 130 | } 131 | ++readId_; 132 | queueCache.push(vectCache_[i]); 133 | } 134 | vectCache_.clear(); 135 | } 136 | 137 | void OpenThread::SafeQueue::push(OpenThread::Node* node) 138 | { 139 | spinLock_.lock(); 140 | node->id_ = writeId_++; 141 | tail_->next_ = node; 142 | tail_ = node; 143 | node->next_ = 0; 144 | spinLock_.unlock(); 145 | } 146 | 147 | //OpenThread 148 | OpenThread::OpenThread(const std::string& name) 149 | :state_(STOP), 150 | name_(name), 151 | pool_(0) 152 | { 153 | cb_ = 0; 154 | pid_ = -1; 155 | leftCount_ = 0; 156 | totalCount_ = 0; 157 | cpuCost_ = 0; 158 | cpuStart_ = 0; 159 | 160 | isIdle_ = false; 161 | custom_ = 0; 162 | memset(&threadId_, 0, sizeof(threadId_)); 163 | 164 | pthread_mutex_init(&mutex_, NULL); 165 | pthread_cond_init(&cond_, NULL); 166 | } 167 | 168 | OpenThread::OpenThread(const OpenThread&) 169 | { 170 | assert(false); 171 | pool_ = 0; 172 | cb_ = 0; 173 | pid_ = -1; 174 | leftCount_ = 0; 175 | totalCount_ = 0; 176 | cpuCost_ = 0; 177 | cpuStart_ = 0; 178 | isIdle_ = false; 179 | custom_ = 0; 180 | memset(&threadId_, 0, sizeof(threadId_)); 181 | 182 | pthread_mutex_init(&mutex_, NULL); 183 | pthread_cond_init(&cond_, NULL); 184 | } 185 | 186 | 187 | OpenThread::~OpenThread() 188 | { 189 | assert(state_ == STOP); 190 | cb_ = 0; 191 | pid_ = -1; 192 | isIdle_ = false; 193 | pthread_mutex_destroy(&mutex_); 194 | pthread_cond_destroy(&cond_); 195 | } 196 | 197 | bool OpenThread::start(void (*cb)(const Msg&)) 198 | { 199 | if (!pool_) 200 | { 201 | assert(false); 202 | return false; 203 | } 204 | OpenThreadRef ref; 205 | ref.thread_ = pool_->thread(name_); 206 | if (!ref) 207 | { 208 | assert(false); 209 | return false; 210 | } 211 | if (ref.pid() != pid_ || ref.name() != name_) 212 | { 213 | assert(false); 214 | return false; 215 | } 216 | pthread_mutex_lock(&mutex_); 217 | if (!cb) 218 | { 219 | assert(false); 220 | pthread_mutex_unlock(&mutex_); 221 | return false; 222 | } 223 | assert(state_ == STOP); 224 | if (state_ != STOP) 225 | { 226 | assert(false); 227 | pthread_mutex_unlock(&mutex_); 228 | return false; 229 | } 230 | state_ = START; 231 | 232 | cb_ = cb; 233 | readId_ = 0; 234 | leftCount_ = 0; 235 | totalCount_ = 0; 236 | 237 | cpuCost_ = 0; 238 | cpuStart_ = 0; 239 | 240 | memset(&threadId_, 0, sizeof(threadId_)); 241 | std::shared_ptr* ptr = new std::shared_ptr(ref.thread_); 242 | int ret = pthread_create(&threadId_, NULL, (void* (*)(void*))OpenThread::Run, ptr); 243 | if (ret != 0) 244 | { 245 | delete ptr; 246 | cb_ = 0; 247 | state_ = STOP; 248 | pthread_mutex_unlock(&mutex_); 249 | return false; 250 | } 251 | int count = 0; 252 | while (state_ != RUN) 253 | { 254 | OpenThread::Sleep(1); 255 | if (++count > 5000) 256 | { 257 | assert(false); 258 | cb_ = 0; 259 | state_ = STOP; 260 | break; 261 | } 262 | } 263 | pthread_mutex_unlock(&mutex_); 264 | return true; 265 | } 266 | 267 | bool OpenThread::stop() 268 | { 269 | //printf("OpenThread::stop==>>[%s]\n", name_.c_str()); 270 | if (state_ != RUN) return false; 271 | Node* node = new Node; 272 | Msg& msg = node->msg_; 273 | msg.state_ = STOP; 274 | msg.thread_ = 0; 275 | queue_.push(node); 276 | //if (isIdle_) 277 | pthread_cond_signal(&cond_); 278 | return true; 279 | } 280 | 281 | bool OpenThread::send(const std::shared_ptr& data) 282 | { 283 | //printf("OpenThread::send==>>[%s]\n", name_.c_str()); 284 | if (state_ != RUN) return false; 285 | Node* node = new Node; 286 | Msg& msg = node->msg_; 287 | msg.state_ = RUN; 288 | msg.data_ = data; 289 | msg.thread_ = 0; 290 | queue_.push(node); 291 | //if (isIdle_) 292 | pthread_cond_signal(&cond_); 293 | return true; 294 | } 295 | 296 | bool OpenThread::isCurrent() 297 | { 298 | return pthread_equal(pthread_self(), threadId_); 299 | } 300 | 301 | void OpenThread::waitIdle() 302 | { 303 | if (pthread_equal(pthread_self(), threadId_)) 304 | return; 305 | 306 | while (state_ == RUN && !isIdle_) Sleep(1); 307 | } 308 | 309 | void OpenThread::Run(void* arg) 310 | { 311 | assert(arg); 312 | if (!arg) return; 313 | std::shared_ptr* ptr = (std::shared_ptr*)arg; 314 | if (!*ptr) 315 | { 316 | delete ptr; 317 | return; 318 | } 319 | pthread_setname_np((*ptr)->threadId_, (*ptr)->name_.c_str()); 320 | (*ptr)->run(); 321 | delete ptr; 322 | } 323 | 324 | bool OpenThread::hasMsg() 325 | { 326 | assert(pthread_equal(pthread_self(), threadId_)); 327 | if (!queueCache_.empty()) 328 | { 329 | return true; 330 | } 331 | if (!queue_.empty()) 332 | { 333 | queue_.popAll(queueCache_); 334 | } 335 | return !queueCache_.empty(); 336 | } 337 | 338 | OpenThread::Node* OpenThread::popNode() 339 | { 340 | if (!queue_.empty()) 341 | { 342 | queue_.popAll(queueCache_); 343 | } 344 | Node* node = 0; 345 | if (!queueCache_.empty()) 346 | { 347 | totalCount_++; 348 | leftCount_ = queueCache_.size(); 349 | node = queueCache_.front(); 350 | queueCache_.pop(); 351 | } 352 | return node; 353 | } 354 | 355 | void OpenThread::run() 356 | { 357 | assert(state_ == START); 358 | if (state_ != START) return; 359 | state_ = RUN; 360 | assert(pthread_equal(pthread_self(), threadId_)); 361 | { 362 | Msg msg; 363 | msg.thread_ = this; 364 | msg.state_ = START; 365 | cb_(msg); 366 | } 367 | Node* node = 0; 368 | isIdle_ = false; 369 | bool isRunning = true; 370 | assert(queueCache_.empty()); 371 | while (state_ == RUN) 372 | { 373 | while ((node = popNode())) 374 | { 375 | if (node->msg_.state_ == STOP) 376 | { 377 | node->msg_.thread_ = this; 378 | if (node->id_ != readId_) 379 | { 380 | printf("OpenThread[%s] node->id_:%d, readId_:%d\n", name_.c_str(), node->id_, readId_); 381 | assert(false); 382 | } 383 | ++readId_; 384 | cb_(node->msg_); 385 | delete node; 386 | isRunning = false; 387 | break; 388 | } 389 | if (profile_) 390 | { 391 | cpuStart_ = ThreadTime(); 392 | node->msg_.thread_ = this; 393 | if (node->id_ != readId_) 394 | { 395 | printf("OpenThread[%s] node->id_:%d, readId_:%d\n", name_.c_str(), node->id_, readId_); 396 | assert(false); 397 | } 398 | ++readId_; 399 | cb_(node->msg_); 400 | cpuCost_ += ThreadTime() - cpuStart_; 401 | } 402 | else 403 | { 404 | node->msg_.thread_ = this; 405 | if (node->id_ != readId_) 406 | { 407 | printf("OpenThread[%s] node->id_:%d, readId_:%d\n", name_.c_str(), node->id_, readId_); 408 | assert(false); 409 | } 410 | ++readId_; 411 | cb_(node->msg_); 412 | } 413 | delete node; 414 | } 415 | if (!isRunning) break; 416 | 417 | isIdle_ = true; 418 | pthread_mutex_lock(&mutex_); 419 | pthread_cond_wait(&cond_, &mutex_); 420 | isIdle_ = false; 421 | pthread_mutex_unlock(&mutex_); 422 | } 423 | //printf("OpenThread[%s] exit\n", name_.c_str()); 424 | state_ = STOP; 425 | pthread_mutex_lock(&mutex_); 426 | while (!queueCache_.empty()) 427 | { 428 | node = queueCache_.front(); 429 | queueCache_.pop(); 430 | delete node; 431 | } 432 | queue_.clear(); 433 | pthread_mutex_unlock(&mutex_); 434 | //printf("OpenThread[%s] exit===>>\n", name_.c_str()); 435 | } 436 | 437 | // static method 438 | OpenThreadPool OpenThread::DefaultPool_; 439 | bool OpenThread::Init(size_t capacity, bool profile) 440 | { 441 | return DefaultPool_.init(capacity, profile); 442 | } 443 | 444 | OpenThreadRef OpenThread::Create(const std::string& name) 445 | { 446 | OpenThreadRef ref; 447 | ref.thread_ = DefaultPool_.create(name); 448 | return ref; 449 | } 450 | 451 | OpenThreadRef OpenThread::Create(const std::string& name, void (*cb)(const Msg&)) 452 | { 453 | OpenThreadRef ref; 454 | ref.thread_ = DefaultPool_.create(name, cb); 455 | return ref; 456 | } 457 | 458 | OpenThreadRef OpenThread::Thread(int pid) 459 | { 460 | OpenThreadRef ref; 461 | ref.thread_ = DefaultPool_.thread(pid); 462 | return ref; 463 | } 464 | 465 | OpenThreadRef OpenThread::Thread(const std::string& name) 466 | { 467 | OpenThreadRef ref; 468 | ref.thread_ = DefaultPool_.thread(name); 469 | return ref; 470 | } 471 | 472 | const std::string& OpenThread::ThreadName(int pid) 473 | { 474 | return DefaultPool_.threadName(pid); 475 | } 476 | 477 | int OpenThread::ThreadId(const std::string& name) 478 | { 479 | return DefaultPool_.threadId(name); 480 | } 481 | 482 | size_t OpenThread::GetThreadCapacity() 483 | { 484 | return DefaultPool_.capacity(); 485 | } 486 | 487 | size_t OpenThread::GetThreadSize() 488 | { 489 | return DefaultPool_.size(); 490 | } 491 | 492 | bool OpenThread::Send(int pid, const std::shared_ptr& data) 493 | { 494 | return DefaultPool_.send(pid, data); 495 | } 496 | 497 | bool OpenThread::Send(const std::string& name, const std::shared_ptr& data) 498 | { 499 | return DefaultPool_.send(name, data); 500 | } 501 | 502 | bool OpenThread::Send(const std::vector& vectPid, const std::shared_ptr& data) 503 | { 504 | return DefaultPool_.send(vectPid, data); 505 | } 506 | 507 | bool OpenThread::Send(const std::vector& vectName, const std::shared_ptr& data) 508 | { 509 | return DefaultPool_.send(vectName, data); 510 | } 511 | 512 | bool OpenThread::Stop(int pid) 513 | { 514 | return DefaultPool_.stop(pid); 515 | } 516 | 517 | bool OpenThread::Stop(const std::string& name) 518 | { 519 | return DefaultPool_.stop(name); 520 | } 521 | 522 | void OpenThread::StopAll() 523 | { 524 | DefaultPool_.stopAll(); 525 | } 526 | 527 | std::shared_ptr OpenThread::GetThread(OpenThreadRef& ref) 528 | { 529 | return ref.thread_; 530 | } 531 | 532 | void OpenThread::ThreadJoin(OpenThreadRef& ref) 533 | { 534 | DefaultPool_.threadJoin(ref.thread_); 535 | } 536 | 537 | void OpenThread::ThreadJoin(const std::vector& vectPid) 538 | { 539 | DefaultPool_.threadJoin(vectPid); 540 | } 541 | 542 | void OpenThread::ThreadJoin(const std::vector& vectName) 543 | { 544 | DefaultPool_.threadJoin(vectName); 545 | } 546 | 547 | void OpenThread::ThreadJoinAll() 548 | { 549 | DefaultPool_.threadJoinAll(); 550 | } 551 | 552 | //OpenThreader 553 | bool OpenThreader::start() 554 | { 555 | auto threadRef = OpenThread::Thread(name_); 556 | if (threadRef) 557 | { 558 | printf("OpenThreader::start. [%s] is exist\n", name_.c_str()); 559 | assert(false); 560 | return false; 561 | } 562 | threadRef = OpenThread::Create(name_); 563 | assert(threadRef); 564 | pid_ = -1; 565 | if (threadRef) 566 | { 567 | thread_ = OpenThread::GetThread(threadRef); 568 | pid_ = thread_->pid(); 569 | assert(!thread_->isRunning()); 570 | thread_->setCustom(this); 571 | thread_->start(OpenThreader::Thread); 572 | return true; 573 | } 574 | return false; 575 | } 576 | void OpenThreader::stop() 577 | { 578 | auto threadRef = OpenThread::Thread(name_); 579 | if (threadRef) 580 | { 581 | assert(threadRef == thread_); 582 | if (threadRef.isRunning()) 583 | { 584 | threadRef.stop(); 585 | threadRef.waitStop(); 586 | } 587 | } 588 | else 589 | thread_.reset(); 590 | } 591 | 592 | void OpenThreader::Thread(OpenThreadMsg& msg) 593 | { 594 | OpenThreader* that = msg.custom(); 595 | if (!that) 596 | { 597 | assert(false); return; 598 | } 599 | switch (msg.state_) 600 | { 601 | case OpenThread::RUN: 602 | that->onMsg(msg); return; 603 | case OpenThread::START: 604 | that->onStart(); return; 605 | case OpenThread::STOP: 606 | that->onStop(); return; 607 | default: 608 | assert(false); return; 609 | } 610 | } 611 | 612 | // SafeMap 613 | OpenThreadPool::SafeMap::SafeMap() 614 | :capacity_(0) 615 | { 616 | } 617 | 618 | OpenThreadPool::SafeMap::SafeMap(const SafeMap& that) 619 | :capacity_(0) 620 | { 621 | assert(false); 622 | } 623 | 624 | OpenThreadPool::SafeMap::SafeMap(size_t capacity) 625 | :capacity_(0) 626 | { 627 | setCapacity(capacity); 628 | } 629 | 630 | OpenThreadPool::SafeMap::~SafeMap() 631 | { 632 | } 633 | 634 | void OpenThreadPool::SafeMap::setCapacity(size_t capacity) 635 | { 636 | if (capacity_ > 0) 637 | { 638 | assert(false); 639 | return; 640 | } 641 | capacity_ = capacity; 642 | vectKeys_.resize(capacity, std::shared_ptr()); 643 | vectValues_.resize(capacity, std::shared_ptr()); 644 | } 645 | 646 | bool OpenThreadPool::SafeMap::isFull() 647 | { 648 | for (size_t i = 0; i < vectKeys_.size(); i++) 649 | { 650 | if (!vectKeys_[i]) return false; 651 | } 652 | return true; 653 | } 654 | 655 | size_t OpenThreadPool::SafeMap::size() 656 | { 657 | for (size_t i = 0; i < vectKeys_.size(); i++) 658 | { 659 | if (!vectKeys_[i]) return i; 660 | } 661 | return vectKeys_.size(); 662 | } 663 | 664 | std::shared_ptr OpenThreadPool::SafeMap::operator[](size_t pid) 665 | { 666 | assert(capacity_ == vectKeys_.size()); 667 | assert(vectValues_.size() == vectKeys_.size()); 668 | std::shared_ptr ret; 669 | if (pid < vectValues_.size()) 670 | { 671 | ret = vectValues_[pid]; 672 | } 673 | if (ret) 674 | { 675 | assert(ret->pid() == pid); 676 | } 677 | return ret; 678 | } 679 | 680 | std::shared_ptr OpenThreadPool::SafeMap::operator[](const std::string& name) 681 | { 682 | assert(capacity_ == vectKeys_.size()); 683 | assert(vectValues_.size() == vectKeys_.size()); 684 | size_t i = 0; 685 | std::shared_ptr sptrKey; 686 | std::shared_ptr ret; 687 | for (; i < vectKeys_.size(); i++) 688 | { 689 | sptrKey = vectKeys_[i]; 690 | if (!sptrKey) break; 691 | if (sptrKey->compare(name) == 0) 692 | { 693 | ret = vectValues_[i]; 694 | if (ret) 695 | { 696 | assert(ret->pid() == i); 697 | } 698 | break; 699 | } 700 | } 701 | return ret; 702 | } 703 | 704 | int OpenThreadPool::SafeMap::set(std::shared_ptr& value) 705 | { 706 | if (!value) return -1; 707 | if (value->pid() != -1) return -1; 708 | assert(capacity_ == vectKeys_.size()); 709 | assert(vectValues_.size() == vectKeys_.size()); 710 | std::shared_ptr sptrKey; 711 | int pid = -1; 712 | std::string name = value->name(); 713 | for (int i = 0; i < (int)vectKeys_.size(); i++) 714 | { 715 | sptrKey = vectKeys_[i]; 716 | if (!sptrKey) 717 | { 718 | pid = i; 719 | vectValues_[pid] = value; 720 | vectKeys_[pid] = std::shared_ptr(new const std::string(name)); 721 | break; 722 | } 723 | if (sptrKey->compare(name) == 0) 724 | { 725 | pid = i; 726 | vectValues_[pid] = value; 727 | break; 728 | } 729 | } 730 | if (pid != -1 && value) 731 | { 732 | value->pid_ = pid; 733 | } 734 | return pid; 735 | } 736 | 737 | void OpenThreadPool::SafeMap::clear() 738 | { 739 | assert(capacity_ == vectKeys_.size()); 740 | assert(vectValues_.size() == vectKeys_.size()); 741 | for (size_t i = 0; i < vectKeys_.size(); ++i) 742 | { 743 | vectKeys_[i].reset(); 744 | vectValues_[i].reset(); 745 | } 746 | } 747 | 748 | // OpenThreadPool 749 | OpenThreadPool::OpenThreadPool() 750 | :profile_(false), 751 | isInit_(false), 752 | isClearIng_(false) 753 | { 754 | pthread_mutex_init(&mutex_, NULL); 755 | pthread_mutex_init(&mutex_close_, NULL); 756 | } 757 | 758 | OpenThreadPool::~OpenThreadPool() 759 | { 760 | pthread_mutex_destroy(&mutex_); 761 | pthread_mutex_destroy(&mutex_close_); 762 | } 763 | 764 | void OpenThreadPool::lock() 765 | { 766 | pthread_mutex_lock(&mutex_); 767 | } 768 | 769 | void OpenThreadPool::unlock() 770 | { 771 | pthread_mutex_unlock(&mutex_); 772 | } 773 | 774 | bool OpenThreadPool::init(size_t capacity, bool profile) 775 | { 776 | lock(); 777 | if (isClearIng_) 778 | { 779 | unlock(); 780 | return false; 781 | } 782 | if (isInit_) 783 | { 784 | unlock(); 785 | assert(false); 786 | return true; 787 | } 788 | isInit_ = true; 789 | profile_ = profile; 790 | safeMap_.setCapacity(capacity); 791 | unlock(); 792 | return true; 793 | } 794 | 795 | size_t OpenThreadPool::size() 796 | { 797 | lock(); 798 | if (isClearIng_) 799 | { 800 | unlock(); 801 | return 0; 802 | } 803 | if (!isInit_) 804 | { 805 | unlock(); 806 | if (!checkInit()) 807 | { 808 | if (!init(256, true)) 809 | { 810 | return 0; 811 | } 812 | } 813 | lock(); 814 | } 815 | size_t size = safeMap_.size(); 816 | unlock(); 817 | return size; 818 | } 819 | 820 | size_t OpenThreadPool::capacity() 821 | { 822 | lock(); 823 | if (isClearIng_) 824 | { 825 | unlock(); 826 | return 0; 827 | } 828 | if (!isInit_) 829 | { 830 | unlock(); 831 | if (!checkInit()) 832 | { 833 | if (!init(256, true)) 834 | { 835 | return 0; 836 | } 837 | } 838 | lock(); 839 | } 840 | size_t cap = safeMap_.capacity(); 841 | unlock(); 842 | return cap; 843 | } 844 | 845 | bool OpenThreadPool::checkInit() 846 | { 847 | lock(); 848 | if (isClearIng_) 849 | { 850 | unlock(); 851 | return false; 852 | } 853 | if (!isInit_) 854 | { 855 | unlock(); 856 | return false; 857 | } 858 | unlock(); 859 | return true; 860 | } 861 | 862 | void OpenThreadPool::stopAll() 863 | { 864 | if (isClearIng_) 865 | { 866 | return; 867 | } 868 | pthread_mutex_lock(&mutex_close_); 869 | isClearIng_ = true; 870 | if (!isInit_) 871 | { 872 | isClearIng_ = false; 873 | pthread_mutex_unlock(&mutex_close_); 874 | return; 875 | } 876 | std::shared_ptr sptr; 877 | std::string name; 878 | for (size_t i = 0; i < safeMap_.capacity(); i++) 879 | { 880 | sptr = safeMap_[i]; 881 | if (!sptr) continue; 882 | if (sptr->isRunning()) 883 | { 884 | //sptr->waitIdle(); 885 | sptr->stop(); 886 | int count = 1; 887 | while (sptr->isRunning()) 888 | { 889 | if (sptr->isCurrent()) break; 890 | OpenThread::Sleep(100); 891 | ++count; 892 | if (count == 5 || count == 10) 893 | { 894 | sptr->stop(); 895 | } 896 | } 897 | } 898 | } 899 | safeMap_.clear(); 900 | isClearIng_ = false; 901 | pthread_mutex_unlock(&mutex_close_); 902 | } 903 | 904 | std::shared_ptr OpenThreadPool::create(const std::string& name) 905 | { 906 | std::shared_ptr sptr; 907 | if (name.empty()) 908 | { 909 | assert(false); 910 | return sptr; 911 | } 912 | if (!isInit_) 913 | { 914 | if (!checkInit()) 915 | { 916 | if (!init(256, true)) 917 | { 918 | return sptr; 919 | } 920 | } 921 | } 922 | sptr = safeMap_[name]; 923 | if (!sptr) 924 | { 925 | lock(); 926 | sptr = safeMap_[name]; 927 | if (!sptr) 928 | { 929 | if (!safeMap_.isFull()) 930 | { 931 | sptr = std::shared_ptr(new OpenThread(name)); 932 | sptr->pool_ = this; 933 | if (!safeMap_.set(sptr)) 934 | { 935 | unlock(); 936 | return sptr; 937 | } 938 | } 939 | sptr = safeMap_[name]; 940 | } 941 | unlock(); 942 | } 943 | else 944 | { 945 | assert(sptr->name() == name); 946 | } 947 | return sptr; 948 | } 949 | 950 | std::shared_ptr OpenThreadPool::create(const std::string& name, void (*cb)(const OpenThread::Msg&)) 951 | { 952 | std::shared_ptr sptr = create(name); 953 | if (sptr && cb) 954 | { 955 | if (!sptr->isRunning()) 956 | { 957 | sptr->start(cb); 958 | } 959 | else 960 | { 961 | assert(sptr->cb_ == cb); 962 | } 963 | } 964 | return sptr; 965 | } 966 | 967 | std::shared_ptr OpenThreadPool::thread(int pid) 968 | { 969 | std::shared_ptr sptr; 970 | if (pid < 0 || pid >= capacity()) 971 | { 972 | return sptr; 973 | } 974 | if (!isInit_) 975 | { 976 | if (!checkInit()) return sptr; 977 | } 978 | sptr = safeMap_[pid]; 979 | if (sptr) 980 | { 981 | assert(sptr->pid() == pid); 982 | assert(sptr->pool_ == this); 983 | } 984 | return sptr; 985 | } 986 | 987 | std::shared_ptr OpenThreadPool::thread(const std::string& name) 988 | { 989 | std::shared_ptr sptr; 990 | if (!isInit_) 991 | { 992 | if (!checkInit()) return sptr; 993 | } 994 | sptr = safeMap_[name]; 995 | if (sptr) 996 | { 997 | assert(sptr->name() == name); 998 | assert(sptr->pool_ == this); 999 | } 1000 | return sptr; 1001 | } 1002 | 1003 | const std::string& OpenThreadPool::threadName(int pid) 1004 | { 1005 | static std::string emtpyString; 1006 | if (pid < 0 || pid >= capacity()) 1007 | { 1008 | return emtpyString; 1009 | } 1010 | if (!isInit_) 1011 | { 1012 | if (!checkInit()) return emtpyString; 1013 | } 1014 | std::shared_ptr sptr = safeMap_[pid]; 1015 | if (sptr) 1016 | { 1017 | assert(sptr->pool_ == this); 1018 | assert(sptr->pid() == pid); 1019 | return sptr->name(); 1020 | } 1021 | return emtpyString; 1022 | } 1023 | 1024 | int OpenThreadPool::threadId(const std::string& name) 1025 | { 1026 | if (!isInit_) 1027 | { 1028 | if (!checkInit()) return -1; 1029 | } 1030 | std::shared_ptr sptr = safeMap_[name]; 1031 | if (sptr) 1032 | { 1033 | assert(sptr->pool_ == this); 1034 | assert(sptr->name() == name); 1035 | return sptr->pid(); 1036 | } 1037 | return -1; 1038 | } 1039 | 1040 | bool OpenThreadPool::send(int pid, const std::shared_ptr& data) 1041 | { 1042 | if (pid < 0 || pid >= capacity()) 1043 | { 1044 | return false; 1045 | } 1046 | if (!isInit_) 1047 | { 1048 | if (!checkInit()) return false; 1049 | } 1050 | std::shared_ptr sptr = safeMap_[pid]; 1051 | if (sptr && sptr->isRunning()) 1052 | { 1053 | assert(sptr->pool_ == this); 1054 | assert(sptr->pid() == pid); 1055 | return sptr->send(data); 1056 | } 1057 | return false; 1058 | } 1059 | 1060 | bool OpenThreadPool::send(const std::string& name, const std::shared_ptr& data) 1061 | { 1062 | if (!isInit_) 1063 | { 1064 | if (!checkInit()) return false; 1065 | } 1066 | std::shared_ptr sptr = safeMap_[name]; 1067 | if (sptr && sptr->isRunning()) 1068 | { 1069 | assert(sptr->pool_ == this); 1070 | assert(sptr->name() == name); 1071 | return sptr->send(data); 1072 | } 1073 | return false; 1074 | } 1075 | 1076 | bool OpenThreadPool::send(const std::vector& vectPid, const std::shared_ptr& data) 1077 | { 1078 | if (!isInit_) 1079 | { 1080 | if (!checkInit()) return false; 1081 | } 1082 | std::shared_ptr sptr; 1083 | bool ret = true; 1084 | for (size_t i = 0; i < vectPid.size(); i++) 1085 | { 1086 | sptr = safeMap_[vectPid[i]]; 1087 | if (sptr && sptr->isRunning()) 1088 | { 1089 | assert(sptr->pool_ == this); 1090 | assert(sptr->pid() == vectPid[i]); 1091 | ret = sptr->send(data) && ret; 1092 | } 1093 | } 1094 | return ret; 1095 | } 1096 | 1097 | bool OpenThreadPool::send(const std::vector& vectName, const std::shared_ptr& data) 1098 | { 1099 | if (!isInit_) 1100 | { 1101 | if (!checkInit()) return false; 1102 | } 1103 | std::shared_ptr sptr; 1104 | bool ret = true; 1105 | for (size_t i = 0; i < vectName.size(); i++) 1106 | { 1107 | sptr = safeMap_[vectName[i]]; 1108 | if (sptr && sptr->isRunning()) 1109 | { 1110 | assert(sptr->pool_ == this); 1111 | assert(sptr->name() == vectName[i]); 1112 | ret = sptr->send(data) && ret; 1113 | } 1114 | } 1115 | return ret; 1116 | } 1117 | 1118 | bool OpenThreadPool::stop(int pid) 1119 | { 1120 | if (pid < 0 || pid >= capacity()) 1121 | { 1122 | return false; 1123 | } 1124 | if (!isInit_) 1125 | { 1126 | if (!checkInit()) return false; 1127 | } 1128 | std::shared_ptr sptr = safeMap_[pid]; 1129 | if (sptr && sptr->isRunning()) 1130 | { 1131 | assert(sptr->pool_ == this); 1132 | assert(sptr->pid() == pid); 1133 | sptr->stop(); 1134 | } 1135 | return true; 1136 | } 1137 | 1138 | bool OpenThreadPool::stop(const std::string& name) 1139 | { 1140 | if (!isInit_) 1141 | { 1142 | if (!checkInit()) return false; 1143 | } 1144 | std::shared_ptr sptr = safeMap_[name]; 1145 | if (sptr && sptr->isRunning()) 1146 | { 1147 | assert(sptr->pool_ == this); 1148 | assert(sptr->name() == name); 1149 | sptr->stop(); 1150 | } 1151 | return true; 1152 | } 1153 | 1154 | void OpenThreadPool::threadJoin(const std::shared_ptr& sptr) 1155 | { 1156 | if (sptr && sptr->isRunning()) 1157 | { 1158 | pthread_join(sptr->threadId_, NULL); 1159 | } 1160 | } 1161 | 1162 | void OpenThreadPool::threadJoin(const std::vector& vectPid) 1163 | { 1164 | if (!isInit_) 1165 | { 1166 | if (!checkInit()) return; 1167 | } 1168 | std::shared_ptr sptr; 1169 | for (size_t i = 0; i < vectPid.size(); i++) 1170 | { 1171 | sptr = safeMap_[vectPid[i]]; 1172 | if (!sptr) continue; 1173 | if (sptr->isRunning()) 1174 | { 1175 | assert(sptr->pool_ == this); 1176 | assert(sptr->pid() == vectPid[i]); 1177 | pthread_join(sptr->threadId_, NULL); 1178 | } 1179 | } 1180 | } 1181 | 1182 | void OpenThreadPool::threadJoin(const std::vector& vectName) 1183 | { 1184 | if (!isInit_) 1185 | { 1186 | if (!checkInit()) return; 1187 | } 1188 | std::shared_ptr sptr; 1189 | for (size_t i = 0; i < vectName.size(); i++) 1190 | { 1191 | sptr = safeMap_[vectName[i]]; 1192 | if (!sptr) continue; 1193 | if (sptr->isRunning()) 1194 | { 1195 | assert(sptr->pool_ == this); 1196 | assert(sptr->name() == vectName[i]); 1197 | pthread_join(sptr->threadId_, NULL); 1198 | } 1199 | } 1200 | } 1201 | void OpenThreadPool::threadJoinAll() 1202 | { 1203 | size_t size = safeMap_.capacity(); 1204 | std::shared_ptr sptr; 1205 | for (size_t i = 0; i < size; i++) 1206 | { 1207 | sptr = safeMap_[i]; 1208 | if (!sptr) continue; 1209 | if (sptr->isRunning()) 1210 | { 1211 | assert(sptr->pool_ == this); 1212 | assert(sptr->pid() == i); 1213 | pthread_join(sptr->threadId_, NULL); 1214 | } 1215 | } 1216 | } 1217 | 1218 | 1219 | // OpenThreadRef 1220 | bool OpenThreadRef::start(void (*cb)(OpenThreadMsg&)) 1221 | { 1222 | OpenThread* ptr = thread_.get(); 1223 | return ptr ? ptr->start(cb) : false; 1224 | } 1225 | 1226 | bool OpenThreadRef::stop() 1227 | { 1228 | OpenThread* ptr = thread_.get(); 1229 | return ptr ? ptr->stop(), true : false; 1230 | } 1231 | 1232 | bool OpenThreadRef::send(const std::shared_ptr& data) 1233 | { 1234 | OpenThread* ptr = thread_.get(); 1235 | return ptr ? ptr->send(data) : false; 1236 | } 1237 | 1238 | bool OpenThreadRef::isIdle() 1239 | { 1240 | OpenThread* ptr = thread_.get(); 1241 | return ptr ? ptr->isIdle() : false; 1242 | } 1243 | 1244 | bool OpenThreadRef::isRunning() 1245 | { 1246 | OpenThread* ptr = thread_.get(); 1247 | return ptr ? ptr->isRunning() : false; 1248 | } 1249 | 1250 | bool OpenThreadRef::waitStop(int64_t milliSecond) 1251 | { 1252 | OpenThread* ptr = thread_.get(); 1253 | if (!ptr) return false; 1254 | if (!ptr->isRunning()) 1255 | { 1256 | return true; 1257 | } 1258 | if (ptr->isCurrent()) 1259 | { 1260 | return false; 1261 | } 1262 | while (ptr->isRunning()) 1263 | { 1264 | OpenThread::Sleep(milliSecond); 1265 | } 1266 | return true; 1267 | } 1268 | 1269 | int OpenThreadRef::pid() 1270 | { 1271 | OpenThread* ptr = thread_.get(); 1272 | return ptr ? ptr->pid() : -1; 1273 | } 1274 | 1275 | const std::string& OpenThreadRef::name() 1276 | { 1277 | static const std::string Empty; 1278 | OpenThread* ptr = thread_.get(); 1279 | return ptr ? ptr->name() : Empty; 1280 | } 1281 | 1282 | bool OpenThreadWorker::send(int pid, const std::shared_ptr& data) 1283 | { 1284 | if (!data) 1285 | { 1286 | assert(false); 1287 | return false; 1288 | } 1289 | if (pid < 0) 1290 | { 1291 | assert(false); 1292 | return false; 1293 | } 1294 | OpenThreadProto* proto = dynamic_cast((OpenThreadProto*)data.get()); 1295 | if (proto) 1296 | { 1297 | proto->srcPid_ = pid_; 1298 | proto->srcName_ = name_; 1299 | } 1300 | return OpenThread::Send(pid, data); 1301 | } 1302 | 1303 | bool OpenThreadWorker::send(std::vector& vectPid, const std::shared_ptr& data) 1304 | { 1305 | if (!data) 1306 | { 1307 | assert(false); 1308 | return false; 1309 | } 1310 | OpenThreadProto* proto = dynamic_cast((OpenThreadProto*)data.get()); 1311 | if (proto) 1312 | { 1313 | proto->srcPid_ = pid_; 1314 | proto->srcName_ = name_; 1315 | } 1316 | return OpenThread::Send(vectPid, data); 1317 | } 1318 | 1319 | bool OpenThreadWorker::sendLoop(const std::shared_ptr& data) 1320 | { 1321 | if (!data) 1322 | { 1323 | assert(false); 1324 | return false; 1325 | } 1326 | OpenThreadProto* proto = dynamic_cast((OpenThreadProto*)data.get()); 1327 | if (proto) 1328 | { 1329 | proto->srcPid_ = pid_; 1330 | proto->srcName_ = name_; 1331 | } 1332 | return OpenThread::Send(pid_, data); 1333 | } 1334 | 1335 | bool OpenThreadWorker::Send(int pid, const std::shared_ptr& data) 1336 | { 1337 | if (!data) 1338 | { 1339 | assert(false); 1340 | return false; 1341 | } 1342 | if (pid < 0) 1343 | { 1344 | assert(false); 1345 | return false; 1346 | } 1347 | OpenThreadProto* proto = dynamic_cast((OpenThreadProto*)data.get()); 1348 | if (proto) 1349 | { 1350 | proto->srcPid_ = -1; 1351 | } 1352 | return OpenThread::Send(pid, data); 1353 | } 1354 | 1355 | void OpenThreadWorker::onMsg(OpenThreadMsg& msg) 1356 | { 1357 | const OpenThreadProto* proto = msg.data(); 1358 | if (!proto) return; 1359 | std::map::iterator iter = mapHandle_.find(proto->protoType()); 1360 | if (iter != mapHandle_.end()) 1361 | { 1362 | (this->*iter->second)(*proto); 1363 | return; 1364 | } 1365 | assert(false); 1366 | } 1367 | 1368 | 1369 | //OpenSync 1370 | OpenSync::OpenSyncRef::OpenSyncRef() 1371 | { 1372 | isSleep_ = false; 1373 | pthread_mutex_init(&mutex_, NULL); 1374 | pthread_cond_init(&cond_, NULL); 1375 | } 1376 | 1377 | OpenSync::OpenSyncRef::OpenSyncRef(const OpenSyncRef& that) 1378 | { 1379 | assert(false); 1380 | isSleep_ = that.isSleep_; 1381 | pthread_mutex_init(&mutex_, NULL); 1382 | pthread_cond_init(&cond_, NULL); 1383 | } 1384 | 1385 | OpenSync::OpenSyncRef::~OpenSyncRef() 1386 | { 1387 | pthread_mutex_destroy(&mutex_); 1388 | pthread_cond_destroy(&cond_); 1389 | } 1390 | 1391 | bool OpenSync::OpenSyncRef::await() 1392 | { 1393 | if (!isSleep_) 1394 | { 1395 | isSleep_ = true; 1396 | pthread_mutex_lock(&mutex_); 1397 | pthread_cond_wait(&cond_, &mutex_); 1398 | pthread_mutex_unlock(&mutex_); 1399 | return true; 1400 | } 1401 | return false; 1402 | } 1403 | 1404 | bool OpenSync::OpenSyncRef::wakeup() 1405 | { 1406 | if (isSleep_) 1407 | { 1408 | isSleep_ = 0; 1409 | pthread_cond_signal(&cond_); 1410 | return true; 1411 | } 1412 | return false; 1413 | } 1414 | 1415 | void OpenThread::Sleep(int64_t milliSecond) 1416 | { 1417 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 1418 | ::Sleep((DWORD)milliSecond); 1419 | #else 1420 | ::usleep(milliSecond * 1000); 1421 | #endif 1422 | } 1423 | 1424 | int64_t OpenThread::MilliUnixtime() 1425 | { 1426 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 1427 | int64_t ft = 0; 1428 | ::GetSystemTimeAsFileTime((LPFILETIME)&ft); 1429 | int64_t milliSecond = (ft / 10000000 - 11644473600LL) * 1000 + (ft / 10) % 1000000; 1430 | return milliSecond; 1431 | #else 1432 | struct timeval tv; 1433 | ::gettimeofday(&tv, NULL); 1434 | int64_t milliSecond = tv.tv_sec * 1000 + tv.tv_usec; 1435 | return milliSecond; 1436 | #endif 1437 | } 1438 | 1439 | int64_t OpenThread::ThreadTime() 1440 | { 1441 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 1442 | int64_t ft = 0; 1443 | ::GetSystemTimeAsFileTime((LPFILETIME)&ft); 1444 | int64_t tt = (ft / 10000000 - 11644473600LL) * 1000000 + (ft / 10) % 1000000000; 1445 | #else 1446 | #define NANOSEC 1000000000 1447 | #define MICROSEC 1000000 1448 | #if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER) 1449 | struct timespec ti; 1450 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ti); 1451 | int64_t tt = ti.tv_sec * MICROSEC + ti.tv_nsec / (NANOSEC / MICROSEC); 1452 | #else 1453 | struct task_thread_times_info aTaskInfo; 1454 | mach_msg_type_number_t aTaskInfoCount = TASK_THREAD_TIMES_INFO_COUNT; 1455 | if (KERN_SUCCESS != task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&aTaskInfo, &aTaskInfoCount)) { 1456 | return 0; 1457 | } 1458 | int64_t tt = aTaskInfo.user_time.seconds * MICROSEC + aTaskInfo.user_time.microseconds; 1459 | #endif 1460 | #endif 1461 | return tt; 1462 | } 1463 | 1464 | }; 1465 | 1466 | 1467 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 1468 | #ifdef __cplusplus 1469 | extern "C" { 1470 | #endif 1471 | 1472 | int pthread_mutex_lock(pthread_mutex_t* _mutex) 1473 | { 1474 | int rc = WaitForSingleObject(*_mutex, INFINITE); 1475 | return rc == WAIT_OBJECT_0 ? 0 : rc; 1476 | } 1477 | 1478 | int pthread_mutex_unlock(pthread_mutex_t* _mutex) 1479 | { 1480 | int rc = ReleaseMutex(*_mutex); 1481 | return rc != 0 ? 0 : GetLastError(); 1482 | } 1483 | 1484 | int pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr) 1485 | { 1486 | *_mutex = CreateMutex(NULL, FALSE, NULL); 1487 | return *_mutex == NULL ? GetLastError() : 0; 1488 | } 1489 | 1490 | int pthread_mutex_destroy(pthread_mutex_t* _mutex) 1491 | { 1492 | int rc = CloseHandle(*_mutex); 1493 | return rc != 0 ? 0 : GetLastError(); 1494 | } 1495 | 1496 | typedef unsigned(__stdcall* routinefunc)(void*); 1497 | int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine1) (void*), void* arg) 1498 | { 1499 | int _intThreadId = 0; 1500 | routinefunc start_routine = (routinefunc)start_routine1; 1501 | (*thread).thread_handle = (HANDLE)_beginthreadex(NULL, 0, start_routine, arg, 0, (unsigned int*)&_intThreadId); 1502 | (*thread).thread_id = _intThreadId; 1503 | return (*thread).thread_handle == 0 ? errno : 0; 1504 | } 1505 | 1506 | int pthread_equal(pthread_t t1, pthread_t t2) 1507 | { 1508 | return ((t1.thread_id == t2.thread_id) ? 1 : 0); 1509 | } 1510 | 1511 | pthread_t pthread_self() 1512 | { 1513 | pthread_t thread_self = {0}; 1514 | thread_self.thread_id = GetCurrentThreadId(); 1515 | thread_self.thread_handle = GetCurrentThread(); 1516 | return thread_self; 1517 | } 1518 | 1519 | int pthread_join(pthread_t _thread, void** ignore) 1520 | { 1521 | int rc = WaitForSingleObject(_thread.thread_handle, INFINITE); 1522 | return rc == WAIT_OBJECT_0 ? 0 : rc; 1523 | } 1524 | 1525 | int pthread_detach(pthread_t _thread) 1526 | { 1527 | int rc = CloseHandle(_thread.thread_handle); 1528 | return rc != 0 ? 0 : GetLastError(); 1529 | } 1530 | 1531 | void pthread_mutexattr_init(pthread_mutexattr_t* ignore) {} 1532 | void pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore) {} 1533 | void pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr) {} 1534 | 1535 | int pthread_cond_init(pthread_cond_t* cv, const pthread_condattr_t* ignore) 1536 | { 1537 | assert(sizeof(CRITICAL_SECTION) <= sizeof(cv->waiters_count_lock_)); 1538 | cv->waiters_count_ = 0; 1539 | cv->was_broadcast_ = 0; 1540 | cv->sema_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); 1541 | if (cv->sema_ == NULL) return GetLastError(); 1542 | CRITICAL_SECTION* lock = (CRITICAL_SECTION*)cv->waiters_count_lock_; 1543 | InitializeCriticalSection(lock); 1544 | cv->waiters_done_ = CreateEvent(NULL, FALSE, FALSE, NULL); 1545 | return (cv->waiters_done_ == NULL) ? GetLastError() : 0; 1546 | } 1547 | 1548 | int pthread_cond_destroy(pthread_cond_t* cond) 1549 | { 1550 | CloseHandle(cond->sema_); 1551 | CRITICAL_SECTION* lock = (CRITICAL_SECTION*)cond->waiters_count_lock_; 1552 | DeleteCriticalSection(lock); 1553 | return (CloseHandle(cond->waiters_done_) == 0) ? GetLastError() : 0; 1554 | } 1555 | 1556 | int pthread_cond_signal(pthread_cond_t* cv) 1557 | { 1558 | CRITICAL_SECTION* lock = (CRITICAL_SECTION*)cv->waiters_count_lock_; 1559 | EnterCriticalSection(lock); 1560 | int have_waiters = cv->waiters_count_ > 0; 1561 | LeaveCriticalSection(lock); 1562 | if (!have_waiters) return 0; 1563 | return ReleaseSemaphore(cv->sema_, 1, 0) == 0 ? GetLastError() : 0; 1564 | } 1565 | 1566 | int pthread_cond_broadcast(pthread_cond_t* cv) 1567 | { 1568 | int have_waiters = 0; 1569 | CRITICAL_SECTION* lock = (CRITICAL_SECTION*)cv->waiters_count_lock_; 1570 | EnterCriticalSection(lock); 1571 | if (cv->waiters_count_ > 0) 1572 | { 1573 | cv->was_broadcast_ = 1; 1574 | have_waiters = 1; 1575 | } 1576 | if (have_waiters) 1577 | { 1578 | ReleaseSemaphore(cv->sema_, cv->waiters_count_, 0); 1579 | LeaveCriticalSection(lock); 1580 | WaitForSingleObject(cv->waiters_done_, INFINITE); 1581 | cv->was_broadcast_ = 0; 1582 | } 1583 | else 1584 | LeaveCriticalSection(lock); 1585 | return 0; 1586 | } 1587 | 1588 | int pthread_cond_wait(pthread_cond_t* cv, pthread_mutex_t* external_mutex) 1589 | { 1590 | int last_waiter = 0; 1591 | CRITICAL_SECTION* lock = (CRITICAL_SECTION*)cv->waiters_count_lock_; 1592 | EnterCriticalSection(lock); 1593 | cv->waiters_count_++; 1594 | LeaveCriticalSection(lock); 1595 | SignalObjectAndWait(*external_mutex, cv->sema_, INFINITE, FALSE); 1596 | EnterCriticalSection(lock); 1597 | cv->waiters_count_--; 1598 | 1599 | last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0; 1600 | LeaveCriticalSection(lock); 1601 | if (last_waiter) 1602 | SignalObjectAndWait(cv->waiters_done_, *external_mutex, INFINITE, FALSE); 1603 | else 1604 | WaitForSingleObject(*external_mutex, INFINITE); 1605 | return 0; 1606 | } 1607 | 1608 | int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) 1609 | { 1610 | int result = 0; 1611 | pthread_key_t* newkey = (pthread_key_t*)calloc(1, sizeof(pthread_key_t)); 1612 | if (newkey == NULL) 1613 | { 1614 | result = ENOMEM; 1615 | } 1616 | else if ((newkey->key = TlsAlloc()) == TLS_OUT_OF_INDEXES) 1617 | { 1618 | result = EAGAIN; 1619 | free(newkey); 1620 | newkey = NULL; 1621 | } 1622 | else if (destructor != NULL) 1623 | { 1624 | newkey->destructor = destructor; 1625 | } 1626 | key = newkey; 1627 | return result; 1628 | } 1629 | 1630 | int pthread_key_delete(pthread_key_t key) 1631 | { 1632 | LPVOID lpvData = TlsGetValue(key.key); 1633 | int rc = TlsFree(key.key); 1634 | rc = (rc != 0) ? 0 : GetLastError(); 1635 | if (key.destructor != NULL && lpvData != 0) 1636 | { 1637 | key.destructor(lpvData); 1638 | } 1639 | free(&key); 1640 | return (rc); 1641 | } 1642 | 1643 | void* pthread_getspecific(pthread_key_t key) 1644 | { 1645 | LPVOID lpvData = TlsGetValue(key.key); 1646 | if (lpvData == 0 && GetLastError() != ERROR_SUCCESS) 1647 | return NULL; 1648 | else 1649 | return lpvData; 1650 | } 1651 | 1652 | int pthread_setspecific(pthread_key_t key, const void* value) 1653 | { 1654 | int rc = TlsSetValue(key.key, (LPVOID)value); 1655 | return rc != 0 ? 0 : GetLastError(); 1656 | } 1657 | 1658 | int pthread_setname_np(pthread_t thread, const char* name) 1659 | { 1660 | return 0; 1661 | } 1662 | int pthread_getname_np(pthread_t thread, char* name, size_t len) 1663 | { 1664 | return 0; 1665 | } 1666 | #ifdef __cplusplus 1667 | } 1668 | #endif 1669 | 1670 | #endif 1671 | 1672 | -------------------------------------------------------------------------------- /test/open/openthread.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2023-, openlinyou, 3 | * 4 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 5 | * copies of the Software, and permit persons to whom the Software is 6 | * furnished to do so, under the terms of the COPYING file. 7 | ***************************************************************************/ 8 | 9 | #ifndef HEADER_OPEN_THREAD_H 10 | #define HEADER_OPEN_THREAD_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | typedef void* HANDLE; 28 | typedef unsigned long DWORD; 29 | typedef HANDLE pthread_mutex_t; 30 | struct pthread_t_ 31 | { 32 | HANDLE thread_handle; 33 | DWORD thread_id; 34 | }; 35 | 36 | typedef struct pthread_t_ pthread_t; 37 | typedef int pthread_mutexattr_t; 38 | typedef int pthread_condattr_t; 39 | typedef int pthread_attr_t; 40 | #define PTHREAD_MUTEX_RECURSIVE 0 41 | 42 | typedef struct 43 | { 44 | int waiters_count_; 45 | HANDLE sema_; 46 | HANDLE waiters_done_; 47 | size_t was_broadcast_; 48 | char waiters_count_lock_[256]; 49 | } pthread_cond_t; 50 | 51 | struct pthread_key_t_ 52 | { 53 | DWORD key; 54 | void (*destructor) (void *); 55 | }; 56 | typedef struct pthread_key_t_ pthread_key_t; 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #else 63 | #include 64 | #endif 65 | 66 | namespace open 67 | { 68 | 69 | class OpenThreadRef; 70 | class OpenThreadPool; 71 | 72 | ////////////OpenThread////////////////////// 73 | class OpenThread 74 | { 75 | public: 76 | enum State 77 | { 78 | START, 79 | RUN, 80 | STOP 81 | }; 82 | class Msg 83 | { 84 | OpenThread* thread_; 85 | std::shared_ptr data_; 86 | Msg():thread_(0), data_(0), state_(START) {}; 87 | Msg(const Msg&) :thread_(0), data_(0), state_(START){} 88 | void operator=(const Msg&) {} 89 | public: 90 | State state_; 91 | template 92 | inline const T* data() const { return dynamic_cast((const T*)data_.get()); } 93 | template 94 | inline T* edit() const { return dynamic_cast((T*)data_.get()); } 95 | OpenThread& thread() const; 96 | const int pid() const; 97 | const std::string& name() const; 98 | template 99 | T* custom() const { return thread_ ? dynamic_cast((T*)thread_->custom_) : 0; } 100 | friend class OpenThread; 101 | }; 102 | friend class Msg; 103 | 104 | ~OpenThread(); 105 | bool start(void (*cb)(const Msg&)); 106 | bool stop(); 107 | bool send(const std::shared_ptr& data); 108 | bool isCurrent(); 109 | void waitIdle(); 110 | 111 | inline bool isIdle() { return isIdle_; } 112 | inline bool isRunning() { return state_ == RUN; } 113 | inline State state() { return state_; } 114 | 115 | inline int pid() { return pid_; } 116 | inline const std::string& name() { return name_; } 117 | inline size_t& totalCount() { return totalCount_; } 118 | inline size_t& leftCount() { return leftCount_; } 119 | inline int64_t& cpuCost() { return cpuCost_; } 120 | inline int64_t& cpuStart() { return cpuStart_; } 121 | 122 | template 123 | static std::shared_ptr MakeShared() 124 | { 125 | return std::shared_ptr(new T); 126 | } 127 | static bool Init(size_t capacity = 256, bool profile = true); 128 | static OpenThreadRef Create(const std::string& name); 129 | static OpenThreadRef Create(const std::string& name, void (*cb)(const Msg&)); 130 | static OpenThreadRef Thread(int pid); 131 | static OpenThreadRef Thread(const std::string& name); 132 | static const std::string& ThreadName(int pid); 133 | static int ThreadId(const std::string& name); 134 | static size_t GetThreadCapacity(); 135 | static size_t GetThreadSize(); 136 | 137 | static bool Send(int pid, const std::shared_ptr& data); 138 | static bool Send(const std::string& name, const std::shared_ptr& data); 139 | static bool Send(const std::vector& vectPid, const std::shared_ptr& data); 140 | static bool Send(const std::vector& vectName, const std::shared_ptr& data); 141 | static bool Stop(int pid); 142 | static bool Stop(const std::string& name); 143 | static void StopAll(); 144 | static void ThreadJoin(OpenThreadRef& ref); 145 | static void ThreadJoin(const std::vector& vectPid); 146 | static void ThreadJoin(const std::vector& vectName); 147 | static void ThreadJoinAll(); 148 | static std::shared_ptr GetThread(OpenThreadRef& ref); 149 | 150 | static void Sleep(int64_t milliSecond); 151 | static int64_t ThreadTime(); 152 | static int64_t MilliUnixtime(); 153 | 154 | //Use with care 155 | bool hasMsg(); 156 | inline void setCustom(void* custom) { custom_ = custom; } 157 | private: 158 | void run(); 159 | static void Run(void* arg); 160 | OpenThread(const std::string& name); 161 | OpenThread(const OpenThread&); 162 | void operator=(const OpenThread&) {} 163 | 164 | int pid_; 165 | volatile State state_; 166 | volatile bool isIdle_; 167 | void* custom_; 168 | 169 | const std::string name_; 170 | pthread_t threadId_; 171 | pthread_cond_t cond_; 172 | pthread_mutex_t mutex_; 173 | void (*cb_)(const Msg&); 174 | OpenThreadPool* pool_; 175 | 176 | bool profile_; 177 | size_t totalCount_; 178 | size_t leftCount_; 179 | int64_t cpuCost_; 180 | int64_t cpuStart_; 181 | private: 182 | struct Node 183 | { 184 | unsigned int id_; 185 | Msg msg_; 186 | Node* next_; 187 | Node():id_(0), next_(0){} 188 | }; 189 | class SpinLock 190 | { 191 | private: 192 | SpinLock(const SpinLock&) {}; 193 | void operator=(const SpinLock) {}; 194 | public: 195 | SpinLock() {}; 196 | void lock() { while (flag_.test_and_set(std::memory_order_acquire)); } 197 | void unlock() { flag_.clear(std::memory_order_release); } 198 | private: 199 | std::atomic_flag flag_; 200 | }; 201 | class SafeQueue 202 | { 203 | Node head_; 204 | Node* tail_; 205 | SpinLock spinLock_; 206 | unsigned int writeId_; 207 | unsigned int readId_; 208 | std::vector vectCache_; 209 | public: 210 | SafeQueue(); 211 | ~SafeQueue(); 212 | void clear(); 213 | void popAll(); 214 | void popAll(std::queue& queueCache); 215 | void push(Node* node); 216 | bool empty() { return !head_.next_; } 217 | }; 218 | unsigned int readId_; 219 | SafeQueue queue_; 220 | 221 | Node* popNode(); 222 | std::queue queueCache_; 223 | private: 224 | static OpenThreadPool DefaultPool_; 225 | friend class OpenThreadPool; 226 | public: 227 | static inline bool Send(const std::initializer_list& list, const std::shared_ptr& data) 228 | { std::vector v = list;return Send(v, data); } 229 | static inline bool Send(const std::initializer_list& list, const std::shared_ptr& data) 230 | { std::vector v = list;return Send(v, data); } 231 | static inline void ThreadJoin(const std::initializer_list& list) 232 | { std::vector v = list;return ThreadJoin(v); } 233 | static inline void ThreadJoin(const std::initializer_list& list) 234 | { std::vector v = list; return ThreadJoin(v); } 235 | }; 236 | typedef const OpenThread::Msg OpenThreadMsg; 237 | 238 | ////////////OpenThreadPool////////////////////// 239 | class OpenThreadPool 240 | { 241 | class SafeMap 242 | { 243 | size_t capacity_; 244 | std::vector> vectValues_; 245 | std::vector> vectKeys_; 246 | SafeMap(const SafeMap& that); 247 | void operator=(const SafeMap& that) {} 248 | public: 249 | SafeMap(); 250 | SafeMap(size_t capacity); 251 | ~SafeMap(); 252 | bool isFull(); 253 | void clear(); 254 | size_t size(); 255 | size_t capacity() { return vectKeys_.size(); } 256 | void setCapacity(size_t capacity); 257 | std::shared_ptr operator[](size_t pid); 258 | std::shared_ptr operator[](const std::string& name); 259 | int set(std::shared_ptr& value); 260 | }; 261 | public: 262 | OpenThreadPool(); 263 | ~OpenThreadPool(); 264 | 265 | void lock(); 266 | void unlock(); 267 | 268 | bool init(size_t capacity, bool profile = true); 269 | bool checkInit(); 270 | void stopAll(); 271 | size_t size(); 272 | size_t capacity(); 273 | 274 | std::shared_ptr create(const std::string& name); 275 | std::shared_ptr create(const std::string& name, void (*cb)(const OpenThread::Msg&)); 276 | std::shared_ptr thread(int pid); 277 | std::shared_ptr thread(const std::string& name); 278 | const std::string& threadName(int pid); 279 | int threadId(const std::string& name); 280 | 281 | bool send(int pid, const std::shared_ptr& data); 282 | bool send(const std::string& name, const std::shared_ptr& data); 283 | bool send(const std::vector& vectPid, const std::shared_ptr& data); 284 | bool send(const std::vector& vectName, const std::shared_ptr& data); 285 | bool stop(int pid); 286 | bool stop(const std::string& name); 287 | void threadJoin(const std::shared_ptr& ref); 288 | void threadJoin(const std::vector& vectPid); 289 | void threadJoin(const std::vector& vectName); 290 | void threadJoinAll(); 291 | 292 | private: 293 | bool profile_; 294 | SafeMap safeMap_; 295 | volatile bool isInit_; 296 | volatile bool isClearIng_; 297 | pthread_mutex_t mutex_; 298 | pthread_mutex_t mutex_close_; 299 | }; 300 | 301 | ////////////OpenThreadRef////////////////////// 302 | class OpenThreadRef 303 | { 304 | std::shared_ptr thread_; 305 | public: 306 | OpenThreadRef() {} 307 | OpenThreadRef(std::shared_ptr& ref) :thread_(ref) {} 308 | OpenThreadRef(const OpenThreadRef& that) { thread_ = that.thread_; } 309 | void operator=(const OpenThreadRef& that) { thread_ = that.thread_; } 310 | bool operator==(const OpenThreadRef& that) { return thread_ == that.thread_; } 311 | bool operator==(const std::shared_ptr& that) { return thread_ == that; } 312 | inline void waitIdle() { if (thread_) thread_->waitIdle(); } 313 | bool start(void (*cb)(OpenThreadMsg&)); 314 | bool stop(); 315 | bool send(const std::shared_ptr& data); 316 | bool waitStop(int64_t milliSecond = 1); 317 | 318 | bool isIdle(); 319 | bool isRunning(); 320 | 321 | int pid(); 322 | const std::string& name(); 323 | operator bool() const { return !!thread_; } 324 | friend class OpenThread; 325 | }; 326 | 327 | ////////////OpenThreader////////////////////// 328 | class OpenThreader 329 | { 330 | public: 331 | OpenThreader(const std::string& name) :name_(name), pid_(-1) {} 332 | virtual ~OpenThreader(){ stop(); } 333 | virtual bool start(); 334 | virtual void stop(); 335 | virtual void onStart() { } 336 | virtual void onMsg(OpenThreadMsg& msg) { } 337 | virtual void onStop() { } 338 | const inline int pid() { return pid_; } 339 | const std::string& name() { return name_; } 340 | static void Thread(OpenThreadMsg& msg); 341 | static inline int ThreadId(const std::string& name) { return OpenThread::ThreadId(name); } 342 | static inline const std::string& ThreadName(int pid) { return OpenThread::ThreadName(pid); } 343 | protected: 344 | int pid_; 345 | const std::string name_; 346 | std::shared_ptr thread_; 347 | }; 348 | 349 | ////////////OpenThreadProto////////////////////// 350 | struct OpenThreadProto 351 | { 352 | int srcPid_; 353 | std::string srcName_; 354 | 355 | OpenThreadProto() :srcPid_(-1) {} 356 | int srcPid() { return srcPid_; } 357 | const std::string& srcName() { return srcName_; } 358 | int srcPid() const { return srcPid_; } 359 | const std::string& srcName() const { return srcName_; } 360 | 361 | static inline int ProtoType() { return -1; } 362 | //implement 363 | virtual inline int protoType() const { assert(false); return OpenThreadProto::ProtoType(); } 364 | }; 365 | 366 | ////////////OpenThreadWorker////////////////////// 367 | class OpenThreadWorker; 368 | typedef void(OpenThreadWorker::*OpenThreadHandle)(const OpenThreadProto&); 369 | class OpenThreadWorker : public OpenThreader 370 | { 371 | public: 372 | OpenThreadWorker(const std::string& name) 373 | :OpenThreader(name) {} 374 | virtual ~OpenThreadWorker() {} 375 | 376 | virtual bool send(int pid, const std::shared_ptr& data); 377 | virtual bool send(std::vector& vectPid, const std::shared_ptr& data); 378 | virtual bool sendLoop(const std::shared_ptr& data); 379 | static bool Send(int pid, const std::shared_ptr& data); 380 | void registers(int protoId, const OpenThreadHandle handle) 381 | { 382 | std::map::iterator iter = mapHandle_.find(protoId); 383 | if (iter != mapHandle_.end()) 384 | { 385 | assert(false); 386 | return; 387 | } 388 | mapHandle_[protoId] = handle; 389 | } 390 | protected: 391 | bool canLoop() 392 | { 393 | OpenThread* p = thread_.get(); 394 | return p ? (p->isRunning() && !p->hasMsg()) : false; 395 | } 396 | virtual void onMsg(OpenThreadMsg& msg); 397 | 398 | std::map mapHandle_; 399 | }; 400 | 401 | 402 | ////////////OpenSync////////////////////// 403 | class OpenSync 404 | { 405 | class OpenSyncRef 406 | { 407 | volatile bool isSleep_; 408 | pthread_cond_t cond_; 409 | pthread_mutex_t mutex_; 410 | OpenSyncRef(); 411 | OpenSyncRef(const OpenSyncRef&); 412 | void operator=(const OpenSyncRef&) {} 413 | public: 414 | ~OpenSyncRef(); 415 | bool await(); 416 | bool wakeup(); 417 | friend class OpenSync; 418 | }; 419 | std::shared_ptr sync_; 420 | public: 421 | OpenSync() { sync_ = std::shared_ptr(new OpenSyncRef); } 422 | OpenSync(const OpenSync& that) { sync_ = that.sync_; } 423 | void operator=(const OpenSync& that) { sync_ = that.sync_; } 424 | 425 | inline void await() { if (sync_) sync_->await(); } 426 | inline bool wakeup() { if (sync_) return sync_->wakeup(); return false; } 427 | operator bool() const { return !!sync_; } 428 | }; 429 | 430 | 431 | }; 432 | 433 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 434 | #ifdef __cplusplus 435 | extern "C" { 436 | #endif 437 | // mutex 438 | int pthread_mutex_lock(pthread_mutex_t* _mutex); 439 | int pthread_mutex_unlock(pthread_mutex_t* _mutex); 440 | int pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr); 441 | int pthread_mutex_destroy(pthread_mutex_t* _mutex); 442 | 443 | // pthread 444 | int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg); 445 | int pthread_equal(pthread_t t1, pthread_t t2); 446 | pthread_t pthread_self(); 447 | int pthread_join(pthread_t _thread, void** ignore); 448 | int pthread_detach(pthread_t _thread); 449 | 450 | void pthread_mutexattr_init(pthread_mutexattr_t* ignore); 451 | void pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore); 452 | void pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr); 453 | 454 | int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)); 455 | int pthread_key_delete(pthread_key_t key); 456 | void* pthread_getspecific(pthread_key_t key); 457 | int pthread_setspecific(pthread_key_t key, const void* value); 458 | 459 | int pthread_setname_np(pthread_t thread, const char* name); 460 | int pthread_getname_np(pthread_t thread, char* name, size_t len); 461 | 462 | // cond 463 | int pthread_cond_init(pthread_cond_t* cv, const pthread_condattr_t* ignore); 464 | int pthread_cond_destroy(pthread_cond_t* cond); 465 | int pthread_cond_signal(pthread_cond_t* cv); 466 | int pthread_cond_broadcast(pthread_cond_t* cv); 467 | int pthread_cond_wait(pthread_cond_t* cv, pthread_mutex_t* external_mutex); 468 | #ifdef __cplusplus 469 | } 470 | #endif 471 | 472 | #endif 473 | 474 | template 475 | class OpenSyncReturn 476 | { 477 | class OpenSyncRef 478 | { 479 | volatile bool isSleep_; 480 | pthread_cond_t cond_; 481 | pthread_mutex_t mutex_; 482 | std::shared_ptr srcData_; 483 | std::shared_ptr destData_; 484 | OpenSyncRef() 485 | { 486 | isSleep_ = false; 487 | pthread_mutex_init(&mutex_, NULL); 488 | pthread_cond_init(&cond_, NULL); 489 | } 490 | OpenSyncRef(const OpenSyncRef& that) 491 | { 492 | assert(false); 493 | isSleep_ = that.isSleep_; 494 | pthread_mutex_init(&mutex_, NULL); 495 | pthread_cond_init(&cond_, NULL); 496 | } 497 | void operator=(const OpenSyncRef&) {} 498 | public: 499 | ~OpenSyncRef() 500 | { 501 | pthread_mutex_destroy(&mutex_); 502 | pthread_cond_destroy(&cond_); 503 | } 504 | bool await() 505 | { 506 | if (!isSleep_) 507 | { 508 | isSleep_ = true; 509 | pthread_mutex_lock(&mutex_); 510 | pthread_cond_wait(&cond_, &mutex_); 511 | pthread_mutex_unlock(&mutex_); 512 | return true; 513 | } 514 | return false; 515 | } 516 | inline const std::shared_ptr& awaitReturn() 517 | { 518 | await(); 519 | return destData_; 520 | } 521 | bool wakeup() 522 | { 523 | if (isSleep_) 524 | { 525 | isSleep_ = 0; 526 | pthread_cond_signal(&cond_); 527 | return true; 528 | } 529 | return false; 530 | } 531 | bool wakeup(const std::shared_ptr& data) 532 | { 533 | if (isSleep_) 534 | { 535 | isSleep_ = 0; 536 | destData_ = data; 537 | pthread_cond_signal(&cond_); 538 | return true; 539 | } 540 | return false; 541 | } 542 | friend class OpenSyncReturn; 543 | }; 544 | std::shared_ptr sync_; 545 | public: 546 | OpenSyncReturn() { sync_ = std::shared_ptr(new OpenSyncRef); } 547 | OpenSyncReturn(const OpenSyncReturn& that) { sync_ = that.sync_; } 548 | void operator=(const OpenSyncReturn& that) { sync_ = that.sync_; } 549 | 550 | void operator=(const std::shared_ptr& data) { if (sync_) sync_->srcData_ = data; } 551 | void put(const std::shared_ptr& data) { if (sync_) sync_->srcData_ = data; } 552 | inline const std::shared_ptr get() const { if (sync_) return sync_->srcData_; return std::shared_ptr(); } 553 | 554 | inline void await() { if (sync_) sync_->await(); } 555 | inline const std::shared_ptr awaitReturn() { if (sync_) return sync_->awaitReturn(); return std::shared_ptr(); } 556 | 557 | inline bool wakeup() { if (sync_) return sync_->wakeup(); return false; } 558 | inline bool wakeup(const std::shared_ptr& data) { if (sync_) return sync_->wakeup(data); return false; } 559 | 560 | operator bool() const { return !!sync_; } 561 | }; 562 | 563 | #endif /* HEADER_OPEN_THREAD_H */ 564 | -------------------------------------------------------------------------------- /test/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "opensocket.h" 7 | #include "open/openthread.h" 8 | using namespace open; 9 | 10 | const std::string TestServerIp_ = "0.0.0.0"; 11 | const std::string TestClientIp_ = "127.0.0.1"; 12 | const int TestServerPort_ = 8888; 13 | 14 | //proto 15 | struct SocketProto : public OpenThreadProto 16 | { 17 | std::shared_ptr data_; 18 | static inline int ProtoType() { return 1; } 19 | virtual inline int protoType() const { return SocketProto::ProtoType(); } 20 | }; 21 | 22 | 23 | class ProtoBuffer : public OpenThreadProto 24 | { 25 | std::shared_ptr data_; 26 | public: 27 | int msgId_; 28 | ProtoBuffer() 29 | : OpenThreadProto() 30 | , msgId_(0) 31 | , data_(0) {} 32 | virtual ~ProtoBuffer() {} 33 | template 34 | inline T& data() 35 | { 36 | T* t = 0; 37 | if (data_) 38 | { 39 | t = dynamic_cast((T*)data_.get()); 40 | if (data_.get() == t) return *t; 41 | data_.reset(); 42 | } 43 | t = new T; 44 | data_ = std::shared_ptr(t); 45 | return *t; 46 | } 47 | template 48 | inline T& data() const 49 | { 50 | if (data_) 51 | { 52 | T* t = dynamic_cast((T*)data_.get()); 53 | if (data_.get() == t) return *t; 54 | } 55 | assert(false); 56 | static T t; 57 | return t; 58 | } 59 | static inline int ProtoType() { return (int)(uintptr_t) & (ProtoType); } 60 | virtual inline int protoType() const { return ProtoBuffer::ProtoType(); } 61 | }; 62 | 63 | 64 | ////////////App////////////////////// 65 | class App 66 | { 67 | static void SocketFunc(const OpenSocketMsg* msg) 68 | { 69 | if (!msg) return; 70 | if (msg->uid_ >= 0) 71 | { 72 | auto proto = std::shared_ptr(new SocketProto); 73 | proto->srcPid_ = -1; 74 | proto->srcName_ = "OpenSocket"; 75 | proto->data_ = std::shared_ptr((OpenSocketMsg*)msg); 76 | if (!OpenThread::Send((int)msg->uid_, proto)) 77 | printf("SocketFunc dispatch faild pid = %d\n", (int)msg->uid_); 78 | return; 79 | } 80 | delete msg; 81 | } 82 | public: 83 | static App Instance_; 84 | App() { OpenSocket::Start(App::SocketFunc); } 85 | }; 86 | App App::Instance_; 87 | 88 | 89 | enum EMsgId 90 | { 91 | new_accept, 92 | new_client, 93 | test_client 94 | }; 95 | 96 | 97 | ////////////Listener////////////////////// 98 | struct DataNewClient 99 | { 100 | int accept_fd_; 101 | std::string addr_; 102 | DataNewClient() :accept_fd_(-1) {} 103 | }; 104 | class Listener : public OpenThreadWorker 105 | { 106 | std::set setSlaveId_; 107 | std::vector vectSlaveId_; 108 | int listen_fd_; 109 | unsigned int balance_; 110 | bool isOpening_; 111 | public: 112 | Listener(const std::string& name) 113 | :OpenThreadWorker(name), 114 | listen_fd_(-1) 115 | { 116 | isOpening_ = false; 117 | balance_ = 0; 118 | 119 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Listener::onSocketProto); 120 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Listener::onProtoBuffer); 121 | } 122 | virtual ~Listener() {} 123 | virtual void onStart() 124 | { 125 | listen_fd_ = OpenSocket::Instance().listen((uintptr_t)pid(), TestServerIp_, TestServerPort_, 64); 126 | if (listen_fd_ < 0) 127 | { 128 | printf("Listener::onStart faild listen_fd_ = %d\n", listen_fd_); 129 | assert(false); 130 | } 131 | OpenSocket::Instance().start((uintptr_t)pid(), listen_fd_); 132 | } 133 | private: 134 | void onProtoBuffer(const ProtoBuffer& proto) 135 | { 136 | if (proto.msgId_ == new_accept) 137 | { 138 | auto msg = proto.data(); 139 | assert(msg == "listen success!"); 140 | if (proto.srcPid() >= 0) 141 | { 142 | if (setSlaveId_.find(proto.srcPid()) == setSlaveId_.end()) 143 | { 144 | setSlaveId_.insert(proto.srcPid()); 145 | vectSlaveId_.push_back(proto.srcPid()); 146 | printf("Hello OpenSocket, srcPid = %d\n", proto.srcPid()); 147 | } 148 | } 149 | } 150 | } 151 | void notify(int accept_fd, const std::string& addr) 152 | { 153 | if (!vectSlaveId_.empty()) 154 | { 155 | auto proto = std::shared_ptr(new ProtoBuffer); 156 | proto->msgId_ = new_client; 157 | auto& msg = proto->data(); 158 | msg.accept_fd_ = accept_fd; 159 | msg.addr_ = addr; 160 | if (balance_ >= vectSlaveId_.size()) 161 | { 162 | balance_ = 0; 163 | } 164 | int slaveId = vectSlaveId_[balance_++]; 165 | bool ret = send(slaveId, proto); 166 | if (ret) return; 167 | } 168 | OpenSocket::Instance().close(pid_, accept_fd); 169 | } 170 | virtual void onSocketProto(const SocketProto& proto) 171 | { 172 | const auto msg = proto.data_; 173 | switch (msg->type_) 174 | { 175 | case OpenSocket::ESocketAccept: 176 | notify(msg->ud_, msg->data()); 177 | printf("Listener::onStart [%s]ESocketAccept:acceptFd = %d\n", ThreadName((int)msg->uid_).c_str(), msg->ud_); 178 | break; 179 | case OpenSocket::ESocketClose: 180 | isOpening_ = false; 181 | break; 182 | case OpenSocket::ESocketError: 183 | printf("Listener::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 184 | break; 185 | case OpenSocket::ESocketWarning: 186 | printf("Listener::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 187 | break; 188 | case OpenSocket::ESocketOpen: 189 | isOpening_ = true; 190 | break; 191 | case OpenSocket::ESocketUdp: 192 | case OpenSocket::ESocketData: 193 | assert(false); 194 | break; 195 | default: 196 | break; 197 | } 198 | } 199 | }; 200 | 201 | ////////////Accepter////////////////////// 202 | struct ServerClient 203 | { 204 | int fd_; 205 | std::string addr_; 206 | std::string buffer_; 207 | ServerClient() :fd_(-1) {} 208 | }; 209 | class Accepter : public OpenThreadWorker 210 | { 211 | int listenId_; 212 | std::map mapClient_; 213 | public: 214 | Accepter(const std::string& name) 215 | :OpenThreadWorker(name), 216 | listenId_(-1) 217 | { 218 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Accepter::onSocketProto); 219 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Accepter::onProtoBuffer); 220 | } 221 | virtual ~Accepter() {} 222 | 223 | virtual void onStart() 224 | { 225 | while (listenId_ < 0) 226 | { 227 | listenId_ = ThreadId("listener"); 228 | OpenThread::Sleep(1000); 229 | } 230 | auto root = std::shared_ptr(new ProtoBuffer); 231 | root->msgId_ = new_accept; 232 | auto& data = root->data(); 233 | data = "listen success!"; 234 | send(listenId_, root); 235 | } 236 | private: 237 | void onProtoBuffer(const ProtoBuffer& proto) 238 | { 239 | if (proto.msgId_ == new_client) 240 | { 241 | auto msg = proto.data(); 242 | int accept_fd = msg.accept_fd_; 243 | if (accept_fd >= 0) 244 | { 245 | auto iter = mapClient_.find(accept_fd); 246 | if (iter != mapClient_.end()) 247 | { 248 | assert(false); 249 | mapClient_.erase(iter); 250 | OpenSocket::Instance().close(pid(), accept_fd); 251 | return; 252 | } 253 | 254 | auto& client = mapClient_[accept_fd]; 255 | client.fd_ = accept_fd; 256 | client.addr_ = msg.addr_; 257 | OpenSocket::Instance().start(pid_, accept_fd); 258 | } 259 | } 260 | } 261 | 262 | void onRead(const std::shared_ptr& msg) 263 | { 264 | auto iter = mapClient_.find(msg->fd_); 265 | if (iter == mapClient_.end()) 266 | { 267 | OpenSocket::Instance().close(pid_, msg->fd_); 268 | return; 269 | } 270 | auto& client = iter->second; 271 | client.buffer_.append(msg->data(), msg->size()); 272 | auto& buffer = client.buffer_; 273 | if (buffer.empty()) 274 | return; 275 | 276 | std::string data = "[" + name_ + "]" + client.addr_ + ":" + buffer; 277 | client.buffer_.clear(); 278 | OpenSocket::Instance().send(client.fd_, data.data(), (int)data.size()); 279 | } 280 | 281 | virtual void onSocketProto(const SocketProto& proto) 282 | { 283 | const auto msg = proto.data_; 284 | switch (msg->type_) 285 | { 286 | case OpenSocket::ESocketData: 287 | onRead(msg); 288 | break; 289 | case OpenSocket::ESocketClose: 290 | mapClient_.erase(msg->fd_); 291 | break; 292 | case OpenSocket::ESocketError: 293 | mapClient_.erase(msg->fd_); 294 | printf("Accepter::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 295 | break; 296 | case OpenSocket::ESocketWarning: 297 | printf("Accepter::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 298 | break; 299 | case OpenSocket::ESocketOpen: 300 | { 301 | auto iter = mapClient_.find(msg->fd_); 302 | if (iter == mapClient_.end()) 303 | { 304 | OpenSocket::Instance().close(pid_, msg->fd_); 305 | return; 306 | } 307 | } 308 | break; 309 | case OpenSocket::ESocketAccept: 310 | case OpenSocket::ESocketUdp: 311 | assert(false); 312 | break; 313 | default: 314 | break; 315 | } 316 | } 317 | }; 318 | 319 | struct TestMsg 320 | { 321 | int count_; 322 | TestMsg() :count_(0) {} 323 | }; 324 | struct User 325 | { 326 | int fd_; 327 | int userId_; 328 | std::string buffer_; 329 | }; 330 | class Client : public OpenThreadWorker 331 | { 332 | std::map mapUser_; 333 | public: 334 | Client(const std::string& name) 335 | :OpenThreadWorker(name) 336 | { 337 | registers(SocketProto::ProtoType(), (OpenThreadHandle)&Client::onSocketProto); 338 | registers(ProtoBuffer::ProtoType(), (OpenThreadHandle)&Client::onProtoBuffer); 339 | } 340 | virtual ~Client() {} 341 | virtual void onStart() 342 | { 343 | } 344 | private: 345 | void onProtoBuffer(const ProtoBuffer& proto) 346 | { 347 | if (proto.msgId_ == test_client) 348 | { 349 | auto msg = proto.data(); 350 | int count = msg.count_; 351 | int fd = 0; 352 | for (int i = 0; i < count; i++) 353 | { 354 | fd = OpenSocket::Instance().connect(pid_, TestClientIp_, TestServerPort_); 355 | if (fd < 0) 356 | { 357 | printf("Client::start_test faild fd = %d\n", fd); 358 | assert(0); 359 | } 360 | auto& user = mapUser_[fd]; 361 | user.fd_ = fd; 362 | user.userId_ = pid_ + i * 1000; 363 | printf("Client::start_test[%s] fd = %d \n", name().c_str(), fd); 364 | } 365 | } 366 | } 367 | void onRead(const std::shared_ptr& msg) 368 | { 369 | auto iter = mapUser_.find(msg->fd_); 370 | if (iter == mapUser_.end()) 371 | { 372 | OpenSocket::Instance().close(pid_, msg->fd_); 373 | return; 374 | } 375 | auto& user = iter->second; 376 | user.buffer_.append(msg->data(), msg->size()); 377 | printf("Client::onRead[%s:%d]:%s\n", name().c_str(), user.userId_, user.buffer_.c_str()); 378 | user.buffer_.clear(); 379 | OpenSocket::Sleep(500); 380 | std::string data = "Hello OpenSocket!"; 381 | OpenSocket::Instance().send(user.fd_, data.data(), (int)data.size()); 382 | } 383 | virtual void onSocketProto(const SocketProto& proto) 384 | { 385 | const auto msg = proto.data_; 386 | switch (msg->type_) 387 | { 388 | case OpenSocket::ESocketData: 389 | onRead(msg); 390 | break; 391 | case OpenSocket::ESocketClose: 392 | mapUser_.erase(msg->fd_); 393 | break; 394 | case OpenSocket::ESocketError: 395 | mapUser_.erase(msg->fd_); 396 | printf("Client::onStart [%s]ESocketError:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 397 | break; 398 | case OpenSocket::ESocketWarning: 399 | printf("Client::onStart [%s]ESocketWarning:%s\n", ThreadName((int)msg->uid_).c_str(), msg->info()); 400 | break; 401 | case OpenSocket::ESocketOpen: 402 | { 403 | auto iter = mapUser_.find(msg->fd_); 404 | if (iter == mapUser_.end()) 405 | { 406 | OpenSocket::Instance().close(pid_, msg->fd_); 407 | return; 408 | } 409 | std::string buffer = "Hello OpenSocket!"; 410 | OpenSocket::Instance().send(msg->fd_, buffer.data(), (int)buffer.size()); 411 | } 412 | break; 413 | case OpenSocket::ESocketAccept: 414 | case OpenSocket::ESocketUdp: 415 | assert(false); 416 | break; 417 | default: 418 | break; 419 | } 420 | } 421 | }; 422 | 423 | int main() 424 | { 425 | std::vector vectWorker; 426 | 427 | printf("start server==>>\n"); 428 | //server 429 | std::vector vectServer = 430 | { 431 | new Listener("listener"), 432 | new Accepter("accepter1"), 433 | new Accepter("accepter2"), 434 | new Accepter("accepter3"), 435 | new Accepter("accepter4") 436 | }; 437 | for (size_t i = 0; i < vectServer.size(); i++) 438 | { 439 | vectWorker.push_back(vectServer[i]); 440 | vectServer[i]->start(); 441 | } 442 | 443 | printf("slepp 3000 ms==>>\n"); 444 | //wait server start. 445 | OpenThread::Sleep(3000); 446 | 447 | printf("start client==>>\n"); 448 | //client 449 | std::vector vectClient = 450 | { 451 | new Client("client1"), 452 | new Client("client2"), 453 | new Client("client3"), 454 | new Client("client4"), 455 | }; 456 | for (size_t i = 0; i < vectClient.size(); i++) 457 | { 458 | vectWorker.push_back(vectClient[i]); 459 | vectClient[i]->start(); 460 | } 461 | 462 | auto proto = std::shared_ptr(new ProtoBuffer); 463 | proto->msgId_ = test_client; 464 | auto& data = proto->data(); 465 | data.count_ = 10; 466 | // 467 | for (size_t i = 0; i < vectClient.size(); i++) 468 | { 469 | vectClient[i]->send(vectClient[i]->pid(), proto); 470 | } 471 | 472 | printf("wait close==>>\n"); 473 | //wait all worker 474 | OpenThread::ThreadJoinAll(); 475 | for (size_t i = 0; i < vectWorker.size(); i++) 476 | { 477 | delete vectWorker[i]; 478 | } 479 | vectWorker.clear(); 480 | printf("Pause\n"); 481 | return getchar(); 482 | } -------------------------------------------------------------------------------- /test/udp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "opensocket.h" 3 | #include "openthread.h" 4 | 5 | int main() 6 | { 7 | printf("coding.\n"); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /test/worker.h: -------------------------------------------------------------------------------- 1 | #ifndef WORKER_HEADER_H 2 | #define WORKER_HEADER_H 3 | 4 | #include 5 | #include "opensocket.h" 6 | #include "open/openthread.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace open; 14 | 15 | enum EProtoType 16 | { 17 | EProtoText, 18 | EProtoSocket 19 | }; 20 | 21 | class Data 22 | { 23 | int srcPid_; 24 | EProtoType ptype_; 25 | std::string srcName_; 26 | std::string key_; 27 | std::shared_ptr proto_; 28 | Data(const Data& that) {} 29 | void operator=(const Data& that) {} 30 | 31 | public: 32 | Data() :srcPid_(-1), ptype_(EProtoText) {} 33 | Data(int pid, const std::string& name, const std::string& key) 34 | :srcPid_(pid), srcName_(name), key_(key) {} 35 | ~Data() { } 36 | 37 | inline const int& srcPid() const { return srcPid_; } 38 | inline const EProtoType& ptype() const { return ptype_; } 39 | inline const std::string& srcName() const { return srcName_; } 40 | inline const std::string& key() const { return key_; } 41 | 42 | template 43 | inline const T* proto() const 44 | { 45 | return dynamic_cast((const T*)proto_.get()); 46 | } 47 | inline void setProto(EProtoType ptype, const std::shared_ptr& proto) { ptype_ = ptype; proto_ = proto; } 48 | 49 | }; 50 | 51 | class Worker; 52 | typedef void(Worker::* Handle)(const Data&); 53 | struct Rpc 54 | { 55 | Handle handle_; 56 | }; 57 | 58 | class Worker : public OpenThreader 59 | { 60 | public: 61 | Worker(const std::string& name) 62 | :OpenThreader(name){} 63 | virtual ~Worker() {} 64 | template 65 | bool send(int sid, const std::string& key, const T& t) 66 | { 67 | printf("[%s]send=>[%s] key:%s\n", name_.c_str(), ThreadName(sid).c_str(), key.c_str()); 68 | auto data = std::shared_ptr(new Data(pid(), name_, key)); 69 | auto proto = std::shared_ptr(new const T(t)); 70 | data->setProto(EProtoText, proto); 71 | bool ret = OpenThread::Send(sid, data); 72 | assert(ret); 73 | return ret; 74 | } 75 | void onText(const Data& data) 76 | { 77 | printf("[%s]receive<<=[%s] key:%s\n", name_.c_str(), data.srcName().c_str(), data.key().c_str()); 78 | auto iter = mapKeyFunc_.find(data.key()); 79 | if (iter != mapKeyFunc_.end()) 80 | { 81 | auto& rpc = iter->second; 82 | if (rpc.handle_) 83 | { 84 | (this->*rpc.handle_)(data); 85 | return; 86 | } 87 | } 88 | printf("[%s]no implement key:%s\n", name_.c_str(), data.key().c_str()); 89 | } 90 | virtual void onSocket(const Data& data) 91 | { 92 | } 93 | virtual void onMsg(OpenThreadMsg& msg) 94 | { 95 | const Data* data = msg.data(); 96 | if (data) 97 | { 98 | if (data->ptype() == EProtoText) 99 | onText(*data); 100 | else if (data->ptype() == EProtoSocket) 101 | onSocket(*data); 102 | } 103 | } 104 | std::map mapKeyFunc_; 105 | }; 106 | 107 | class App 108 | { 109 | static void SocketFunc(const OpenSocketMsg* msg) 110 | { 111 | if (msg->uid_ >= 0) 112 | { 113 | auto data = std::shared_ptr(new Data()); 114 | auto proto = std::shared_ptr(msg); 115 | data->setProto(EProtoSocket, proto); 116 | bool ret = OpenThread::Send((int)msg->uid_, data); 117 | assert(ret); 118 | } 119 | else 120 | delete msg; 121 | } 122 | public: 123 | static App Instance_; 124 | OpenSocket openSocket_; 125 | App() 126 | { 127 | openSocket_.run(App::SocketFunc); 128 | } 129 | }; 130 | App App::Instance_; 131 | 132 | class Hashid 133 | { 134 | struct Node 135 | { 136 | int id_; 137 | Node* next_; 138 | }; 139 | int cap_; 140 | int count_; 141 | int hashmod_; 142 | Node* id_; 143 | Node** hash_; 144 | public: 145 | Hashid() 146 | :id_(0), 147 | hash_(0), 148 | cap_(0), 149 | count_(0), 150 | hashmod_(0) 151 | {} 152 | ~Hashid() { clear(); } 153 | inline int full() { return count_ == cap_; } 154 | void clear() 155 | { 156 | if (id_) 157 | { 158 | delete[] id_; 159 | id_ = 0; 160 | } 161 | if (hash_) 162 | { 163 | delete[] hash_; 164 | hash_ = 0; 165 | } 166 | } 167 | void init(int max) 168 | { 169 | clear(); 170 | int hashcap = 16; 171 | while (hashcap < max) { 172 | hashcap *= 2; 173 | } 174 | hashmod_ = hashcap - 1; 175 | cap_ = max; 176 | count_ = 0; 177 | id_ = new Node[max]; 178 | for (int i = 0; i < max; i++) { 179 | id_[i].id_ = -1; 180 | id_[i].next_ = NULL; 181 | } 182 | hash_ = new Node * [hashcap]; 183 | memset(hash_, 0, hashcap * sizeof(Node*)); 184 | } 185 | int lookup(int id) 186 | { 187 | int h = id & hashmod_; 188 | Node* c = hash_[h]; 189 | while (c) { 190 | if (c->id_ == id) 191 | return (int)(c - id_); 192 | c = c->next_; 193 | } 194 | return -1; 195 | } 196 | int remove(int id) 197 | { 198 | int h = id & hashmod_; 199 | Node* c = hash_[h]; 200 | if (c == NULL) 201 | return -1; 202 | if (c->id_ == id) { 203 | hash_[h] = c->next_; 204 | goto _clear; 205 | } 206 | while (c->next_) { 207 | if (c->next_->id_ == id) { 208 | Node* temp = c->next_; 209 | c->next_ = temp->next_; 210 | c = temp; 211 | goto _clear; 212 | } 213 | c = c->next_; 214 | } 215 | return -1; 216 | _clear: 217 | c->id_ = -1; 218 | c->next_ = NULL; 219 | --count_; 220 | return (int)(c - id_); 221 | } 222 | int insert(int id) 223 | { 224 | Node* c = NULL; 225 | for (int i = 0; i < cap_; ++i) { 226 | int index = (i + id) % cap_; 227 | if (id_[index].id_ == -1) { 228 | c = &id_[index]; 229 | break; 230 | } 231 | } 232 | assert(c); 233 | ++count_; 234 | c->id_ = id; 235 | assert(c->next_ == NULL); 236 | int h = id & hashmod_; 237 | if (hash_[h]) { 238 | c->next_ = hash_[h]; 239 | } 240 | hash_[h] = c; 241 | return (int)(c - id_); 242 | } 243 | }; 244 | 245 | #endif //WORKER_HEADER_H --------------------------------------------------------------------------------