2010-02-04 69 views
0

我想写一个服务器应用程序包装,因为我会与任何应用程序,我已经搜索了一个多星期的至少体面的指南或教程异步套接字(这包装必须是异步),到目前为止,我能做的是这样的:异步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后ags up to 100%usage .. 我想我的方法是不正确的,所以我的问题是有人可能会指出我的代码中可能存在的缺陷,或者只是指出我的异步套接字的体面指南,前提是我已经搜索过了一个星期没有结果(可能我的绝望阻碍了我选择正确的关键字:| )。 在此之前感谢并对此巨大的代码感到遗憾,只要它允许就修剪它。

制造商, SimpleButPerfect。

回答

2

1错误: 在服务器:: WaitForConnections创建HEVENT(处理器= WSACreateEvent())每次while循环执行,而不破坏它的时间。在while循环外部移动HEVENT创建。

第二个错误: 您的缓冲区长度为255(char),但您这样做: RClient-> Buffer [RClient-> RecvSize] ='\ 0'; 其中RClient-> RecvSize可以是缓冲区大小的缓冲区 - 这意味着您将classis设置为“buffer overrun”。

我希望这会有所帮助。 Dominik

+0

感谢您的回答,但是当我在循环外部创建处理程序时,循环仅仅开始像疯狂一样发射,甚至没有等待WSAEvent发生.. SimpleButPerfect。 – SimpleButPerfect 2010-02-04 14:05:48

+1

这是因为由WSAEvent()创建的事件是手动重置事件,并且您不会将其重置到任何位置;所以它被设置一次,然后保持设置。 – 2010-02-04 19:17:54

+0

忽略了代码,谢谢指出缺陷。 – SimpleButPerfect 2010-02-05 05:28:05