step:
1.初始化Winsock
2.创建一个完成端口
3.根据服务器线程数创建一定量的线程数
4.准备好一个socket进行bind然后listen
5.进入循环accept等待客户请求
6.创建一个数据结构容纳socket和其他相关信息
7.将连进来的socket同完成端口相关联
8.投递一个准备接受的请求
以后就不断的重复5至8的过程
1: include
#define WIN32_LEAN_AND_MEAN //定义宏,不会出现error C2011: 'fd_set' : 'struct' type redefinition等错误
#define VC_EXTRALEAN
#include <windows.h>
#include <winsock2.h>
#include "iostream"
#pragma comment(lib, "Ws2_32.lib")
2: define data structure
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND; //发送字节数
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
3: init socket
1: WORD wVersionRequested;
2: WSADATA wsaData;
3: int Ret;
4:
5: wVersionRequested = MAKEWORD(2,0);
6: //err = WSAStartup(wVersionRequested, &wsaData);//调用Windows Sockets DLL
7: if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
8: {
9: printf("WSAStartup failed with error %d\n", Ret);
10: return;
11: }
4: allocate gloal heap memory
1: //使用NEW不可以 PerHandleData = new PER_HANDLE_DATA;
2: if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA))) == NULL)
3: {
4: printf("GlobalAlloc() failed with error %d\n", GetLastError());
5: return;
6: }
5: server side
1:
2: //server.cpp
3: #include <winsock2.h>
4: #include <windows.h>
5: #include "socketapi.h"
6: #include "socketnotify.h"
7: #include "iostream"
8:
9: using namespace std;
10: #pragma comment(lib, "Ws2_32")
11:
12: #define OP_READ 0
13: #define OP_WRITE 1
14: #define OP_ACCEPT 2
15: #define DATA_BUFSIZE 1024
16:
17:
18:
19: typedef struct
20: {
21: OVERLAPPED Overlapped;
22: WSABUF DataBuf;
23: CHAR Buffer[DATA_BUFSIZE];
24: DWORD BytesSEND; //发送字节数
25: DWORD BytesRECV;
26: } PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
27:
28:
29: typedef struct
30: {
31: SOCKET Socket;
32: } PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
33:
34:
35: DWORD __stdcall CompletionRoutine(LPVOID Param);
36: int main()
37: {
38: WORD wVersionRequested;
39: WSADATA wsaData;
40: int Ret;
41:
42: wVersionRequested = MAKEWORD(2,0);
43: //err = WSAStartup(wVersionRequested, &wsaData);//调用Windows Sockets DLL
44: if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
45: {
46: printf("WSAStartup failed with error %d\n", Ret);
47: return;
48: }
49: HANDLE CompletionPort;
50: LPPER_HANDLE_DATA PerHandleData ;
51: LPPER_IO_OPERATION_DATA PerIoData ;
52: SOCKADDR_IN InternetAddr;
53: DWORD RecvBytes;
54: DWORD Flags;
55: SOCKET server;
56: SOCKET Accept;
57: if ((server = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
58: WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
59: {
60: printf("WSASocket() failed with error %d\n", WSAGetLastError());
61: return;
62: }
63: InternetAddr.sin_family = AF_INET;
64: InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
65: InternetAddr.sin_port = htons(8000);
66: if (bind(server, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
67: {
68: printf("bind() failed with error %d\n", WSAGetLastError());
69: WSACleanup();
70: return;
71: }
72:
73: if (listen(server, 5) == SOCKET_ERROR)
74: {
75: printf("listen() failed with error %d\n", WSAGetLastError());
76: WSACleanup();
77: return;
78: }
79: // server.set_port(8000);
80: // server.listen();
81: ///////////////////////////
82: //取得系统中CPU的数目,创建和CPU数目相等的线程,如果事先估计到完成端口处理线程会堵塞,
83: //可以考虑创建 SysInfo.dwNumberOfProcessors*2个线程。一般在单处理器上创建和CPU数目相等
84: //的线程就可以了
85: //获得CPU个数
86: SYSTEM_INFO sysInfo;
87: ZeroMemory(&sysInfo,sizeof(SYSTEM_INFO));
88: ZeroMemory(&wsaData,sizeof(WSADATA));
89: GetSystemInfo(&sysInfo);
90: int nNumberOfConcurrent = sysInfo.dwNumberOfProcessors * 2+2;
91:
92: CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, nNumberOfConcurrent);
93: if (NULL == CompletionPort)
94: {
95: cout << "CreateIoCompletionPort() failed: " << GetLastError() << endl;
96:
97: return ;
98: }
99:
100: PER_IO_OPERATION_DATA per_io_data;
101:
102: cout<<"port:"<<CompletionPort<<endl;
103: HANDLE m_hThreadArray[8];
104: for (int i=0; i<1; i++)
105: {
106: m_hThreadArray[i] = CreateThread(NULL, 0, CompletionRoutine, (LPVOID)CompletionPort, 0, NULL);
107: if (NULL == m_hThreadArray[i])
108: {
109: while (i>0)
110: {
111: CloseHandle(m_hThreadArray[i-1]);
112: m_hThreadArray[i-1] = INVALID_HANDLE_VALUE;
113: i--;
114: }//end of while
115:
116: cout << "CreateThread() failed: " << GetLastError() << endl;
117: CloseHandle(CompletionPort);
118:
119:
120: return ;
121: }
122: }//end of for
123:
124: Sleep(1000);
125: while(1)
126: {
127: cout<<"waiting for accept "<<endl;
128: //int sClient = server.accept();
129:
130: if ((Accept = WSAAccept(server, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
131: {
132: printf("WSAAccept() failed with error %d\n", WSAGetLastError());
133: return;
134: }
135:
136: cout<<"accetp :"<<Accept<<endl;
137:
138: //PerHandleData = new PER_HANDLE_DATA;
139: if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA))) == NULL)
140: {
141: printf("GlobalAlloc() failed with error %d\n", GetLastError());
142: return;
143: }
144: PerHandleData->Socket = Accept;
145: if(CreateIoCompletionPort((HANDLE)Accept, CompletionPort, (DWORD)PerHandleData, 0) == NULL)
146: {
147: printf("CreateIoCompletionPort failed with error %d\n", GetLastError());
148: return ;
149:
150: }
151: //PerIoData = new PER_IO_OPERATION_DATA;
152: //
153: //清管子的数据结构,准备往里面灌数据
154: //
155: if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA))) == NULL)
156: {
157: printf("GlobalAlloc() failed with error %d\n", GetLastError());
158: return;
159: }
160: memset(&(PerIoData->Overlapped), sizeof(OVERLAPPED),0);
161: PerIoData->BytesSEND = 0;
162: PerIoData->BytesRECV = 0;
163: PerIoData->DataBuf.len = DATA_BUFSIZE;
164: PerIoData->DataBuf.buf = PerIoData->Buffer;
165:
166: //
167: // accept接到了数据,就放到PerIoData中,而perIoData又通过线程中的函数取出,
168: //
169:
170: RecvBytes = 0;
171: Flags = 0;
172: if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
173: &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
174: {
175: if (WSAGetLastError() != ERROR_IO_PENDING)
176: {
177: printf("main WSARecv() failed with error %d\n", WSAGetLastError());
178: WSACleanup();
179: return;
180: }
181: }
182: //cout<<"recv :"<<PerIoData->Buffer<<endl;
183:
184:
185:
186: }
187: PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL);
188: CloseHandle(CompletionPort);
189:
190: WSACleanup();
191:
192: cin>>i;
193: return ;
194: }
195:
196: DWORD __stdcall CompletionRoutine(LPVOID Param)
197: {
198:
199: HANDLE CompletionPort = (HANDLE) Param;
200:
201: PER_IO_OPERATION_DATA *pData = (PER_IO_OPERATION_DATA*)Param;
202:
203: DWORD BytesTransferred;
204: LPOVERLAPPED Overlapped;
205: LPPER_HANDLE_DATA PerHandleData;
206: LPPER_IO_OPERATION_DATA PerIoData;
207: DWORD SendBytes, RecvBytes;
208: DWORD Flags;
209:
210:
211:
212: while(1)
213: {
214:
215: int bSuccess = GetQueuedCompletionStatus(
216: CompletionPort,
217: &BytesTransferred,
218: (LPDWORD)&PerHandleData,
219: (LPOVERLAPPED *) &PerIoData,
220: INFINITE
221: );
222:
223: cout<<"----------------------------"<<endl;
224:
225: if (0 == bSuccess)
226: {
227: if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
228: &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
229: {
230: int iError = WSAGetLastError();
231: if ( iError!= ERROR_IO_PENDING)
232: {
233: printf("client %d closed \n", PerHandleData->Socket);
234: closesocket(PerHandleData->Socket);
235: }
236: }
237:
238: continue;
239: }
240: if (NULL == PerIoData)
241: {
242: //
243: cout<<"//PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了。"<<endl;
244: //
245: return 0;
246: }
247: Flags = 0;
248: if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
249: &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
250: {
251: if (WSAGetLastError() != ERROR_IO_PENDING)
252: {
253: printf("thread WSARecv() failed with error %d\n", WSAGetLastError());
254: return 0;
255: }
256: }
257:
258: cout<<"recv from "<<PerHandleData->Socket<<":"<<PerIoData->Buffer<<endl;
259:
260:
261: }
262:
263: return 0;
264: }
6: client side
1: #include "iostream"
2:
3: #include <winsock2.h>
4: #include <windows.h>
5: using namespace std;
6: #pragma comment(lib, "Ws2_32")
7:
8:
9: int main()
10: {
11: WORD wVersionRequested;
12: WSADATA wsaData;
13: int err;
14: wVersionRequested = MAKEWORD(2,0);
15: err = WSAStartup(wVersionRequested, &wsaData);//调用Windows Sockets DLL
16: if(err != 0)
17: {
18: cout<<"socket init error."<< endl;
19: }
20: int i=0;
21: int iRet = 0;
22: SOCKET client;
23:
24: client = socket( AF_INET, SOCK_STREAM, 0);
25: if( client == INVALID_SOCKET )
26: {
27: cout<< "socket() error"<<WSAGetLastError() <<endl;
28: }
29: SOCKADDR_IN saServer;
30:
31: memset(&saServer,0,sizeof(saServer));
32:
33: saServer.sin_family = AF_INET;
34: saServer.sin_addr.s_addr = inet_addr("127.0.0.1");
35: saServer.sin_port = htons(8000);
36: int nRet = connect(client,(sockaddr*)&saServer, sizeof(saServer));
37: if( iRet == SOCKET_ERROR)
38: {
39: cout<<"connect error"<<endl;
40: return 0;
41: }
42: else
43: {
44: cout<<"iRet:"<<iRet<<endl;
45: cout<<"connect success"<<WSAGetLastError()<<endl;
46: }
47: char buffer[128]={0};
48: while(1)
49: {
50: memset(buffer,0,128);
51: cout<<"input to send:";
52: cin>>buffer;
53: if(buffer[0] == 'q')
54: break;
55: int nBytes;
56:
57: if ((nBytes = send(client, buffer, strlen(buffer),0))
58: == SOCKET_ERROR)
59: {
60: if (GetLastError() == WSAEWOULDBLOCK)
61: {
62: printf("Blocking\n");
63: Sleep(100);
64: break;
65: }
66: else
67: {
68: cout<<"send error:"<<GetLastError()<<endl;
69: closesocket(client);
70: break;
71: }
72: }
73: cout<<"send success .."<<endl;
74: }
75: WSACleanup();
76: return 0;
77: }