문제 해결 - WSAAsyncSelect 모델 은 FD 를 터치 하지 않 습 니 다.CLOSE

47442 단어 select
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
본 고 는 오리지널 로 본문 에 나타 난 작가 와 출처 를 밝 히 고 문장의 완전 성 을 확보한다.
작가 의 동의 없 이 수정 하지 마 십시오 (본 성명 포함). 법률 추궁 의 권 리 를 보류 합 니 다.
작가 의 동의 없 이 출판, 인쇄 또는 학술 인용 에 사용 하지 마 십시오.
본 고 는 비정 기적 으로 수정 하고 보완 하 며 내용 이 정확 하도록 원문 으로 옮 겨 읽 는 것 을 권장 합 니 다.
본문 링크: http://www.cnblogs.com/wlsandwho/p/4228894.html
=======================================================================
 최근 한 학우 가 사직 을 했 는데, QQ 공간 에서 북상 하여 일자 리 를 찾 겠 다 고 하 는데, 무엇 을 하 느 냐 고 묻 자, "연전 에 사직 하고, 연후 에 출근한다" 고 대답 했다.
이렇게 하면 정말 좋 습 니까?
=======================================================================
 최근 작은 것 을 쓰 고 있 는데 비 차단 모드 의 소켓 이 필요 하 다. MFC 인터페이스 가 사용 되 고 정 보 량 이 많 지 않 고 무 서운 점 을 고려 해 WSAAsyncSelect 모델 을 선택 했다.
=======================================================================
1 대 N 의 상황 을 고려 하여 매번 accept 후에 map < socket, Client Info > 의 저장 구 조 를 유지 하고 자 연 스 럽 게 클 라 이언 트 가 정상적으로 닫 힐 때마다 이 구 조 를 다시 업데이트 해 야 합 니 다.
=======================================================================
"클 라 이언 트 가 정상적으로 닫 힐 때마다" shutdown 과 closessocket 을 호출 하기 때문에 FD 를 처리 해 야 합 니 다.CLOSE。
=======================================================================
무 서운 것 은 FDCLOSE 의 분기 가 트리거 되 지 않 았 습 니 다.
=======================================================================
그렇다면 문제 가 생 겼 는데, 도대체 왜 촉발 되 지 않 았 을 까?
나 는 감청 후의 WSAAsyncSelect 를 보 았 다.
1 WSAAsyncSelect(m_sockListen,hWnd,m_wMsgServer,FD_ACCEPT|FD_CLOSE)

연결 을 받 은 WSAAsyncSelect 를 다시 봤 어 요.
1 WSAAsyncSelect(sockClient, hWnd, m_wMsgServer, FD_READ|FD_WRITE|FD_CLOSE)

괜 찮 은 것 같은 데, 이상해.
=======================================================================
자신의 코드 를 살짝 보고 인터넷 에 있 는 자 료 를 찾 아 보기 로 했 는데 자 연 스 럽 게 결과 가 없 었 다.
'윈도 네트워크 프로 그래 밍 기술' 의 원본 코드 를 대조 해서 무시 하 는 부분 이 있 는 지 볼 수 밖 에 없다.
책의 원본 코드 를 붙 여 주세요.
  1 // Module Name: asyncselect.cpp
  2 //
  3 // Description:
  4 //
  5 //    This sample illustrates how to develop a simple echo server Winsock
  6 //    application using the WSAAsyncSelect() I/O model. This sample is
  7 //    implemented as a console-style application (to reduce the programming
  8 //    complexity of writing a real Windows application) and simply prints
  9 //    messages when connections are established and removed from the server.
 10 //    The application listens for TCP connections on port 5150 and accepts them
 11 //    as they arrive. When this application receives data from a client, it
 12 //    simply echos (this is why we call it an echo server) the data back in
 13 //    it's original form until the client closes the connection.
 14 //
 15 //    Since the WSAAsyncSelect I/O model requires an application to manage
 16 //    window messages when network event occur, this application creates
 17 //    a window for the I/O model only. The window stays hidden during the
 18 //    entire execution of this application.
 19 //
 20 // Compile:
 21 //
 22 //    cl -o asyncselect asyncselect.cpp ws2_32.lib user32.lib gdi32.lib
 23 //
 24 // Command Line Options:
 25 //
 26 //    asyncselect.exe 
 27 //
 28 //    Note: There are no command line options for this sample.
 29 
 30 #include <winsock2.h>
 31 #include <windows.h>
 32 #include <stdio.h>
 33 #include <conio.h>
 34 
 35 #define PORT 5150
 36 #define DATA_BUFSIZE 8192
 37 
 38 typedef struct _SOCKET_INFORMATION {
 39    BOOL RecvPosted;
 40    CHAR Buffer[DATA_BUFSIZE];
 41    WSABUF DataBuf;
 42    SOCKET Socket;
 43    DWORD BytesSEND;
 44    DWORD BytesRECV;
 45    _SOCKET_INFORMATION *Next;
 46 } SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
 47 
 48 #define WM_SOCKET (WM_USER + 1)
 49 
 50 void CreateSocketInformation(SOCKET s);
 51 LPSOCKET_INFORMATION GetSocketInformation(SOCKET s);
 52 void FreeSocketInformation(SOCKET s);
 53 
 54 HWND MakeWorkerWindow(void);
 55 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 56 
 57 LPSOCKET_INFORMATION SocketInfoList;
 58 
 59 void main(void)
 60 {
 61    MSG msg;
 62    DWORD Ret;
 63    SOCKET Listen;
 64    SOCKADDR_IN InternetAddr;
 65    HWND Window;
 66    WSADATA wsaData;
 67 
 68    if ((Window = MakeWorkerWindow()) == NULL)
 69       return;
 70 
 71    // Prepare echo server
 72 
 73    if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
 74    {
 75       printf("WSAStartup failed with error %d
", Ret); 76 return; 77 } 78 79 if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 80 { 81 printf("socket() failed with error %d
", WSAGetLastError()); 82 return; 83 } 84 85 WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT|FD_CLOSE); 86 87 InternetAddr.sin_family = AF_INET; 88 InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); 89 InternetAddr.sin_port = htons(PORT); 90 91 if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR) 92 { 93 printf("bind() failed with error %d
", WSAGetLastError()); 94 return; 95 } 96 97 if (listen(Listen, 5)) 98 { 99 printf("listen() failed with error %d
", WSAGetLastError()); 100 return; 101 } 102 103 // Translate and dispatch window messages for the application thread 104 105 while(Ret = GetMessage(&msg, NULL, 0, 0)) 106 { 107 if (Ret == -1) 108 { 109 printf("GetMessage() failed with error %d
", GetLastError()); 110 return; 111 } 112 113 TranslateMessage(&msg); 114 DispatchMessage(&msg); 115 } 116 } 117 118 119 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 120 { 121 SOCKET Accept; 122 LPSOCKET_INFORMATION SocketInfo; 123 DWORD RecvBytes, SendBytes; 124 DWORD Flags; 125 126 if (uMsg == WM_SOCKET) 127 { 128 if (WSAGETSELECTERROR(lParam)) 129 { 130 printf("Socket failed with error %d
", WSAGETSELECTERROR(lParam)); 131 FreeSocketInformation(wParam); 132 } 133 else 134 { 135 switch(WSAGETSELECTEVENT(lParam)) 136 { 137 case FD_ACCEPT: 138 139 if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET) 140 { 141 printf("accept() failed with error %d
", WSAGetLastError()); 142 break; 143 } 144 145 // Create a socket information structure to associate with the 146 // socket for processing I/O. 147 148 CreateSocketInformation(Accept); 149 150 printf("Socket number %d connected
", Accept); 151 152 WSAAsyncSelect(Accept, hwnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE); 153 154 break; 155 156 case FD_READ: 157 158 SocketInfo = GetSocketInformation(wParam); 159 160 // Read data only if the receive buffer is empty. 161 162 if (SocketInfo->BytesRECV != 0) 163 { 164 SocketInfo->RecvPosted = TRUE; 165 return 0; 166 } 167 else 168 { 169 SocketInfo->DataBuf.buf = SocketInfo->Buffer; 170 SocketInfo->DataBuf.len = DATA_BUFSIZE; 171 172 Flags = 0; 173 if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, 174 &Flags, NULL, NULL) == SOCKET_ERROR) 175 { 176 if (WSAGetLastError() != WSAEWOULDBLOCK) 177 { 178 printf("WSARecv() failed with error %d
", WSAGetLastError()); 179 FreeSocketInformation(wParam); 180 return 0; 181 } 182 } 183 else // No error so update the byte count 184 { 185 SocketInfo->BytesRECV = RecvBytes; 186 } 187 } 188 189 // DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV. Go ahead 190 // and begin writing data to the client. 191 192 case FD_WRITE: 193 194 SocketInfo = GetSocketInformation(wParam); 195 196 if (SocketInfo->BytesRECV > SocketInfo->BytesSEND) 197 { 198 SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND; 199 SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND; 200 201 if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0, 202 NULL, NULL) == SOCKET_ERROR) 203 { 204 if (WSAGetLastError() != WSAEWOULDBLOCK) 205 { 206 printf("WSASend() failed with error %d
", WSAGetLastError()); 207 FreeSocketInformation(wParam); 208 return 0; 209 } 210 } 211 else // No error so update the byte count 212 { 213 SocketInfo->BytesSEND += SendBytes; 214 } 215 } 216 217 if (SocketInfo->BytesSEND == SocketInfo->BytesRECV) 218 { 219 SocketInfo->BytesSEND = 0; 220 SocketInfo->BytesRECV = 0; 221 222 // If a RECV occurred during our SENDs then we need to post an FD_READ 223 // notification on the socket. 224 225 if (SocketInfo->RecvPosted == TRUE) 226 { 227 SocketInfo->RecvPosted = FALSE; 228 PostMessage(hwnd, WM_SOCKET, wParam, FD_READ); 229 } 230 } 231 232 break; 233 234 case FD_CLOSE: 235 236 printf("Closing socket %d
", wParam); 237 FreeSocketInformation(wParam); 238 239 break; 240 } 241 } 242 return 0; 243 } 244 245 return DefWindowProc(hwnd, uMsg, wParam, lParam); 246 } 247 248 249 void CreateSocketInformation(SOCKET s) 250 { 251 LPSOCKET_INFORMATION SI; 252 253 if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR, 254 sizeof(SOCKET_INFORMATION))) == NULL) 255 { 256 printf("GlobalAlloc() failed with error %d
", GetLastError()); 257 return; 258 } 259 260 // Prepare SocketInfo structure for use. 261 262 SI->Socket = s; 263 SI->RecvPosted = FALSE; 264 SI->BytesSEND = 0; 265 SI->BytesRECV = 0; 266 267 SI->Next = SocketInfoList; 268 269 SocketInfoList = SI; 270 } 271 272 LPSOCKET_INFORMATION GetSocketInformation(SOCKET s) 273 { 274 SOCKET_INFORMATION *SI = SocketInfoList; 275 276 while(SI) 277 { 278 if (SI->Socket == s) 279 return SI; 280 281 SI = SI->Next; 282 } 283 284 return NULL; 285 } 286 287 void FreeSocketInformation(SOCKET s) 288 { 289 SOCKET_INFORMATION *SI = SocketInfoList; 290 SOCKET_INFORMATION *PrevSI = NULL; 291 292 while(SI) 293 { 294 if (SI->Socket == s) 295 { 296 if (PrevSI) 297 PrevSI->Next = SI->Next; 298 else 299 SocketInfoList = SI->Next; 300 301 closesocket(SI->Socket); 302 GlobalFree(SI); 303 return; 304 } 305 306 PrevSI = SI; 307 SI = SI->Next; 308 } 309 } 310 311 HWND MakeWorkerWindow(void) 312 { 313 WNDCLASS wndclass; 314 CHAR *ProviderClass = "AsyncSelect"; 315 HWND Window; 316 317 wndclass.style = CS_HREDRAW | CS_VREDRAW; 318 wndclass.lpfnWndProc = (WNDPROC)WindowProc; 319 wndclass.cbClsExtra = 0; 320 wndclass.cbWndExtra = 0; 321 wndclass.hInstance = NULL; 322 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 323 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 324 wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 325 wndclass.lpszMenuName = NULL; 326 wndclass.lpszClassName = ProviderClass; 327 328 if (RegisterClass(&wndclass) == 0) 329 { 330 printf("RegisterClass() failed with error %d
", GetLastError()); 331 return NULL; 332 } 333 334 // Create a window. 335 336 if ((Window = CreateWindow( 337 ProviderClass, 338 "", 339 WS_OVERLAPPEDWINDOW, 340 CW_USEDEFAULT, 341 CW_USEDEFAULT, 342 CW_USEDEFAULT, 343 CW_USEDEFAULT, 344 NULL, 345 NULL, 346 NULL, 347 NULL)) == NULL) 348 { 349 printf("CreateWindow() failed with error %d
", GetLastError()); 350 return NULL; 351 } 352 353 return Window; 354 }

코드 에서 FD 가 실 현 된 것 을 알 았 습 니 다.WRITE, 그래서 이 지점 코드 블록의 구체 적 인 내용 을 차단 했다.이렇게 되면 나의 코드 와 논리 적 인 차 이 는 바로 내 가 FD 를 실현 하지 못 했다 는 것 이다.WRITE 분기.
MSDN 의 문서 가 너무 많은 것 을 감안 하여 오늘 은 금요일 이 라 자세히 보고 싶 지 않 아 자신의 코드 에 FD 를 추가 해 보 았 습 니 다.WRITE_BIT 의 처리 - 빈 코드 블록.
1     case FD_WRITE:
2         {
3 
4         }
5         break;

성공 하 다 니.
 
나중에 여러 번 시 도 했 는데 WSAAsyncSelect 에 어떤 FD 가 나열 되 어 있 는 지 알 게 되 었 습 니 다.XXXX, 이 루 고 싶 지 않 은 것 은 열거 하지 마 세 요.
 (왜 그런 지 에 대해 서 는 문 서 를 봐 야 한다.)
= = = = = = = = = = = = = = = = = = = = =
 
 
 
 
 
 
 
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 치욕의 벽 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
http://www.cnblogs.com/wlsandwho/p/4206472.html
 
 
 
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 추가 확장 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
그럼, FDWRITE 는 또 언제 촉발 되 나 요?
한 번 검색 하여 비교적 믿 을 만 한 것 을 찾 았 다. http://bbs.csdn.net/topics/200074769
현재 12 층 cpp_programer 의 총 결 을 발췌 하여 기록 합 니 다.
 
소켓 연결 이 만 들 어 졌 을 때 (클 라 이언 트 의 connect (), connectex () 등 서버 측의 accept 가 받 아들 여 만 든 새 소켓 포함) FD 가 실 행 됩 니 다.WRITE, 앞으로 send (), WSASend () 로 데 이 터 를 보 낼 수 있 습 니 다. 나중에 정상적으로 보 내 면 FD 를 터치 하지 않 습 니 다.WRITE. 데이터 가 정상적으로 전송 되 지 않 으 면 send (), WSASend () 등 으로 데 이 터 를 보 내 고 WSAGetLastError () 는 WSAEWOULDBLOCK 오 류 를 되 돌려 줍 니 다. 시스템 버퍼 가 데 이 터 를 다시 보 낼 수 있 을 때 FD 가 실 행 됩 니 다.WRITE.
 
 

좋은 웹페이지 즐겨찾기