OVERLAP.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:12k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. * Sample demonstrating use of Events in Overlapped (Asynchronous) I/O
  3. *
  4. * This code uses AcceptEx()
  5. * YOU MUST HAVE SERVICE PACK 3 on NT 3.51 to use it !!!
  6. *
  7. *       This is a part of the Microsoft Source Code Samples.
  8. *       Copyright 1996-1997 Microsoft Corporation.
  9. *       All rights reserved.
  10. *       This source code is only intended as a supplement to
  11. *       Microsoft Development Tools and/or WinHelp documentation.
  12. *       See these sources for detailed information regarding the
  13. *       Microsoft samples programs.
  14. ******************************************************************************/
  15. #define WIN32_LEAN_AND_MEAN
  16. #include <winsock2.h>
  17. #include <mswsock.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #define DEFAULT_PORT 5001
  22. #define MAX_IO_PEND 10 // maximum pending I/O requests
  23. #define OP_READ 0x10
  24. #define OP_WRITE 0x20
  25. #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
  26. #define xfree(p)   HeapFree(GetProcessHeap(),0,(p))
  27. //
  28. // This structure keeps some useful information
  29. //
  30. typedef struct _socklist {
  31. SOCKET sock;
  32. OVERLAPPED *overlap;
  33. char Buffer[128];
  34. }Socklist;
  35. int curr_size; //current number of handles we are intersted in
  36. int DoWait(HANDLE *,Socklist *) ;
  37. void HandleEvent(int , HANDLE *,Socklist *) ;
  38. void Usage(char *progname) {
  39. fprintf(stderr,"Usagen%s -e [endpoint] -i [interface]n",
  40. progname);
  41. fprintf(stderr,"Where:n");
  42. fprintf(stderr,"tendpoint is the port to listen onn");
  43. fprintf(stderr,"tinterface is the ipaddr (in dotted decimal notation)");
  44. fprintf(stderr," to bind ton");
  45. fprintf(stderr,"Defaults are 5001 and INADDR_ANYn");
  46. WSACleanup();
  47. exit(1);
  48. }
  49. int main(int argc, char **argv) {
  50. char *interface= NULL;
  51. char *Buffer = xmalloc(256);
  52. unsigned short port=DEFAULT_PORT;
  53. int i;
  54. struct sockaddr_in local;
  55. WSADATA wsaData;
  56. SOCKET listen_socket, accept_sock;
  57. OVERLAPPED *Overlap;
  58. DWORD bytes_read;
  59. DWORD lasterror;
  60. //
  61. // Handles is the array that stores the Event Handles
  62. HANDLE Handles[MAX_IO_PEND] ;
  63. //
  64. // socklist is a parallel array that keeps state information for
  65. // each Handle.
  66. Socklist socklist[MAX_IO_PEND];
  67. /* Parse arguments */
  68. if (argc >1) {
  69. for(i=1;i <argc;i++) {
  70. if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
  71. switch(tolower(argv[i][1])) {
  72. case 'i':
  73. interface = argv[++i];
  74. break;
  75. case 'e':
  76. port = atoi(argv[++i]);
  77. break;
  78. default:
  79. Usage(argv[0]);
  80. break;
  81. }
  82. }
  83. else
  84. Usage(argv[0]);
  85. }
  86. }
  87. if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
  88. fprintf(stderr,"WSAStartup failed with error %dn",WSAGetLastError());
  89. WSACleanup();
  90. return -1;
  91. }
  92. if (port == 0){
  93. Usage(argv[0]);
  94. }
  95. local.sin_family = AF_INET;
  96. local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface); 
  97. /* 
  98.  * Port MUST be in Network Byte Order
  99.  */
  100. local.sin_port = htons(port);
  101. listen_socket = socket(AF_INET,SOCK_STREAM,0); // TCP socket
  102. if(listen_socket == INVALID_SOCKET) {
  103. fprintf(stderr,"socket() failed with error %dn",WSAGetLastError());
  104. WSACleanup();
  105. return -1;
  106. }
  107. if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) ) 
  108. == SOCKET_ERROR) {
  109. fprintf(stderr,"bind() failed with error %dn",WSAGetLastError());
  110. WSACleanup();
  111. return -1;
  112. }
  113. if (listen(listen_socket,5) == SOCKET_ERROR) {
  114. fprintf(stderr,"listen() failed with error %dn",WSAGetLastError());
  115. WSACleanup();
  116. return -1;
  117. }
  118. printf("%s: Listening on port %dn",argv[0],port);
  119. //
  120. // Add the listening socket to our state information for the handle.
  121. //
  122. socklist[0].sock = listen_socket;
  123. curr_size =1;
  124. for(i=1;i<MAX_IO_PEND;i++)
  125. Handles[i] = INVALID_HANDLE_VALUE;
  126. //
  127. // The structure of the following loop is very similar to a situation
  128. // where select() might be used. 
  129. // We use WaitForSingleObject to multiplex between incoming/outgoing
  130. // data on existing connections.
  131. //
  132. // We don't queue an AcceptEx() until someone actually connects to 
  133. // the previous socket. This is to keep the code simple, not a limitation
  134. // of the API itself.
  135. while(1) {
  136. // create a socket for AcceptEx()
  137. accept_sock = socket(AF_INET,SOCK_STREAM,0);
  138. //
  139. // Allocate an overlapped structure.
  140. // We use the Offset field to keep track of the socket handle
  141. // we have accpeted a connection on, since there is no other
  142. // way to pass information to GetOverlappedResult()
  143. //
  144. Overlap = xmalloc(sizeof(OVERLAPPED));
  145. Overlap->Offset = accept_sock;
  146. Overlap->hEvent = CreateEvent(NULL,
  147.  TRUE,//manual reset
  148.  FALSE, // initially non-signalled
  149.  NULL);
  150. if (!Overlap->hEvent) {
  151. fprintf(stderr,"CreateEvent failed %dn",GetLastError());
  152. return -1;
  153. }
  154. //
  155. // Set the appropriate array members
  156. //
  157. Handles[0] = Overlap->hEvent;
  158. socklist[0].overlap = Overlap;
  159. // AcceptEx()
  160. if (!AcceptEx(listen_socket,
  161.   accept_sock,
  162.   Buffer,
  163.   0, // read nothing from the socket
  164.   sizeof(struct sockaddr_in) +16,
  165.   sizeof(struct sockaddr_in) +16,
  166.   &bytes_read,
  167.   Overlap)){
  168. lasterror=WSAGetLastError();
  169. if(lasterror!=ERROR_IO_PENDING){
  170. fprintf(stderr,"acceptex failed %dn",lasterror);
  171. return -1;
  172. }
  173. }
  174. //
  175. // This loop simple checks the handles to see which one is 
  176. // signalled. 
  177. // If error, exit. 
  178. // If there is a new incoming connection, we break to the outer loop
  179. // queue another AcceptEx()
  180. //
  181. while(1){
  182. i = DoWait(Handles,socklist);
  183. if (i<0)
  184. break;
  185. HandleEvent(i,Handles,socklist);
  186. if (i ==0)
  187. break;
  188. };
  189. if (i < 0)
  190. return -1;
  191. }
  192. }
  193. /*
  194.  * This is the main function that handles all the events occuring on the
  195.  * different handles we are watching.
  196.  *
  197.  * Parameters:
  198.  *          index: Index into the Handles[] array. Returned by DoWait()
  199.  *          Handles: Array of Event Handles we are watching
  200.  *          socklist: Helper parallel array of state information
  201.  *
  202.  */
  203. void HandleEvent(int index, HANDLE *Handles,Socklist *socklist) {
  204. OVERLAPPED *Overlap;
  205. SOCKET newsock;
  206. DWORD bytes,overlap_err=0,lasterr;
  207. Overlap = socklist[index].overlap;
  208. //
  209. // Check the specified handle
  210. //
  211. // If a socket is closed by the other side, the error returned is
  212. // ERROR_NETNAM_DELETED
  213. //
  214. if(!GetOverlappedResult(Handles[index], Overlap, &bytes, TRUE) ) {
  215. fprintf(stderr,"GetOverlappedResult failed with error %dn",
  216. overlap_err=GetLastError());
  217. if (overlap_err  != ERROR_NETNAME_DELETED) 
  218. return;
  219. }
  220. newsock = Overlap->Offset;
  221. //
  222. // If the other side closed the connection, close our socket and 
  223. // move the last element of the Handles[] array into our 
  224. // index.
  225. //
  226. // The array compaction is done so that we only pass valid handles
  227. // in the first "curr_size" elements of the array to
  228. // WaitForMultipleObjects(). The function will fail otherwise.
  229. // We should NEVER get this for our listening socket
  230. if (index && overlap_err == ERROR_NETNAME_DELETED) {
  231. closesocket(newsock);
  232. xfree(Overlap);
  233. Handles[index] = Handles[curr_size-1];
  234. socklist[index] = socklist[curr_size-1];
  235. curr_size--;
  236. return;
  237. }
  238. if( (index ==0) ) { //listening socket
  239. if (curr_size >= MAX_IO_PEND) {
  240. fprintf(stderr,"Too many pending requestsn");
  241. return;
  242. }
  243. //
  244. // Get the event handle used to queue the AcceptEx(),
  245. // and re-use it to queue a ReadFile on the socket.
  246. //
  247. Handles[curr_size] = Overlap->hEvent;
  248. socklist[curr_size].overlap = Overlap;
  249. //
  250. // The OffsetHigh field is used to keep track of what we are doing.
  251. // This enables us to alternate ReadFile and WriteFile on a 
  252. // connection
  253. Overlap->OffsetHigh = OP_READ;
  254. if (!ReadFile((HANDLE)newsock, socklist[curr_size].Buffer,
  255. sizeof(socklist[curr_size].Buffer),
  256. &bytes,
  257. Overlap) ) {
  258. lasterr = GetLastError();
  259. // Handle ERROR_NETNAME_DELETED specially
  260. // Other errors are Not Good
  261. //
  262. if (lasterr && lasterr != ERROR_IO_PENDING &&
  263. lasterr != ERROR_NETNAME_DELETED ) {
  264. fprintf(stderr,"Inital ReadFile failed %dn");
  265. return;
  266. }
  267. if (lasterr == ERROR_NETNAME_DELETED) {
  268. closesocket(newsock);
  269. xfree(Overlap);
  270. Handles[index] = Handles[curr_size];
  271. socklist[index] = socklist[curr_size];
  272. curr_size--;
  273. return;
  274. }
  275. }
  276. //
  277. // Increment the last valid handle location in the Handles
  278. // array.
  279. curr_size++;
  280. return;
  281. }
  282. //
  283. // This possibly indicates a closed socket.
  284. //
  285. if (  (bytes == 0 ) && (Overlap->OffsetHigh == OP_READ) ){
  286. closesocket(newsock);
  287. xfree(Overlap);
  288. Handles[index] = Handles[curr_size];
  289. socklist[index] = socklist[curr_size];
  290. curr_size--;
  291. return;
  292. }
  293. //
  294. //  If the previos operation was an OP_READ, queue WriteFile on the
  295. //  socket
  296. //
  297. if (Overlap->OffsetHigh == OP_READ) { // ReadFile was queued
  298. printf("Read buffer [%s]n",socklist[index].Buffer);
  299. printf("Echoing back to clientn");
  300. if (!WriteFile((HANDLE)newsock, socklist[index].Buffer,
  301. sizeof(socklist[index].Buffer),
  302. &bytes,
  303. Overlap) ) {
  304. lasterr = GetLastError();
  305. if (lasterr && lasterr != ERROR_IO_PENDING &&
  306. lasterr != ERROR_NETNAME_DELETED ) {
  307. fprintf(stderr,"WriteFile failed %dn");
  308. ExitProcess(1);
  309. }
  310. if ( (lasterr == ERROR_NETNAME_DELETED) || (!lasterr)) {
  311. closesocket(newsock);
  312. xfree(Overlap);
  313. Handles[index] = Handles[curr_size];
  314. socklist[index] = socklist[curr_size];
  315. curr_size--;
  316. return;
  317. }
  318. }
  319. Overlap->OffsetHigh = OP_WRITE;
  320. return;
  321. }
  322. //
  323. // If we had a WriteFile queued, now do a ReadFile
  324. //
  325. else if (Overlap->OffsetHigh == OP_WRITE) { // WriteFile was queued
  326. printf("Wrote %d bytesn",bytes);
  327. printf("Queueing readn");
  328. if (!ReadFile((HANDLE)newsock, socklist[index].Buffer,
  329. sizeof(socklist[index].Buffer),
  330. &bytes,
  331. Overlap) ) {
  332. lasterr =GetLastError();
  333. if (lasterr && lasterr != ERROR_IO_PENDING) {
  334. if (lasterr == ERROR_NETNAME_DELETED) {
  335. closesocket(newsock);
  336. xfree(Overlap);
  337. Handles[index] = Handles[curr_size];
  338. socklist[index] = socklist[curr_size];
  339. curr_size--;
  340. return;
  341. }
  342. fprintf(stderr,"ReadFile failed %dn",GetLastError());
  343. ExitProcess(1);
  344. }
  345. }
  346. Overlap->OffsetHigh = OP_READ;
  347. return;
  348. }
  349. else {
  350. fprintf(stderr,"Unknown operation queuedn");
  351. }
  352. }
  353. //
  354. // This is the wait function used to keep track of events
  355. //
  356. int DoWait(HANDLE *Handles,Socklist *socklist ) {
  357. DWORD wait_rc;
  358. HANDLE hTemp;
  359. Socklist socklTemp;
  360. int i;
  361. //
  362. // Rotate the array, beginning at index 1, by one element.
  363. // This ensures that all handles get a fair chance to be serviced.
  364. //
  365. // There is no way to detect how many handles were signalled when
  366. // WaitForMultipleObjects() returns. We simply pick the first one and 
  367. // come back to this function later
  368. // Without the rotation below, this has the potential for starving
  369. // connections accepted later.
  370. //
  371. // Index 0 is avoided, since it is our listening socket. 
  372. //
  373. for(i=1;i<curr_size-1;i++){
  374. hTemp = Handles[i+1];
  375. Handles[i+1] = Handles[i];
  376. Handles[i] = hTemp;
  377. socklTemp = socklist[i+1];
  378. socklist[i+1] = socklist[i];
  379. socklist[i] = socklTemp;
  380. }
  381. wait_rc = WaitForMultipleObjects(curr_size,Handles,FALSE,
  382. INFINITE);
  383. if (wait_rc == WAIT_FAILED) {
  384. fprintf(stderr,"Wait failed Error %dn",GetLastError());
  385. return -1;
  386. }
  387. return (wait_rc - WAIT_OBJECT_0);
  388. }