server.c

本文介绍了一个基于Windows平台的管道通信服务器程序实现细节。该程序利用多线程处理多个客户端连接请求,并通过重叠I/O进行高效的数据读写操作。文章深入解析了服务器端的初始化配置、客户端连接管理以及数据广播等核心功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5572165936844014&dt=1194442938015&lmt=1194190197&format=336x280_as&output=html&correlator=1194442937843&url=file%3A%2F%2F%2FC%3A%2FDocuments%2520and%2520Settings%2Flhh1%2F%E6%A1%8C%E9%9D%A2%2FCLanguage.htm&color_bg=FFFFFF&color_text=000000&color_link=000000&color_url=FFFFFF&color_border=FFFFFF&ad_type=text&ga_vid=583001034.1194442938&ga_sid=1194442938&ga_hid=1942779085&flash=9&u_h=768&u_w=1024&u_ah=740&u_aw=1024&u_cd=32&u_tz=480&u_java=true" frameborder="0" width="336" scrolling="no" height="280" allowtransparency="allowtransparency"> #define  STRICT
#include <windows.h>
#include "server.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

                                       // clients[] is a global array of
                                       // structures used to keep track
                                       // of the multiple instances of
                                       // the server side of the named
                                       // pipe.  As a client connects
                                       // to a given instance, a new
                                       // server thread is created and
                                       // added to the array.
WRTHANDLE clients[MAX_PIPE_INSTANCES];
DWORD     clientCount = 0;             // Global count of connected clients.

HWND   hWnd;
HANDLE hInst;
CHAR   lpBuffer[255];


int APIENTRY WinMain (HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPSTR  lpCmdLine,
                      int    nCmdShow)


{

  MSG  msg;
  WNDCLASS wc;


  UNREFERENCED_PARAMETER( lpCmdLine );
  UNREFERENCED_PARAMETER( hPrevInstance );

  //
  // Detect platform and exit gracefully if not Windows NT.
  //

  {
    OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

    GetVersionEx (&osvi);
    if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
   LoadString(hInst, IDS_WRONGOS, lpBuffer, sizeof(lpBuffer));  
      MessageBox (NULL, lpBuffer, "SERVER32", MB_OK | MB_ICONSTOP);
      return 0;
    }
  }

 

  hInst = hInstance;

  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC)MainWndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon (hInstance, "npserver");
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  wc.lpszMenuName = "PipeMenu";
  wc.lpszClassName = "PipeWClass";

  RegisterClass(&wc);

  LoadString(hInst, IDS_WINDOWTITLE, lpBuffer, sizeof(lpBuffer));  
  hWnd = CreateWindow ("PipeWClass",
                       lpBuffer,
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       NULL,
                       NULL,
                       hInstance,
                       NULL);


  ShowWindow (hWnd, nCmdShow);

  while (GetMessage (&msg, NULL, 0, 0))
    DispatchMessage (&msg);

  return (msg.wParam);

}

LONG CALLBACK MainWndProc (HWND   hwnd,
                           UINT   message,
                           WPARAM wParam,
                           LPARAM lParam)
{

  LONG        lpServerThreadID;
  PAINTSTRUCT paintStruct;
  HDC         hDC;

  switch (message)
      {
        case WM_PAINT:
           // DrawBranch is used to paint the spools and text to the window.
           hDC = BeginPaint (hwnd, &paintStruct);
           DrawBranch (hDC);
           EndPaint (hwnd, &paintStruct);
           return(0);

        case WM_CREATE :
           // Create the first instance of a server side of the pipe.
           CreateThread ((LPSECURITY_ATTRIBUTES)NULL,       // No security.
                         (DWORD)0,                          // Same stack size.
                         (LPTHREAD_START_ROUTINE)ServerProc,// Thread procedure.
                         (LPVOID)&hwnd,                     // Parameter.
                         (DWORD)0,                          // Start immediatly.
                         (LPDWORD)&lpServerThreadID);       // Thread ID.
           return (0);

        case WM_DESTROY :
           PostQuitMessage (0);
           return (0);
       }
    return DefWindowProc (hwnd, message, wParam, lParam);
}

 

/*************************************************************************/
*
*  PROCEDURE: ServerProc (HWND *hWnd)
*
*    A thread procedure, which creates an instance of the server side of
*    the named pipe, and then blocks waiting for a client to connect.
*    Once the client connects, a global array is updated with the specific
*    clients information, and this procedure is called again
*    to launch another waiting server thread.  After launching the new
*    thread, this thread begins to loop, reading the named pipe.  When
*    a message comes from its client, it uses TellAll() to broadcast
*    the message to the other clients in the array.
*
*  CALLED BY:
*
*    ServerProc();
*    WinMain();
*
*  CALLS TO:
*
*    TellAll();
*    ServerProc().
*
*  COMMENTS:
*
*    Clients is a global array which hold information on each client
*    connected to the named pipe.  This procedure recieves a buffer.
*    It then steps through this global array, and for each client it
*    writes the buffer.
*
/*************************************************************************/

VOID ServerProc(HWND *hWnd)
 {
   HANDLE hPipe;                       // Pipe handle.
   CHAR   inBuf[IN_BUF_SIZE] = "";     // Input buffer for pipe.
   DWORD  ServerThreadID;              // Used for CreateThread().

   CHAR   errorBuf[LINE_LEN] = "";     // Used for error messages.
   DWORD  bytesRead;                   // Used in ReadFile().
   DWORD  retCode;                     // Used to trap return codes.
   DWORD  clientIndex;                 // Index into global array, for this
                                       // instances client.
   DWORD  lastError;                   // Traps returns from GetLastError().
   BOOL   ExitLoop = FALSE;            // Boolean Flag to exit loop.

   OVERLAPPED OverLapWrt;              // Overlapped structure for writing.
   HANDLE     hEventWrt;               // Event handle for overlapped write.

   OVERLAPPED OverLapRd;               // Overlapped structure for reading.
   HANDLE     hEventRd;                // Event handle for overlapped reads.
   DWORD        bytesTransRd;          // Bytes transferred by overlapped.
   PSECURITY_DESCRIPTOR    pSD;
   SECURITY_ATTRIBUTES     sa;

                                       // create a security NULL security
                                       // descriptor, one that allows anyone
                                       // to write to the pipe... WARNING
                                       // entering NULL as the last attribute
                                       // of the CreateNamedPipe() will
                                       // indicate that you wish all
                                       // clients connecting to it to have
                                       // all of the same security attributes
                                       // as the user that started the
                                       // pipe server.

   pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
               SECURITY_DESCRIPTOR_MIN_LENGTH);

   if (pSD == NULL)
     {
     MessageBox (*hWnd, "Error in LocalAlloc for pSD",
                 "Debug: ServerProc()", MB_OK);
     return;
     }

   if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
     {
     wsprintf (errorBuf, "Error: InitializeSecurityDescriptor() %d",
               GetLastError());
     MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
       LocalFree((HLOCAL)pSD);
       return;
     }

                                       // add a NULL disc. ACL to the
                                       // security descriptor.

   if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))
     {
     wsprintf (errorBuf, "Error: SetSecurityDescriptorDacl() %d",
                GetLastError());
     MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
     LocalFree((HLOCAL)pSD);
     return;
     }

   sa.nLength = sizeof(sa);
   sa.lpSecurityDescriptor = pSD;
   sa.bInheritHandle = TRUE;

                                       // Create a local named pipe with
                                       // the name '//./PIPE/test'.  The
                                       // '.' signifies local pipe.
   hPipe = CreateNamedPipe (".//PIPE//test", // Pipe name = 'test'.
               PIPE_ACCESS_DUPLEX                // 2 way pipe.
               | FILE_FLAG_OVERLAPPED,           // Use overlapped structure.
               PIPE_WAIT                         // Wait on messages.
               | PIPE_READMODE_MESSAGE           // Specify message mode pipe.
               | PIPE_TYPE_MESSAGE,
               MAX_PIPE_INSTANCES,               // Maximum instance limit.
               OUT_BUF_SIZE,                     // Buffer sizes.
               IN_BUF_SIZE,
               TIME_OUT,                         // Specify time out.
               &sa);                             // Security attributes.

                                       // Check Errors.
    if ((DWORD)hPipe == 0xFFFFFFFF)
     {

     retCode = GetLastError();         // Report any error, it should always succeed.
     LoadString(hInst, IDS_ERRORCODE, lpBuffer, sizeof(lpBuffer));
     wsprintf (errorBuf, lpBuffer, retCode);
     LoadString(hInst, IDS_DEBUGTITLE, lpBuffer, sizeof(lpBuffer));
     MessageBox (*hWnd, errorBuf, lpBuffer,
                 MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
     };

                                       // Block until a client connects.
   ConnectNamedPipe(hPipe, NULL);

                                       // Create and init overlap for writing.
   hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
   memset (&OverLapWrt, 0, sizeof(OVERLAPPED));
   OverLapWrt.hEvent = hEventWrt;

                                       // Set the clientIndex, then increment
                                       // the count.  Fill in the structure
                                       // for this client in the array.
   clientIndex = clientCount++;
   clients[clientIndex].hPipe   = hPipe;
   clients[clientIndex].live    = TRUE;
   clients[clientIndex].overLap = OverLapWrt;
   clients[clientIndex].hEvent  = hEventWrt;

                                       // Create and init overlap for reading.
   hEventRd = CreateEvent(NULL,TRUE,FALSE,NULL);
   memset (&OverLapRd, 0, sizeof(OVERLAPPED));
   OverLapRd.hEvent = hEventRd;

                                       // Read from the client, the first
                                       // first message should always be
                                       // the clients user name.
   retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);

   if (!retCode)
    lastError = GetLastError();

   if (lastError == ERROR_IO_PENDING)  // Wait on read if need be.
     WaitForSingleObject (hEventRd, (DWORD)-1);

                                       // Put client's name in the array.
   strcpy (clients[clientIndex].Name, inBuf);

                                       // Create a thread which will make
                                       // another server instance of the
                                       // named pipe.
   CreateThread ((LPSECURITY_ATTRIBUTES)NULL,        // No security attributes.
                 (DWORD)0,                           // Use same stack size.
                 (LPTHREAD_START_ROUTINE)ServerProc, // Thread procedure.
                 (LPVOID)hWnd,                       // Parameter to pass.
                 (DWORD)0,                           // Run immediately.
                 (LPDWORD)&ServerThreadID);          // Thread identifier.

   TellAll("");                        // Forces a paint, draws a red spool
                                       // and name for this client.

                                       // Do loop which basically reads from
                                       // this specific client, and then
                                       // uses TellAll() to broadcast the
                                       // message to all the connected
                                       // clients.
   do{
                                       // Read the pipe.
      retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);

                                       // Check for three kinds of errors:
                                       // If Error = IO_PENDING, wait til
                                       // the event handle signals success,
                                       // If BROKEN_PIPE, exit the do loop.
                                       // Any other error, flag it to the
                                       // user and exit the do loop.
      if (!retCode)
        {
        lastError = GetLastError();

        switch (lastError)
          {
                                       // IO_PENDING, wait on the event.
           case ERROR_IO_PENDING:
             WaitForSingleObject (hEventRd, (DWORD)-1);
             break;
                                       // Pipe is broken, exit the loop.
           case ERROR_BROKEN_PIPE:
             ExitLoop = TRUE;
             break;
                                       // Something else is wrong, exit the
                                       // the loop after telling the user.
           default:
             LoadString(hInst, IDS_READERROR, lpBuffer, sizeof(lpBuffer));
             wsprintf (errorBuf, lpBuffer, lastError);
             LoadString(hInst, IDS_DEBUGINFO, lpBuffer, sizeof(lpBuffer));
             MessageBox (*hWnd, errorBuf, lpBuffer, MB_OK);
             ExitLoop = TRUE;
             break;
          }
        }

      if (!ExitLoop)
        {
        GetOverlappedResult (hPipe, &OverLapRd, &bytesTransRd, FALSE);

                                       // Use TellAll to broadcast the message.
        if (bytesTransRd)
          TellAll(inBuf);
        else
          TellAll("");
        }

   }while(!ExitLoop);

   clients[clientIndex].live = FALSE;  // Turns spool gray.
   CloseHandle (hPipe);                // Close handles.
   CloseHandle (hEventRd);
   CloseHandle (hEventWrt);
   DisconnectNamedPipe (hPipe);        // Close pipe instance.
   ExitThread(0);                      // Clean up and die.
  }


/*  To write the buffer (input parameter) to all of the clients listed
    in the global array "clients". Clients is a global array which hold information on each client
    connected to the named pipe.  This procedure recieves a buffer.
    It then steps through this global array, and for each client it
    writes the buffer.  */

VOID TellAll( CHAR *buffer )
  {
    DWORD i;                           // Index through array.
    DWORD bytesWritten;                // Used in WriteFile().
    DWORD retCode;                     // Traps return codes.
    CHAR  Buf[LINE_LEN];               // Message Buffer.
    DWORD lastError;                   // Traps returns from GetLastError().

    for(i=0; i < clientCount; i++)     // For all clients in the array.
      {
                                       // If client isn't alive, don't waste
                                       // time writing to it.
      if (clients[i].live)
        {
        retCode = WriteFile (clients[i].hPipe, buffer, strlen(buffer),
                             &bytesWritten, &clients[i].overLap);

                                       // Check 3 kinds of errors: IO_PENDING,
                                       // NO_DATA, or other.  Wait on event
                                       // handle if IO_PENDING, else, if it's
                                       // anything other than NO_DATA (pipe
                                       // client disconnected), flag the user.
                                       // In any case, if it's not IO_PENDING,
                                       // clients[i].live = FALSE, spool turns
                                       // gray.
        if (!retCode)
          {
          lastError = GetLastError();

                                       // IO_PENDING, wait on event handle.
          if (lastError == ERROR_IO_PENDING)
            {
            WaitForSingleObject (clients[i].hEvent, (DWORD)-1);
            }
          else
            {
                                       // If not NO_DATA, flag user.
            if (lastError != ERROR_NO_DATA)
              {
              LoadString(hInst, IDS_DEBUGLAST, lpBuffer, sizeof(lpBuffer));
              wsprintf (Buf, "%s = %d", buffer, GetLastError());
              MessageBox(hWnd, Buf, lpBuffer, MB_OK);
              }
            clients[i].live = FALSE;
            }
          }
        } //if client.live
      } // for loop
                                       // Paint window with new information.
    InvalidateRect(hWnd, NULL, TRUE);
  }

 

/*
    To draw one of four bitmaps for each client, depending upon the clients
    status (alive = red spool, dead or disconnected = gray), and location in
    the array.  It also draws the clients user name beside the spool.
    This procedure is executed when the WM_PAINT message is trapped.  */

VOID DrawBranch(HDC hDC)
{
                                       // Spool bitmaps.
  HBITMAP hEndLive, hEndDead, hMidLive, hMidDead, hBitMap;

  HDC hDCMem;
  int X, Y;
  BITMAP bm;
  POINT ptSize, ptOrg;
  DWORD index;

                                       // Load bitmaps: two red (live),
                                       // two dead (gray).  End = end
                                       // of tree (last client to connect),
                                       // mid means in the middle somewhere.
       hEndLive = LoadBitmap (hInst, "EndLive");
       hEndDead = LoadBitmap (hInst, "EndDead");

       hMidLive = LoadBitmap (hInst, "MidLive");
       hMidDead = LoadBitmap (hInst, "MidDead");

                                       // For each client, determine if
                                       // if alive or not, and position;
                                       // then blt appropriate map and
                                       // clients name.
    for (index = 0; index < clientCount; index++)
      {

      if (index < clientCount - 1)     // ClientCount - 1 = last (end) client.
       {
        if(clients[index].live)        // If live = red, else = gray.
         hBitMap = hMidLive;
        else
         hBitMap = hMidDead;
       }
      else
       {
        if(clients[index].live)        // If live = red, else = gray.
         hBitMap = hEndLive;
        else
         hBitMap = hEndDead;
       }
                                       // Calculate coordinates:
      X = BITMAP_X;                    // X position is constant.
      Y = index * BITMAP_Y;            // Y is based on index in the array.

                                       // Blt the chosen map.
      hDCMem = CreateCompatibleDC(hDC);
      SelectObject(hDCMem, hBitMap);
      SetMapMode(hDCMem, GetMapMode(hDC));

      GetObject(hBitMap, sizeof(BITMAP), &bm);

      ptSize.x = bm.bmWidth;
      ptSize.y = bm.bmHeight;
      DPtoLP (hDC, &ptSize, 1);

      ptOrg.x = 0;
      ptOrg.y = 0;
      DPtoLP (hDCMem, &ptOrg, 1);

      BitBlt(hDC, X, Y, ptSize.x, ptSize.y,
             hDCMem, ptOrg.x, ptOrg.y, SRCCOPY);


      X =  NAME_X;                     // Relocate X,Y for clients name.
      Y += NAME_Y;
                                       // Write name next to spool.
      TextOut (hDC, X, Y, clients[index].Name, strlen(clients[index].Name));
      DeleteDC(hDCMem);
      }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值