Knowledge Base Nr: 00249  socketserver_berk.cpp - http://www.swe-kaiser.de
Downloads: 
Win32: WinCE: Implementierung HTTP Server (Socket Server)
  
//hWnd != NULL gibt im fehlerfall messagebox aus
class CWinCESupport
{
...
    static int StartServer(HWND hWnd, int nPortNo, int nTimeOutMs, CString& strRecv);
    static int SendAndReceiveSocket(HWND hWnd, LPCTSTR lpwszHost, LPCTSTR lpwszReq, int nPortNo, CString& strError);
};
int CWinCESupport::StartServer(HWND hWnd, int nPortNo, int nTimeOutMs, CString& strError)
{
  strError = "";
  int index = 0;                      // Integer index
  int iReturn;                        // Return value of recv function
  char szServerA[4000];                // ASCII string
  TCHAR szServerW[4000];               // Unicode string
  TCHAR szError[4000];                 // Error message string
  SOCKET WinSocket = INVALID_SOCKET;  // Window socket
  SOCKET ClientSock = INVALID_SOCKET; // Socket for communicating
  // between the server and client
  SOCKADDR_IN local_sin;              // Local socket address
  SOCKADDR_IN accept_sin;             // Receives the address of the
  // connecting entity
  int accept_sin_len;                 // Length of accept_sin
  WSADATA WSAData;                    // Contains details of the Winsock
  // Initialize Winsock.
  if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
  {
    wsprintf (szError, TEXT("WSAStartup failed. Error: %d"), WSAGetLastError ());
    if (hWnd)
      ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
    strError = szError;
    return -1;
  }
  // Create a TCP/IP socket, WinSocket.
  if ((WinSocket = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  {
    wsprintf (szError, TEXT("Allocating socket failed. Error: %d"), WSAGetLastError ());
    if (hWnd)
      ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
    strError = szError;
    return -2;
  }
  // Fill out the local socket's address information.
  local_sin.sin_family = AF_INET;
  local_sin.sin_port = htons (nPortNo);
  local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
  // Associate the local address with WinSocket.
  if (bind (WinSocket,
    (struct sockaddr *) &local_sin,
    sizeof (local_sin)) == SOCKET_ERROR)
  {
    wsprintf (szError, TEXT("Binding socket failed. Error: %d"), WSAGetLastError ());
    if (hWnd)
      ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
    strError = szError;
    closesocket (WinSocket);
    return -3;
  }
  // Establish a socket to listen for incoming connections.
  const int MAXCONNECTIONS = 1;
  if (listen (WinSocket, MAXCONNECTIONS) == SOCKET_ERROR)
  {
    wsprintf (szError, TEXT("Listening to the client failed. Error: %d"), WSAGetLastError ());
    if (hWnd)
      ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
    strError = szError;
    closesocket (WinSocket);
    return -4;
  }
  accept_sin_len = sizeof (accept_sin);
  // Accept an incoming connection attempt on WinSocket.
  ClientSock = accept (WinSocket,
    (struct sockaddr *) &accept_sin,
    (int *) &accept_sin_len);
  // Stop listening for connections from clients.
  closesocket (WinSocket);
  if (ClientSock == INVALID_SOCKET)
  {
    wsprintf (szError, TEXT("Accepting connection with client failed."), TEXT(" Error: %d"), WSAGetLastError ());
    if (hWnd)
      ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
    strError = szError;
    return -5;
  }
  DWORD dwNow = ::GetTickCount();
  for (;;)
  {
    int nTimeEllapsed = ::GetTickCount() - dwNow;
    if (nTimeEllapsed > nTimeOutMs)
    {
      wsprintf (szError, TEXT("Timeout!"));
      if (hWnd)
        ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
      strError = szError;
      break;
    }
    // Receive data from the client.
    iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);
    // Check if there is any data received. If there is, display it.
    if (iReturn == SOCKET_ERROR)
    {
      wsprintf (szError, TEXT("No data is received, recv failed.")
        TEXT(" Error: %d"), WSAGetLastError ());
      if (hWnd)
        ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
      strError = szError;
      break;
    }
    else if (iReturn == 0)
    {
      break;
    }
    else
    {
      // Convert the ASCII string to the Unicode string.
      for (index = 0; index < iReturn; index++)
      {
        szServerW[index] = szServerA[index];
        strError += szServerA[index];
      }
      //erst komplette anforderung lesen und dann antworten
      if (strError.Find(TEXT("\r\n\r\n")) >= 0)
      {
        // Send a string from the server to the client.
        char szAnswer[2000] = "HTTP/1.1 200 OK\n\r"
                    "Content-type: text/plain\n\r"
                    "Server: RemoteWebCE 1.0\n\r"
                    "Pragma: no-cache\n\r"
                    "Cache-Control: no-cache, must-revalidate\n\r"
                    "Expires: Thu, 01 Dec 1994 16:00:00 GMT\n\r"
                    "\n\r"
                    ""
                    "Das ist mein erster selbstprogrammierter WinCE HTTP Server.\n\r";
        if (send (ClientSock, szAnswer, strlen(szAnswer) + 1, 0) == SOCKET_ERROR)
        {
          wsprintf (szError,
            TEXT("Sending data to the client failed. Error: %d"),
            WSAGetLastError ());
          if (hWnd)
            ::MessageBox (hWnd, szError, TEXT("Error"), MB_OK);
          strError = szError;
        }
      break;
      }
    }
  }
  // Disable both sending and receiving on ClientSock.
  shutdown (ClientSock, 0x02);
  // Close ClientSock.
  closesocket (ClientSock);
  WSACleanup ();
  return 0;
}
///////////////////////////////////
// sample usage
#include "../../msvc60/cpp_classes/WinCESupport.h"
BOOL CWincehttpDlg::OnInitDialog()
{
...
    int nErr = SetTimer(1, 200, NULL);  //ACHTUNG: id=0 funktioniert nicht!!!!!
...
    return TRUE;  // return TRUE  unless you set the focus to a control
}
void CWincehttpDlg::OnTimer(UINT nIDEvent)
{
    static bool volatile s_bLocked = false;
    if (!s_bLocked)
    {
        s_bLocked = true;
        DoServer();
        Sleep(100);
        s_bLocked = false;
    }
    CDialog::OnTimer(nIDEvent);
}
void CWincehttpDlg::DoServer()
{
    HWND hWnd = GetSafeHwnd();
    int nPortNo = 4711;
    int nTimeOutMs = 30000;
    CString strRecv;
    int nErr = CWinCESupport::StartServer(hWnd, nPortNo, nTimeOutMs, strRecv);
    strRecv.Replace(TEXT("\n"), TEXT("\r\n"));
    GetDlgItem(IDC_EDIT1)->SetWindowText(strRecv);
}