2010-02-04 2 views
0

모든 응용 프로그램 에서처럼 서버 응용 프로그램 래퍼를 작성하려고합니다. 적어도 1 주일 이상 비례 소켓 또는 자습서를 검색했습니다. 래퍼는 비동기 수있다) 지금까지 내가 무엇을 할 수 있는지 이것이다 :비동기 winsock 서버 래퍼, CPU 후행 - C++

#ifndef _SERVER_H 
#define _SERVER_H 

#include "asynserv.h" // header file with the important lib includes 
#include <map> 

namespace Connections 
{ 
    DWORD WINAPI MainThread(LPVOID lParam); // Main thread 
    DWORD WINAPI DataThread(LPVOID lParam); // thread that will be created for each client 
    struct ClientServer // struct to keep a server and a client pair. 
    { 
    public: 
     struct Client* Client; 
     class Server* Server; 
    }; 
    struct Client // a struct wrapper to keep clients 
    { 
    public: 
     Client(SOCKET Connection, int BufferSize, UINT ID); 
     ~Client(); 
     SOCKET WorkerSocket; 
     char Buffer[255]; 
     bool Connected; 
     int RecvSize; 
     UINT UID; 
     void Send(char * Data); 
     void Disconnect(); 
    }; 
    class Server 
    { 
    private: 
     SOCKET WorkerSocket; 
     SOCKADDR_IN EndPnt; 
     UINT ID; 
     int CBufferSize; 
    public: 
     Server(int Port, int Backlog, int BufferSize); 
     ~Server(); 
     __event void ClientRecieved(Client* Clientr, char * RecData); 
     bool Enabled; 
     int Port; 
     int Backlog; 
     HWND ReqhWnd; 
     std::map<UINT, Client*> ClientPool; 
     void WaitForConnections(Server*); 
     void WaitForData(Client*); 
     void InvokeClientDC(UINT); 
     void Startup(); 
     void Shutdown(); 
    }; 
} 
#endif 

Server.cpp :

#include "Server.h" 

namespace Connections 
{ 
    void Server::Startup() 
    { 
     WSADATA wsa; 
     WSAStartup(0x0202, &wsa); 
     this->WorkerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
     this->EndPnt.sin_addr.s_addr = ADDR_ANY; 
     this->EndPnt.sin_family = AF_INET; 
     this->EndPnt.sin_port = htons(this->Port); 
     this->Enabled = true; 
     this->ID = 0; 
     bind(this->WorkerSocket, (SOCKADDR*)&this->EndPnt, sizeof(this->EndPnt)); 
     printf("[AsynServer]Bound..\n"); 
     listen(this->WorkerSocket, this->Backlog); 
       CreateThread(NULL, NULL, &MainThread, this, NULL, NULL); 
    } 
    void Server::WaitForConnections(Server * Ser) 
    { 
     WSAEVENT Handler = WSA_INVALID_EVENT; 
     while(Ser->Enabled) 
     { 
      Handler = WSACreateEvent(); 
      WSAEventSelect(Ser->WorkerSocket, Handler, FD_ACCEPT); 
      WaitForSingleObject(Handler, INFINITE); 
      SOCKET accptsock = accept(Ser->WorkerSocket, NULL, NULL); 
      Client * NewClient = new Client(accptsock, 255, Ser->ID++); 
      NewClient->Connected = true; 
      printf("[AsynServer]Client connected.\n"); 
      ClientServer * OurStruct = new ClientServer(); 
      OurStruct->Server = Ser; 
      OurStruct->Client = NewClient; 
      CreateThread(NULL, NULL, &DataThread, OurStruct, NULL, NULL); 
     } 
    } 
    void Server::WaitForData(Client * RClient) 
    { 
     WSAEVENT Tem = WSA_INVALID_EVENT; 
     Tem = WSACreateEvent(); 
     WSAEventSelect(RClient->WorkerSocket, Tem, FD_READ); 
     while(RClient->Connected) 
     { 
      WaitForSingleObject(Tem, INFINITE); 
      RClient->RecvSize = recv(RClient->WorkerSocket, RClient->Buffer, 255, NULL); 
      if(RClient->RecvSize > 0) 
      { 
       RClient->Buffer[RClient->RecvSize] = '\0'; 
       __raise this->ClientRecieved(RClient, RClient->Buffer); 
       Sleep(50); 
      } 
     } 
     return; 
    } 
    DWORD WINAPI MainThread(LPVOID lParam) 
    { 
     ((Server*)lParam)->WaitForConnections((Server*)lParam); 
     return 0; 
    } 
    DWORD WINAPI DataThread(LPVOID lParam) 
    { 
     ClientServer * Sta = ((ClientServer*)lParam); 
     Sta->Server->WaitForData(Sta->Client); 
     return 0; 
    } 
} 

이제 서버 인스턴스를 만들고 메인 스레드를 생성 한 후, 내가 받아 들일 수있는 클라이언트 동시에 데이터를 보내고 읽지 만 두 번 연결 한 후에는 내 CPU l agws 최대 100 % 사용량까지. 내 방법이 잘못되었습니다, 그래서 내 질문에 누군가가 내 코드에 가능한 결함을 지적하거나 그냥 비동기 소켓에 대한 괜찮은 가이드를 가리킨 수있는 제공 한 이미 제공 한 결과가없는 1 주일 (아마도 절망은 올바른 키워드를 선택하는 것을 방해하고 있습니다.). 거대한 코드 조각에 대해 미리 감사 드리며, 허용 된 한 그것을 다듬습니다.

Mfg, SimpleButPerfect.

답변

2

첫 번째 버그 : Server :: WaitForConnections에서 while 루프가 파괴되지 않고 실행될 때마다 HEVENT (Handler = WSACreateEvent())를 만듭니다. while 루프 외부에서 HEVENT 생성을 이동하십시오.

두 번째 버그 : 버퍼가 255 자 (char)이지만 다음을 수행하십시오. RClient-> Buffer [RClient-> RecvSize] = '\ 0'; 여기서 RClient-> RecvSize는 버퍼의 크기를 나타낼 수 있습니다. 즉, 클래스를 "버퍼 오버런"으로 만드는 것을 의미합니다.

이 정보가 도움이되기를 바랍니다. Dominik

+0

답장을 보내 주셔서 감사합니다.하지만 루프 외부에서 처리기를 만들면 WSAEvent가 발생할 때까지 기다리지 않고 루프가 시작됩니다. SimpleButPerfect. – SimpleButPerfect

+1

WSAEvent()에 의해 생성 된 이벤트가 수동 재설정 이벤트이고 어디에서나 재설정하지 않기 때문입니다. 그래서 그것은 한 번 설정되면 다음 설정을 유지합니다. –

+0

코드를 간과 했으므로 결함을 지적 해 주셔서 감사합니다. – SimpleButPerfect