单进程单线程IOCP的实现(含客户端和服务端)

server.cpp

  1 // TestIOCPone.cpp : This file contains the 'main' function. Program execution begins and ends there.
  2 //
  3 #define _WINSOCK_DEPRECATED_NO_WARNINGS
  4 
  5 #include <iostream>
  6 #include <winsock2.h>
  7 #include <process.h>
  8 #include <MSWSock.h>
  9 #include <assert.h>
 10 #include <vector>
 11 
 12 #pragma comment(lib ,"ws2_32.lib")
 13 
 14 HANDLE hIocp = 0;
 15 LPFN_ACCEPTEX accept_ex;
 16 
 17 SOCKET listen_socket;
 18 
 19 
 20 
 21 
 22 enum CPK_TYPE {
 23     ACCEPT_POST = 1000, //接收请求的完成标识
 24     RECV_POST,
 25     SEND_POST,
 26     CLOSE_POST,
 27 };
 28 
 29 
 30 class io_context : public OVERLAPPED
 31 {
 32 public:
 33     io_context() {
 34         memset(static_cast<OVERLAPPED *>(this), 0, sizeof(OVERLAPPED));
 35         client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 36         buf_ = new char[4096];
 37         w_buf_.buf = buf_;
 38         w_buf_.len = 4096;
 39     }
 40     virtual ~io_context() {
 41 
 42     }
 43 
 44     int op_code = 0;
 45     WSABUF w_buf_;
 46     char* buf_;
 47     SOCKET client_socket;
 48 };
 49 
 50 
 51 
 52 
 53 void init_func(int s) {
 54     GUID guidAcceptEx = WSAID_ACCEPTEX;
 55     DWORD bytes = 0;
 56     if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx,
 57         sizeof(GUID), &accept_ex, sizeof(LPFN_ACCEPTEX), &bytes, NULL,
 58         NULL) == SOCKET_ERROR)
 59     {
 60         throw std::exception("get acceptex error:", GetLastError());
 61     }
 62 }
 63 
 64 
 65 
 66 void post_accept()
 67 {
 68 
 69 
 70     io_context* pIoContent = new io_context;
 71 
 72     pIoContent->op_code = ACCEPT_POST;
 73 
 74     DWORD len = 0;
 75 
 76     if (!accept_ex(listen_socket, pIoContent->client_socket, pIoContent->buf_, 0,
 77         sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &len,
 78         pIoContent)) {
 79         if (WSA_IO_PENDING != WSAGetLastError())
 80         {
 81             throw std::exception("accept_ex error:", GetLastError());
 82         }
 83     }
 84 }
 85 
 86 void post_recv(io_context* p_io_content)
 87 {
 88     DWORD recv_len = 0;
 89     DWORD flags = 0;
 90     p_io_content->op_code = RECV_POST;
 91 
 92     if (WSARecv(p_io_content->client_socket, &p_io_content->w_buf_,
 93         1, &recv_len, &flags, p_io_content, NULL) == SOCKET_ERROR) {
 94         if (WSAGetLastError() != WSA_IO_PENDING)
 95         {
 96             throw std::exception("recv error:", GetLastError());
 97         }
 98     }
 99 }
100 
101 void post_send(io_context* p_io_content, const char* data, int len)
102 {
103     DWORD send_len = 0;
104     DWORD flags = 0;
105 
106     p_io_content->op_code = SEND_POST;
107     memcpy(p_io_content->w_buf_.buf, data, len);
108 
109     p_io_content->w_buf_.len = len;
110 
111     if (WSASend(p_io_content->client_socket, &p_io_content->w_buf_,
112         1, &send_len, flags, p_io_content,
113         NULL) == SOCKET_ERROR) {
114         if (WSAGetLastError() != WSA_IO_PENDING)
115         {
116             throw std::exception("send error:", GetLastError());
117         }
118     }
119 }
120 
121 void do_something()
122 {
123     //做其他事情
124 }
125 
126 unsigned int __stdcall work_thread(void* lParam)
127 {
128     LPOVERLAPPED overlapped = NULL;
129     ULONG_PTR cl_key = 0;
130     DWORD recv_bytes = 0;
131     while (true) {
132         do_something();
133 
134         BOOL ret = GetQueuedCompletionStatus(hIocp, &recv_bytes, &cl_key,
135             &overlapped, 0);
136 
137 
138 
139         if (ret) {
140             if (CLOSE_POST == cl_key) {
141                 std::cout << "close & break " << std::endl;
142                 break;
143             }
144 
145             std::cout << "recv_bytes=" << recv_bytes << std::endl;
146             io_context* p_io_content = (io_context*)overlapped;
147 
148             if (p_io_content->op_code == SEND_POST) {
149                 std::cout << "send data ok" << std::endl;
150                 PostQueuedCompletionStatus(hIocp, 0, CLOSE_POST, 0);
151             }
152 
153             if (p_io_content->op_code == RECV_POST) {
154                 std::cout << p_io_content->buf_ << std::endl;
155 
156 
157                 const char* data = "hello from server........";
158                 post_send(p_io_content, data, strlen(data));
159 
160 
161             }
162 
163             if (ACCEPT_POST == cl_key) {
164                 std::cout << "1" << std::endl;
165                 post_accept();
166 
167                 if (!CreateIoCompletionPort((HANDLE)p_io_content->client_socket, hIocp, NULL,
168                     1)) {
169                     throw std::exception("bind listen to iocp", GetLastError());
170                 }
171 
172                 post_recv(p_io_content);
173             }
174 
175 
176 
177         }
178         else
179         {
180             Sleep(1);
181         }
182     }
183 
184     return 0;
185 }
186 
187 int main()
188 {
189     WSADATA wsa;
190     WSAStartup(MAKEWORD(2, 2), &wsa);
191 
192     listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
193 
194     assert(listen_socket != INVALID_SOCKET);
195     sockaddr_in addr = { 0 };
196     addr.sin_family = AF_INET;
197     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
198     addr.sin_port = htons(12345);
199 
200     if (0 != bind(listen_socket, (struct sockaddr *)&addr, sizeof(sockaddr))) {
201         throw std::exception("bind error", GetLastError());
202     }
203     int work_thread_num_ = 1;
204     hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL,
205         work_thread_num_);
206     if (!hIocp) {
207         throw std::exception("create iocp error", GetLastError());
208     }
209     init_func(listen_socket);
210     listen(listen_socket, 0);
211 
212 
213     post_accept();
214 
215     if (!CreateIoCompletionPort((HANDLE)listen_socket, hIocp, ACCEPT_POST, work_thread_num_)) {
216         throw std::exception("bind listen to iocp", GetLastError());
217     }
218 
219     work_thread(NULL);
220 
221 
222     WSACleanup();
223 
224 }
225 
226 

client.cpp

  1 #define _WINSOCK_DEPRECATED_NO_WARNINGS
  2 
  3 #include <iostream>
  4 #include <winsock2.h>
  5 
  6 #pragma comment(lib ,"ws2_32.lib")
  7 
  8 int main()
  9 {
 10     WSADATA wsa;
 11     WSAStartup(MAKEWORD(2, 2), &wsa);
 12 
 13     sockaddr_in client_addr;
 14     client_addr.sin_family = AF_INET;
 15     client_addr.sin_port = htons(12345);
 16     client_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
 17 
 18     SOCKET     client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 19 
 20     if (0 == connect(client_socket, (const sockaddr*)&client_addr, sizeof(client_addr))) {
 21         const char* pbuf = "client=> server...";
 22         char buf[256] = { 0 };
 23         Sleep(1000);
 24         int len = ::send(client_socket, pbuf, strlen(pbuf), 0);
 25         if (len > 0) {
 26             std::cout << "send len=" << len << std::endl;
 27             len = ::recv(client_socket, buf, 256, 0);
 28             if (len > 0) {
 29                 std::cout <<"len=" << len << " data=" << buf << std::endl;
 30             }
 31         }
 32 
 33     }
 34     Sleep(1000);
 35     closesocket(client_socket);
 36 
 37 
 38     WSACleanup();
 39     return 0;
 40 }
PS:会笑的人,运气通常都会比别人好。
原文地址:https://www.cnblogs.com/thinkinc999/p/13716711.html