WSOCK.C //----------------------------------------------------------------------------- // This is a part of the Microsoft Source Code Samples. // Copyright 1993 - 1998 Microsoft Corporation. // All rights reserved. // // This source code is only intended as a supplement to // Microsoft Development Tools and/or WinHelp documentation. // See these sources for detailed information regarding the // Microsoft samples programs. //----------------------------------------------------------------------------- /****************************************************************************\ * wsock.c -- sample program demonstrating Windows Sockets APIs. * * Demonstrates basic sockets programming with the Windows Sockets API. * Allows two occurances of the application to connect. Also, displays * information about a host computer. * ****************************************************************************/ #include <windows.h> /* required for all Windows applications */ #include <stdio.h> /* for sprintf */ #include <string.h> /* for strlen */ #include <memory.h> #include <process.h> /* for _beginthread */ #include "wsock.h" /* specific to this program */ HANDLE hInst; /* current instance */ SOCKET sock; u_short portno; /* Which tcp port are we going to use? */ char szBuff[ 80 ]; /* Temp buffer - used to pass strings */ /* to and from dialog boxes, etc */ char gpszHelloWorld[]= "Hello World."; #define MAX_PENDING_CONNECTS 4 /* The backlog allowed for listen() */ #define NO_FLAGS_SET 0 /* Used with recv()/send() */ #define MY_MSG_LENGTH 80 /* msg buffer sent back and forth */ /**************************************************************************** * * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) * * PURPOSE: calls initialization function, processes message loop * *\***************************************************************************/ WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; UNREFERENCED_PARAMETER( lpCmdLine ); if (!hPrevInstance) /* Other instances of app running? */ if (!InitApplication(hInstance)) /* Initialize shared things */ return (FALSE); /* Exits if unable to initialize */ /* * Perform initializations that apply to a specific instance */ if (!InitInstance(hInstance, nCmdShow)) return (FALSE); /* * Acquire and dispatch messages until a WM_QUIT message is received. */ while (GetMessage(&msg, /* message structure */ NULL, /* handle of window receiving the message */ 0, /* lowest message to examine */ 0)) /* highest message to examine */ { TranslateMessage(&msg); /* Translates virtual key codes */ DispatchMessage(&msg); /* Dispatches message to window */ } return (msg.wParam); /* Returns the value from PostQuitMessage */ } /**************************************************************************** * * FUNCTION: InitApplication(HANDLE) * * PURPOSE: Initializes window data and registers window class * *\***************************************************************************/ BOOL InitApplication(HANDLE hInstance) /* current instance */ { WNDCLASS wc; /* Fill in window class structure with parameters that describe the */ /* main window. */ wc.style = 0; /* Class style(s). */ wc.lpfnWndProc = (WNDPROC)MainWndProc; /* Function to retrieve messages for */ /* windows of this class. */ wc.cbClsExtra = 0; /* No per-class extra data. */ wc.cbWndExtra = 0; /* No per-window extra data. */ wc.hIcon = LoadIcon (hInstance, "wsockicon"); /* Icon name from .RC */ wc.hInstance = hInstance; /* Application that owns the class. */ wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "WSockMenu"; /* Name of menu resource in .RC file. */ wc.lpszClassName = "WSockWClass"; /* Name used in call to CreateWindow. */ /* Register the window class and return success/failure code. */ return (RegisterClass(&wc)); } /****************************************************************************\ * * FUNCTION: InitInstance(HANDLE, int) * * PURPOSE: Saves instance handle and creates main window * *\***************************************************************************/ BOOL InitInstance( HANDLE hInstance, /* Current instance identifier. */ int nCmdShow) /* Param for first ShowWindow() call. */ { HWND hWnd; /* Main window handle. */ /* Save the instance handle in static variable, which will be used in */ /* many subsequence calls from this application to Windows. */ hInst = hInstance; /* Create a main window for this application instance. */ hWnd = CreateWindow( "WSockWClass", /* See RegisterClass() call. */ "Windows Sockets Sample Application", /* Text for window title bar. */ WS_OVERLAPPEDWINDOW, /* Window style. */ CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default vertical position. */ CW_USEDEFAULT, /* Default width. */ CW_USEDEFAULT, /* Default height. */ NULL, /* Overlapped windows have no parent. */ NULL, /* Use the window class menu. */ hInstance, /* This instance owns this window. */ NULL /* Pointer not needed. */ ); /* If window could not be created, return "failure" */ if (!hWnd) return (FALSE); /* Make the window visible; update its client area; and return "success" */ ShowWindow(hWnd, nCmdShow); /* Show the window */ UpdateWindow(hWnd); /* Sends WM_PAINT message */ return (TRUE); /* Returns the value from PostQuitMessage */ } /****************************************************************************\ * * FUNCTION: AcceptThreadProc(PTHREADPACK tp) * * PURPOSE: Use blocking accept() calls and display a message box when * a connection is made. * *\***************************************************************************/ void AcceptThreadProc( PTHREADPACK ptp ) { SOCKADDR_IN acc_sin; /* Accept socket address - internet style */ int acc_sin_len; /* Accept socket address length */ int status; char szMsg[ MY_MSG_LENGTH ]; acc_sin_len = sizeof(acc_sin); wsprintf( szBuff, "thread #%d created.", ptp->nThread); MessageBox(ptp->hWnd, szBuff, "FYI", MB_OK); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(ptp->hWnd, szBuff, "accept(sock) failed", MB_OK); } wsprintf( szBuff, "Thread #%d accepted something\n\nCheck for incoming messages?", ptp->nThread); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( ptp->hWnd ); while (1) { /* * By default sockets are created in blocking mode. * Just keep reading until process destroyed. */ status = recv( sock, szMsg, MY_MSG_LENGTH, NO_FLAGS_SET ); if (status == SOCKET_ERROR) { wsprintf( szMsg, "Error %d", WSAGetLastError() ); MessageBox( ptp->hWnd, szMsg, "Error with recv()", MB_OK); _endthread(); } szMsg[status] = '\0'; /* NULL-terminate the string */ if (status) MessageBox( ptp->hWnd, szMsg, "From thread", MB_OK); else { MessageBox( ptp->hWnd, "Connection broken", "Error", MB_OK); _endthread(); } } /* while (forever) */ } /****************************************************************************\ * * FUNCTION: FillAddr(HWND, PSOCKADDR_IN, BOOL) * * PURPOSE: Retrieves the IP address and port number. * * COMMENTS: * This function is called in two conditions. * 1.) When a client is preparing to call connect(), or * 2.) When a server host is going to call bind(), listen() and * accept(). * In both situations, a SOCKADDR_IN structure is filled. * However, different fields are filled depending on the condition. * * ASSUMPTION: * szBuff is a global variable that contains the remote host name or NULL * if local. * bClient determines if this is being called by a client ( will be * performing a connect ) or a server ( will be listening ) * * *\***************************************************************************/ BOOL FillAddr( HWND hWnd, PSOCKADDR_IN psin, BOOL bClient) { DWORD dwSize; PHOSTENT phe; PSERVENT pse; char szTemp[200]; int status; psin->sin_family = AF_INET; /* * If we are setting up for a listen() call (bConnect = FALSE), * fill servent with our address. */ if (bClient) { phe = gethostbyname(szBuff); if (phe == NULL) { sprintf(szTemp, "%d is the error. Make sure '%s' is listed in the hosts file.", WSAGetLastError(), szBuff); MessageBox(hWnd, szTemp, "gethostbyname() failed.", MB_OK); return FALSE; } memcpy((char FAR *)&(psin->sin_addr), phe->h_addr, phe->h_length); } else { // server /* * Retrieve my ip address. Assuming the hosts file in * in %systemroot%/system/drivers/etc/hosts contains my computer name. */ dwSize = sizeof(szBuff); gethostname(szBuff, dwSize); psin->sin_addr.s_addr = INADDR_ANY; } /* * Retrieve the Port number */ status = DialogBox(hInst, /* current instance */ "TCPPORTNUM", /* resource to use */ hWnd, /* parent handle */ GetTcpPort); /* instance address */ switch(status) { case 0: /* User cancelled request from prev. dialog box */ return FALSE; case 1: /* actual port number entered */ psin->sin_port = htons(portno); /* Convert to network ordering */ break; case 2: /* service name entereted */ /* * Find the service name, szBuff, which is a type tcp protocol in * the "services" file. */ pse = getservbyname(szBuff, "tcp"); if (pse == NULL) { sprintf(szBuff, "%d is the error. Make sure this is a valid TCP service.", WSAGetLastError()); MessageBox(hWnd, szBuff, "getservbyname(sock) failed", MB_OK); return FALSE; } psin->sin_port = pse->s_port; break; default: return FALSE; } return TRUE; } /**************************************************************************** * * FUNCTION: SetConnectMenus( HWND ) * * PURPOSE: Gray/Enable the proper menu items after a connection has been * established. * *\***************************************************************************/ void SetConnectMenus( HWND hWnd ) { /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED ); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_ENABLED ); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED ); /* * Reflect socket connection in title bar. */ SetWindowText( hWnd, "Connected"); } /****************************************************************************\ * * FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) * * PURPOSE: Processes main window messages * * MESSAGES: * WM_CREATE - call WSAStartUp() and display description message * WSA_ACCEPT - User-defined message used with WSAAsyncSelect(). Sent * by the Windows Sockets DLL when a socket connection is * pending. * * WM_COMMAND * IDM_CONNECT - Connect to a remote host. * IDM_LISTEN - Use the BSD-Style accept(). * IDM_ALISTEN - Use the Windows Sockets Asynchronous APIs to detect when * a connection is made. * IDM_CANCEL - Cancel the Asynchronous call above. * IDM_TLISTEN - Uses two threads to accept network connections (using the * BSD-Style accept(). * IDM_HOSTNAME- Display information about a host. * IDM_ABOUT - About box. * * WM_DESTROY - destroy window and call the WSACleanUp() * *\***************************************************************************/ LONG APIENTRY MainWndProc( HWND hWnd, /* window handle */ UINT message, /* type of message */ UINT wParam, /* additional information */ LONG lParam) /* additional information */ { int status; /* Status Code */ SOCKADDR_IN local_sin; /* Local socket - internet style */ SOCKADDR_IN acc_sin; /* Accept socket address - internet style */ int acc_sin_len; /* Accept socket address length */ switch (message) { case WM_CREATE: { WSADATA WSAData; char szTemp[80]; if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0) { MessageBox( hWnd, WSAData.szDescription, WSAData.szSystemStatus, MB_OK); } else { sprintf(szTemp, "%d is the err", status); MessageBox( hWnd, szTemp, "Error", MB_OK); } } break; /* WM_CREATE */ /* * Notification if data is waiting on a socket. This comes * from Windows Sockets (via WSAAsyncSelect()). */ case WSA_READ: { char szTemp[ MY_MSG_LENGTH ]; if (WSAGETSELECTEVENT(lParam) == FD_READ) { status = recv((SOCKET)wParam, szTemp, MY_MSG_LENGTH, NO_FLAGS_SET ); if (status) { szTemp[ status ] = '\0'; MessageBox( hWnd, szTemp, "WSA_READ", MB_OK); } else MessageBox( hWnd, "Connection broken", "Error", MB_OK); } else { /* FD_CLOSE -- connection dropped */ MessageBox( hWnd, "Connection lost", "WSA_READ", MB_OK); EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); } } break; /* WSA_READ*/ case WSA_ACCEPT: /* Notification if a socket connection is pending. */ /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); if (WSAGETSELECTERROR( lParam ) == 0) { /* Success */ /* * Accept the incoming connection. */ acc_sin_len = sizeof( acc_sin ); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK); break; } MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)", status, status); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } else { MessageBox(hWnd, "accept()", "Error occured!", MB_OK); /* * Cancel any further notifications. */ WSAAsyncSelect( sock, hWnd, 0, 0); SetWindowText( hWnd, "Async Listen call canceled"); } break; /* WSA_ACCEPT */ case WM_COMMAND: /* message: command from application menu */ switch(LOWORD(wParam)) { case IDM_CONNECT: /* Client - connect to remote host */ { /* When a network client wants to connect to a server, it must have: 1.) a TCP port number (gotten via getservbyname()) and 2.) an IP address of the remote host (gotten via gethostbyname()). The following summarizes the steps used to connect. Make a dialog box (HostName) Get the name of the remote host computer in which to connect from the user (store string in "szBuff" global var) * Check to see if the hosts file knows the computer (gethostbyname) * Get the host information (hostent structure filled) * Fill in the address of the remote host into the servent structure (memcpy) * Make a dialog box (TCPPORTNUM) * Get the NAME of the port to connect to on the remote host from the user. * Get the port number (getservbyname) * Fill in the port number of the servent structure Establish a connection (connect) The * prefixed steps are done in the FillAddr() procedure. */ SOCKADDR_IN dest_sin; /* DESTination Socket INternet */ /* Get the name of the remote host. Store the string in szBuff. */ status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (!status) /* User cancelled request from prev. dialog box */ break; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } /* * Retrieve the IP address and TCP Port number * Global variable szBuff contains the remote host name. */ if (!FillAddr( hWnd, &dest_sin, TRUE)) { closesocket( sock ); break; } if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) { closesocket( sock ); MessageBox(hWnd, "connect() failed", "Error", MB_OK); break; } MessageBox(hWnd, "connect() worked!", "Success!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_CONNECT */ case IDM_CONNECTANDSEND: { // // // In order to simulate a more typical real-world client, here // we make the connection, and then immediately send it data. // // See IDM_CONNECT above for full comments. SOCKADDR_IN dest_sin; status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (!status) break; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } if (!FillAddr( hWnd, &dest_sin, TRUE)) { closesocket( sock ); break; } if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) { MessageBox(hWnd, "connect() failed", "Error", MB_OK); closesocket( sock ); break; } if (send (sock, gpszHelloWorld, lstrlen (gpszHelloWorld), 0 ) == SOCKET_ERROR) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error on send()", MB_OK); closesocket( sock ); break; } MessageBox(hWnd, "connect() & send() worked!", "Success!", MB_OK); SetConnectMenus( hWnd ); if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; // IDM_CONNECTANDSEND case IDM_ACCEPTEX: { // // Demonstrate the use of AcceptEx(). // #define MAX_BYTES 2000 #define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 SOCKET sListenSocket; SOCKET sAcceptSocket; char pData [MAX_BYTES]; OVERLAPPED olResult; DWORD dwBytes; // // For this API, we need to create two sockets ahead of time. // The listen socket goes through the standard bind/listen steps. // sListenSocket = socket( AF_INET, SOCK_STREAM, 0); sAcceptSocket = socket( AF_INET, SOCK_STREAM, 0); if ((sListenSocket == INVALID_SOCKET) || (sAcceptSocket == INVALID_SOCKET)) { MessageBox(hWnd, "sock == INVALID_SOCKET", "socket() failed", MB_OK); closesocket(sListenSocket); closesocket(sAcceptSocket); break; } // // Retrieve the IP address and TCP Port number // if (!FillAddr(hWnd, &local_sin, FALSE )) break; // // Associate an address with the socket // if (bind( sListenSocket, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } // // And go into the listening state. // if (listen( sListenSocket, MAX_PENDING_CONNECTS ) < 0) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } // // Disable/enable proper menu items. // EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "AcceptEx.."); // // Create an event for our overlapped structure (required). // memset (&olResult, 0, sizeof(olResult)); olResult.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); dwBytes = 0; // // AcceptEx makes the most sense when used with I/O // CompletionPorts and TransmitFile. // We show a very basic usage here... // if (AcceptEx( sListenSocket, sAcceptSocket, pData, MAX_BYTES - 2*PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, &dwBytes, &olResult) == FALSE) { if (WSAGetLastError() != ERROR_IO_PENDING) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error on AcceptEx()", MB_OK); break; } else { // // In our contrived scenario, we expect GetLastError to be // ERROR_IO_PENDING. A real app would do other work. // Since this is a simple sample, we will just block waiting // for some input to come through the socket. // GetOverlappedResult ( (HANDLE) sAcceptSocket, &olResult, &dwBytes, TRUE); pData[dwBytes] = 0; MessageBox(hWnd, pData, "AcceptEx received data", MB_OK); } } // // As per the documentation, poke the new socket so that it will have // the correct properties and can be used by other functions. // if (setsockopt( sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&sListenSocket, sizeof(sListenSocket) )) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error in setsockopt()", MB_OK); break; } else { // // sAcceptSocket is now OK for use by other functions. // set it into our global socket (sock) // sock = sAcceptSocket; } // // In any case, we are done with our listen socket // closesocket( sListenSocket ); // // Now have a connection -- // SetConnectMenus() grays/enables proper menu items SetConnectMenus( hWnd ); // // Send main window a WSA_READ when either data is pending on // the socket (FD_READ) or the connection is closed (FD_CLOSE) if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_ACCEPTEX */ case IDM_LISTEN: { sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); closesocket(sock); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr(hWnd, &local_sin, FALSE )) break; /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.."); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } acc_sin_len = sizeof(acc_sin); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK); break; } MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_LISTEN */ /* * Asynchronous Listen - Using WSA extensions. */ case IDM_ALISTEN: { sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr( hWnd, &local_sin, FALSE)) { closesocket( sock ); break; } /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.. (Async)"); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); closesocket( sock ); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } /* * Send window a WSA_ACCEPT when something is trying to connect. */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_ACCEPT, FD_ACCEPT)) > 0) { wsprintf( szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); SetWindowText( hWnd, "Async listen cancelled"); closesocket( sock ); } } break; /* IDM_ALISTEN */ /* * Cancel an asynchronous call. */ case IDM_CANCEL: WSAAsyncSelect( sock, hWnd, 0, 0); SetWindowText( hWnd, "Async Listen cancelled.."); /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_ENABLED); break; /* IDM_CANCEL */ /* * Listen in the main thread -- spawn and accept two network * connections inside two threads. */ case IDM_TLISTEN: { static THREADPACK tp; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); closesocket(sock); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr(hWnd, &local_sin, FALSE )) break; /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.."); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } tp.nThread = 0; tp.hWnd = hWnd; _beginthread(AcceptThreadProc, 0, &tp); } break; /* IDM_TLISTEN */ /* * Display host information. */ case IDM_HOSTNAME: /* * Prompt the user and retrieve the text name of the host. */ status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (status == TRUE) { /* If user hit "OK" .. */ /* * Get the host information */ if ((phe = gethostbyname( szBuff )) == NULL) { MessageBox(hWnd, "gethostbyname() failed", "Error", MB_OK); break; } else { /* * Display the host information .. */ DialogBox(hInst, "DISPLAYHOST", hWnd, DisplayHostEnt); } } break; /* IDM_HOSTNAME */ /* * Send a message to (via TCP connection) to remote host. */ case IDM_SENDTCP: DialogBox(hInst, /* current instance */ "GetString", /* resource to use */ hWnd, /* parent handle */ GetSendString); /* instance address */ /* * Assumption -- The GetString dialog box proc fills the global * string buffer, szBuff, with the desired string to send. */ send(sock, szBuff, strlen(szBuff), NO_FLAGS_SET ); break; /* IDM_SENDTCP */ case IDM_ABOUT: DialogBox(hInst, /* current instance */ "AboutBox", /* resource to use */ hWnd, /* parent handle */ About); /* About() instance address */ break; /* IDM_ABOUT */ default: /* Lets Windows process it */ return (DefWindowProc(hWnd, message, wParam, lParam)); break; } break; /* * Clean up. Takes care of any open socket descriptors. */ case WM_DESTROY: WSACleanup(); PostQuitMessage(0); break; default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); }
#include <stdafx.h> #include "utility.h" #define MAXBUF 50000HWND g_hMainWnd = 0; char g_pchStatus[25] = ""; CCriticalSection g_csStatus;UINT ClientWinInetThreadProc(LPVOID pParam) { CCallbackInternetSession session; CHttpConnection* pConnection = NULL; CHttpFile* pFile1 = NULL; char* buffer = new char[MAXBUF]; UINT nBytesRead = 0; DWORD dwStatus; try { // username/password doesn't work yet if(!g_strServerName.IsEmpty()) { pConnection = session.GetHttpConnection(g_strServerName, (INTERNET_PORT) g_nPort); } else { pConnection = session.GetHttpConnection(g_strServerIP, (INTERNET_PORT) g_nPort); } pFile1 = pConnection->OpenRequest(1, g_strFile, NULL, 1, NULL, NULL, // GET request INTERNET_FLAG_KEEP_CONNECTION); // needed for NT Challenge/Response authentication // INTERNET_FLAG_RELOAD forces reload from the server (bypasses client's cache) pFile1->SendRequest(); pFile1->QueryInfoStatusCode(dwStatus); TRACE("QueryInfoStatusCode = %d\n", dwStatus); nBytesRead = pFile1->Read(buffer, MAXBUF - 1); buffer[nBytesRead] = '\0'; // necessary for message box char temp[100]; if(pFile1->Read(temp, 100) != 0) { // makes caching work if read complete AfxMessageBox("File overran buffer -- not cached"); } ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "WININET CLIENT", MB_OK); // could use existing pFile1 to SendRequest again if we wanted to } catch(CInternetException* e) { LogInternetException(pParam, e); e->Delete(); } // could call OpenRequest again on same connection if we wanted to if(pFile1) delete pFile1; // does the close -- prints a warning if(pConnection) delete pConnection; // why does it print a warning? delete [] buffer; g_csStatus.Lock(); strcpy(g_pchStatus, ""); // problem with empty string. bug #9897 g_csStatus.Unlock(); return 0; }
我知道MSDN里微软有一个聊天室的例子,但太复杂了,看起来费劲!最好有个短小但能说明问题的例子,我的地址是:[email protected],谢谢!
[email protected]
用createthread就可以了
amir(萧大将军)英雄所见略同
//----------------------------------------------------------------------------- // This is a part of the Microsoft Source Code Samples. // Copyright 1993 - 1998 Microsoft Corporation. // All rights reserved. // // This source code is only intended as a supplement to // Microsoft Development Tools and/or WinHelp documentation. // See these sources for detailed information regarding the // Microsoft samples programs. //----------------------------------------------------------------------------- /****************************************************************************\ * wsock.c -- sample program demonstrating Windows Sockets APIs. * * Demonstrates basic sockets programming with the Windows Sockets API. * Allows two occurances of the application to connect. Also, displays * information about a host computer. * ****************************************************************************/ #include <windows.h> /* required for all Windows applications */ #include <stdio.h> /* for sprintf */ #include <string.h> /* for strlen */ #include <memory.h> #include <process.h> /* for _beginthread */ #include "wsock.h" /* specific to this program */ HANDLE hInst; /* current instance */ SOCKET sock; u_short portno; /* Which tcp port are we going to use? */ char szBuff[ 80 ]; /* Temp buffer - used to pass strings */ /* to and from dialog boxes, etc */ char gpszHelloWorld[]= "Hello World."; #define MAX_PENDING_CONNECTS 4 /* The backlog allowed for listen() */ #define NO_FLAGS_SET 0 /* Used with recv()/send() */ #define MY_MSG_LENGTH 80 /* msg buffer sent back and forth */ /**************************************************************************** * * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) * * PURPOSE: calls initialization function, processes message loop * *\***************************************************************************/ WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; UNREFERENCED_PARAMETER( lpCmdLine ); if (!hPrevInstance) /* Other instances of app running? */ if (!InitApplication(hInstance)) /* Initialize shared things */ return (FALSE); /* Exits if unable to initialize */ /* * Perform initializations that apply to a specific instance */ if (!InitInstance(hInstance, nCmdShow)) return (FALSE); /* * Acquire and dispatch messages until a WM_QUIT message is received. */ while (GetMessage(&msg, /* message structure */ NULL, /* handle of window receiving the message */ 0, /* lowest message to examine */ 0)) /* highest message to examine */ { TranslateMessage(&msg); /* Translates virtual key codes */ DispatchMessage(&msg); /* Dispatches message to window */ } return (msg.wParam); /* Returns the value from PostQuitMessage */ } /**************************************************************************** * * FUNCTION: InitApplication(HANDLE) * * PURPOSE: Initializes window data and registers window class * *\***************************************************************************/ BOOL InitApplication(HANDLE hInstance) /* current instance */ { WNDCLASS wc; /* Fill in window class structure with parameters that describe the */ /* main window. */ wc.style = 0; /* Class style(s). */ wc.lpfnWndProc = (WNDPROC)MainWndProc; /* Function to retrieve messages for */ /* windows of this class. */ wc.cbClsExtra = 0; /* No per-class extra data. */ wc.cbWndExtra = 0; /* No per-window extra data. */ wc.hIcon = LoadIcon (hInstance, "wsockicon"); /* Icon name from .RC */ wc.hInstance = hInstance; /* Application that owns the class. */ wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "WSockMenu"; /* Name of menu resource in .RC file. */ wc.lpszClassName = "WSockWClass"; /* Name used in call to CreateWindow. */ /* Register the window class and return success/failure code. */ return (RegisterClass(&wc)); } /****************************************************************************\ * * FUNCTION: InitInstance(HANDLE, int) * * PURPOSE: Saves instance handle and creates main window * *\***************************************************************************/ BOOL InitInstance( HANDLE hInstance, /* Current instance identifier. */ int nCmdShow) /* Param for first ShowWindow() call. */ { HWND hWnd; /* Main window handle. */ /* Save the instance handle in static variable, which will be used in */ /* many subsequence calls from this application to Windows. */ hInst = hInstance; /* Create a main window for this application instance. */ hWnd = CreateWindow( "WSockWClass", /* See RegisterClass() call. */ "Windows Sockets Sample Application", /* Text for window title bar. */ WS_OVERLAPPEDWINDOW, /* Window style. */ CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default vertical position. */ CW_USEDEFAULT, /* Default width. */ CW_USEDEFAULT, /* Default height. */ NULL, /* Overlapped windows have no parent. */ NULL, /* Use the window class menu. */ hInstance, /* This instance owns this window. */ NULL /* Pointer not needed. */ ); /* If window could not be created, return "failure" */ if (!hWnd) return (FALSE); /* Make the window visible; update its client area; and return "success" */ ShowWindow(hWnd, nCmdShow); /* Show the window */ UpdateWindow(hWnd); /* Sends WM_PAINT message */ return (TRUE); /* Returns the value from PostQuitMessage */ } /****************************************************************************\ * * FUNCTION: AcceptThreadProc(PTHREADPACK tp) * * PURPOSE: Use blocking accept() calls and display a message box when * a connection is made. * *\***************************************************************************/ void AcceptThreadProc( PTHREADPACK ptp ) { SOCKADDR_IN acc_sin; /* Accept socket address - internet style */ int acc_sin_len; /* Accept socket address length */ int status; char szMsg[ MY_MSG_LENGTH ]; acc_sin_len = sizeof(acc_sin); wsprintf( szBuff, "thread #%d created.", ptp->nThread); MessageBox(ptp->hWnd, szBuff, "FYI", MB_OK); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(ptp->hWnd, szBuff, "accept(sock) failed", MB_OK); } wsprintf( szBuff, "Thread #%d accepted something\n\nCheck for incoming messages?", ptp->nThread); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( ptp->hWnd ); while (1) { /* * By default sockets are created in blocking mode. * Just keep reading until process destroyed. */ status = recv( sock, szMsg, MY_MSG_LENGTH, NO_FLAGS_SET ); if (status == SOCKET_ERROR) { wsprintf( szMsg, "Error %d", WSAGetLastError() ); MessageBox( ptp->hWnd, szMsg, "Error with recv()", MB_OK); _endthread(); } szMsg[status] = '\0'; /* NULL-terminate the string */ if (status) MessageBox( ptp->hWnd, szMsg, "From thread", MB_OK); else { MessageBox( ptp->hWnd, "Connection broken", "Error", MB_OK); _endthread(); } } /* while (forever) */ } /****************************************************************************\ * * FUNCTION: FillAddr(HWND, PSOCKADDR_IN, BOOL) * * PURPOSE: Retrieves the IP address and port number. * * COMMENTS: * This function is called in two conditions. * 1.) When a client is preparing to call connect(), or * 2.) When a server host is going to call bind(), listen() and * accept(). * In both situations, a SOCKADDR_IN structure is filled. * However, different fields are filled depending on the condition. * * ASSUMPTION: * szBuff is a global variable that contains the remote host name or NULL * if local. * bClient determines if this is being called by a client ( will be * performing a connect ) or a server ( will be listening ) * * *\***************************************************************************/ BOOL FillAddr( HWND hWnd, PSOCKADDR_IN psin, BOOL bClient) { DWORD dwSize; PHOSTENT phe; PSERVENT pse; char szTemp[200]; int status; psin->sin_family = AF_INET; /* * If we are setting up for a listen() call (bConnect = FALSE), * fill servent with our address. */ if (bClient) { phe = gethostbyname(szBuff); if (phe == NULL) { sprintf(szTemp, "%d is the error. Make sure '%s' is listed in the hosts file.", WSAGetLastError(), szBuff); MessageBox(hWnd, szTemp, "gethostbyname() failed.", MB_OK); return FALSE; } memcpy((char FAR *)&(psin->sin_addr), phe->h_addr, phe->h_length); } else { // server /* * Retrieve my ip address. Assuming the hosts file in * in %systemroot%/system/drivers/etc/hosts contains my computer name. */ dwSize = sizeof(szBuff); gethostname(szBuff, dwSize); psin->sin_addr.s_addr = INADDR_ANY; } /* * Retrieve the Port number */ status = DialogBox(hInst, /* current instance */ "TCPPORTNUM", /* resource to use */ hWnd, /* parent handle */ GetTcpPort); /* instance address */ switch(status) { case 0: /* User cancelled request from prev. dialog box */ return FALSE; case 1: /* actual port number entered */ psin->sin_port = htons(portno); /* Convert to network ordering */ break; case 2: /* service name entereted */ /* * Find the service name, szBuff, which is a type tcp protocol in * the "services" file. */ pse = getservbyname(szBuff, "tcp"); if (pse == NULL) { sprintf(szBuff, "%d is the error. Make sure this is a valid TCP service.", WSAGetLastError()); MessageBox(hWnd, szBuff, "getservbyname(sock) failed", MB_OK); return FALSE; } psin->sin_port = pse->s_port; break; default: return FALSE; } return TRUE; } /**************************************************************************** * * FUNCTION: SetConnectMenus( HWND ) * * PURPOSE: Gray/Enable the proper menu items after a connection has been * established. * *\***************************************************************************/ void SetConnectMenus( HWND hWnd ) { /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED ); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_ENABLED ); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED ); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED ); /* * Reflect socket connection in title bar. */ SetWindowText( hWnd, "Connected"); } /****************************************************************************\ * * FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) * * PURPOSE: Processes main window messages * * MESSAGES: * WM_CREATE - call WSAStartUp() and display description message * WSA_ACCEPT - User-defined message used with WSAAsyncSelect(). Sent * by the Windows Sockets DLL when a socket connection is * pending. * * WM_COMMAND * IDM_CONNECT - Connect to a remote host. * IDM_LISTEN - Use the BSD-Style accept(). * IDM_ALISTEN - Use the Windows Sockets Asynchronous APIs to detect when * a connection is made. * IDM_CANCEL - Cancel the Asynchronous call above. * IDM_TLISTEN - Uses two threads to accept network connections (using the * BSD-Style accept(). * IDM_HOSTNAME- Display information about a host. * IDM_ABOUT - About box. * * WM_DESTROY - destroy window and call the WSACleanUp() * *\***************************************************************************/ LONG APIENTRY MainWndProc( HWND hWnd, /* window handle */ UINT message, /* type of message */ UINT wParam, /* additional information */ LONG lParam) /* additional information */ { int status; /* Status Code */ SOCKADDR_IN local_sin; /* Local socket - internet style */ SOCKADDR_IN acc_sin; /* Accept socket address - internet style */ int acc_sin_len; /* Accept socket address length */ switch (message) { case WM_CREATE: { WSADATA WSAData; char szTemp[80]; if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0) { MessageBox( hWnd, WSAData.szDescription, WSAData.szSystemStatus, MB_OK); } else { sprintf(szTemp, "%d is the err", status); MessageBox( hWnd, szTemp, "Error", MB_OK); } } break; /* WM_CREATE */ /* * Notification if data is waiting on a socket. This comes * from Windows Sockets (via WSAAsyncSelect()). */ case WSA_READ: { char szTemp[ MY_MSG_LENGTH ]; if (WSAGETSELECTEVENT(lParam) == FD_READ) { status = recv((SOCKET)wParam, szTemp, MY_MSG_LENGTH, NO_FLAGS_SET ); if (status) { szTemp[ status ] = '\0'; MessageBox( hWnd, szTemp, "WSA_READ", MB_OK); } else MessageBox( hWnd, "Connection broken", "Error", MB_OK); } else { /* FD_CLOSE -- connection dropped */ MessageBox( hWnd, "Connection lost", "WSA_READ", MB_OK); EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); } } break; /* WSA_READ*/ case WSA_ACCEPT: /* Notification if a socket connection is pending. */ /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); if (WSAGETSELECTERROR( lParam ) == 0) { /* Success */ /* * Accept the incoming connection. */ acc_sin_len = sizeof( acc_sin ); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK); break; } MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)", status, status); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } else { MessageBox(hWnd, "accept()", "Error occured!", MB_OK); /* * Cancel any further notifications. */ WSAAsyncSelect( sock, hWnd, 0, 0); SetWindowText( hWnd, "Async Listen call canceled"); } break; /* WSA_ACCEPT */ case WM_COMMAND: /* message: command from application menu */ switch(LOWORD(wParam)) { case IDM_CONNECT: /* Client - connect to remote host */ { /* When a network client wants to connect to a server, it must have: 1.) a TCP port number (gotten via getservbyname()) and 2.) an IP address of the remote host (gotten via gethostbyname()). The following summarizes the steps used to connect. Make a dialog box (HostName) Get the name of the remote host computer in which to connect from the user (store string in "szBuff" global var) * Check to see if the hosts file knows the computer (gethostbyname) * Get the host information (hostent structure filled) * Fill in the address of the remote host into the servent structure (memcpy) * Make a dialog box (TCPPORTNUM) * Get the NAME of the port to connect to on the remote host from the user. * Get the port number (getservbyname) * Fill in the port number of the servent structure Establish a connection (connect) The * prefixed steps are done in the FillAddr() procedure. */ SOCKADDR_IN dest_sin; /* DESTination Socket INternet */ /* Get the name of the remote host. Store the string in szBuff. */ status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (!status) /* User cancelled request from prev. dialog box */ break; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } /* * Retrieve the IP address and TCP Port number * Global variable szBuff contains the remote host name. */ if (!FillAddr( hWnd, &dest_sin, TRUE)) { closesocket( sock ); break; } if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) { closesocket( sock ); MessageBox(hWnd, "connect() failed", "Error", MB_OK); break; } MessageBox(hWnd, "connect() worked!", "Success!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_CONNECT */ case IDM_CONNECTANDSEND: { // // // In order to simulate a more typical real-world client, here // we make the connection, and then immediately send it data. // // See IDM_CONNECT above for full comments. SOCKADDR_IN dest_sin; status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (!status) break; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } if (!FillAddr( hWnd, &dest_sin, TRUE)) { closesocket( sock ); break; } if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) { MessageBox(hWnd, "connect() failed", "Error", MB_OK); closesocket( sock ); break; } if (send (sock, gpszHelloWorld, lstrlen (gpszHelloWorld), 0 ) == SOCKET_ERROR) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error on send()", MB_OK); closesocket( sock ); break; } MessageBox(hWnd, "connect() & send() worked!", "Success!", MB_OK); SetConnectMenus( hWnd ); if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; // IDM_CONNECTANDSEND case IDM_ACCEPTEX: { // // Demonstrate the use of AcceptEx(). // #define MAX_BYTES 2000 #define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 SOCKET sListenSocket; SOCKET sAcceptSocket; char pData [MAX_BYTES]; OVERLAPPED olResult; DWORD dwBytes; // // For this API, we need to create two sockets ahead of time. // The listen socket goes through the standard bind/listen steps. // sListenSocket = socket( AF_INET, SOCK_STREAM, 0); sAcceptSocket = socket( AF_INET, SOCK_STREAM, 0); if ((sListenSocket == INVALID_SOCKET) || (sAcceptSocket == INVALID_SOCKET)) { MessageBox(hWnd, "sock == INVALID_SOCKET", "socket() failed", MB_OK); closesocket(sListenSocket); closesocket(sAcceptSocket); break; } // // Retrieve the IP address and TCP Port number // if (!FillAddr(hWnd, &local_sin, FALSE )) break; // // Associate an address with the socket // if (bind( sListenSocket, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } // // And go into the listening state. // if (listen( sListenSocket, MAX_PENDING_CONNECTS ) < 0) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } // // Disable/enable proper menu items. // EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "AcceptEx.."); // // Create an event for our overlapped structure (required). // memset (&olResult, 0, sizeof(olResult)); olResult.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); dwBytes = 0; // // AcceptEx makes the most sense when used with I/O // CompletionPorts and TransmitFile. // We show a very basic usage here... // if (AcceptEx( sListenSocket, sAcceptSocket, pData, MAX_BYTES - 2*PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, &dwBytes, &olResult) == FALSE) { if (WSAGetLastError() != ERROR_IO_PENDING) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error on AcceptEx()", MB_OK); break; } else { // // In our contrived scenario, we expect GetLastError to be // ERROR_IO_PENDING. A real app would do other work. // Since this is a simple sample, we will just block waiting // for some input to come through the socket. // GetOverlappedResult ( (HANDLE) sAcceptSocket, &olResult, &dwBytes, TRUE); pData[dwBytes] = 0; MessageBox(hWnd, pData, "AcceptEx received data", MB_OK); } } // // As per the documentation, poke the new socket so that it will have // the correct properties and can be used by other functions. // if (setsockopt( sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&sListenSocket, sizeof(sListenSocket) )) { wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError()); MessageBox( hWnd, szBuff, "Error in setsockopt()", MB_OK); break; } else { // // sAcceptSocket is now OK for use by other functions. // set it into our global socket (sock) // sock = sAcceptSocket; } // // In any case, we are done with our listen socket // closesocket( sListenSocket ); // // Now have a connection -- // SetConnectMenus() grays/enables proper menu items SetConnectMenus( hWnd ); // // Send main window a WSA_READ when either data is pending on // the socket (FD_READ) or the connection is closed (FD_CLOSE) if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_ACCEPTEX */ case IDM_LISTEN: { sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); closesocket(sock); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr(hWnd, &local_sin, FALSE )) break; /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.."); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } acc_sin_len = sizeof(acc_sin); sock = accept( sock,(struct sockaddr FAR *) &acc_sin, (int FAR *) &acc_sin_len ); if (sock < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK); break; } MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK); /* * Now have a connection -- * SetConnectMenus() grays/enables proper menu items */ SetConnectMenus( hWnd ); /* * Send main window a WSA_READ when either data is pending on * the socket (FD_READ) or the connection is closed (FD_CLOSE) */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) { wsprintf(szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); closesocket( sock ); } } break; /* IDM_LISTEN */ /* * Asynchronous Listen - Using WSA extensions. */ case IDM_ALISTEN: { sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr( hWnd, &local_sin, FALSE)) { closesocket( sock ); break; } /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.. (Async)"); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); closesocket( sock ); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } /* * Send window a WSA_ACCEPT when something is trying to connect. */ if ((status = WSAAsyncSelect( sock, hWnd, WSA_ACCEPT, FD_ACCEPT)) > 0) { wsprintf( szBuff, "%d (0x%x)"); MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK); SetWindowText( hWnd, "Async listen cancelled"); closesocket( sock ); } } break; /* IDM_ALISTEN */ /* * Cancel an asynchronous call. */ case IDM_CANCEL: WSAAsyncSelect( sock, hWnd, 0, 0); SetWindowText( hWnd, "Async Listen cancelled.."); /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_ENABLED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_ENABLED); break; /* IDM_CANCEL */ /* * Listen in the main thread -- spawn and accept two network * connections inside two threads. */ case IDM_TLISTEN: { static THREADPACK tp; sock = socket( AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(hWnd, "socket() failed", "Error", MB_OK); closesocket(sock); break; } /* * Retrieve the IP address and TCP Port number */ if (!FillAddr(hWnd, &local_sin, FALSE )) break; /* * Disable/enable proper menu items. */ EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED); EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED); SetWindowText( hWnd, "Waiting for connection.."); /* * Associate an address with a socket. (bind) */ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK); break; } if (listen( sock, MAX_PENDING_CONNECTS ) < 0) { sprintf(szBuff, "%d is the error", WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK); break; } tp.nThread = 0; tp.hWnd = hWnd; _beginthread(AcceptThreadProc, 0, &tp); } break; /* IDM_TLISTEN */ /* * Display host information. */ case IDM_HOSTNAME: /* * Prompt the user and retrieve the text name of the host. */ status = DialogBox(hInst, "HOSTNAME", hWnd, GetHostName); if (status == TRUE) { /* If user hit "OK" .. */ /* * Get the host information */ if ((phe = gethostbyname( szBuff )) == NULL) { MessageBox(hWnd, "gethostbyname() failed", "Error", MB_OK); break; } else { /* * Display the host information .. */ DialogBox(hInst, "DISPLAYHOST", hWnd, DisplayHostEnt); } } break; /* IDM_HOSTNAME */ /* * Send a message to (via TCP connection) to remote host. */ case IDM_SENDTCP: DialogBox(hInst, /* current instance */ "GetString", /* resource to use */ hWnd, /* parent handle */ GetSendString); /* instance address */ /* * Assumption -- The GetString dialog box proc fills the global * string buffer, szBuff, with the desired string to send. */ send(sock, szBuff, strlen(szBuff), NO_FLAGS_SET ); break; /* IDM_SENDTCP */ case IDM_ABOUT: DialogBox(hInst, /* current instance */ "AboutBox", /* resource to use */ hWnd, /* parent handle */ About); /* About() instance address */ break; /* IDM_ABOUT */ default: /* Lets Windows process it */ return (DefWindowProc(hWnd, message, wParam, lParam)); break; } break; /* * Clean up. Takes care of any open socket descriptors. */ case WM_DESTROY: WSACleanup(); PostQuitMessage(0); break; default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); }
#include "utility.h"
#define MAXBUF 50000HWND g_hMainWnd = 0;
char g_pchStatus[25] = "";
CCriticalSection g_csStatus;UINT ClientWinInetThreadProc(LPVOID pParam)
{
CCallbackInternetSession session;
CHttpConnection* pConnection = NULL;
CHttpFile* pFile1 = NULL;
char* buffer = new char[MAXBUF];
UINT nBytesRead = 0;
DWORD dwStatus;
try {
// username/password doesn't work yet
if(!g_strServerName.IsEmpty()) {
pConnection = session.GetHttpConnection(g_strServerName,
(INTERNET_PORT) g_nPort);
}
else {
pConnection = session.GetHttpConnection(g_strServerIP,
(INTERNET_PORT) g_nPort);
}
pFile1 = pConnection->OpenRequest(1, g_strFile, NULL, 1, NULL, NULL, // GET request
INTERNET_FLAG_KEEP_CONNECTION); // needed for NT Challenge/Response authentication
// INTERNET_FLAG_RELOAD forces reload from the server (bypasses client's cache)
pFile1->SendRequest();
pFile1->QueryInfoStatusCode(dwStatus);
TRACE("QueryInfoStatusCode = %d\n", dwStatus);
nBytesRead = pFile1->Read(buffer, MAXBUF - 1);
buffer[nBytesRead] = '\0'; // necessary for message box
char temp[100];
if(pFile1->Read(temp, 100) != 0) { // makes caching work if read complete
AfxMessageBox("File overran buffer -- not cached");
}
::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "WININET CLIENT", MB_OK);
// could use existing pFile1 to SendRequest again if we wanted to
}
catch(CInternetException* e) {
LogInternetException(pParam, e);
e->Delete();
}
// could call OpenRequest again on same connection if we wanted to
if(pFile1) delete pFile1; // does the close -- prints a warning
if(pConnection) delete pConnection; // why does it print a warning?
delete [] buffer;
g_csStatus.Lock();
strcpy(g_pchStatus, ""); // problem with empty string. bug #9897
g_csStatus.Unlock();
return 0;
}