2012-08-15 93 views
0

我從CAsyncSocket類實現我的ClientSocket的類:CAsyncSocket不發射事件?

class ClientSocket : public CAsyncSocket 
{ 
    // this socket sends data back to "backSocket" which points to this only for 
    // testing but it can send data to other sockets like that too. 
ClientSocket * backSocket; 

    // store some data in backupData untill connection is established. 
    StringBuilder * backupData; 

public: 

virtual void OnClose(int); 
virtual void OnReceive(int); 
ClientSocket(void); 
bool ConnectToBACK(); 
virtual ~ClientSocket(void); 
}; 

ClientSocket::ClientSocket(void) 
{ 
// DONOT run to back !!! recursive calls otherwise. 
backSocket = NULL; 
backupData = NULL; 
} 

bool ClientSocket::ConnectToBACK() 
{ 
if(this->backSocket != NULL) 
    return true; 

// just for debugging :) 
this->backSocket = this; 
return true; 
} 

ClientSocket::~ClientSocket(void) 
{ 
this->Close(); 
if(this->backSocket) 
{ 
    this->backSocket->Close(); 
    delete this->backSocket; 
    this->backSocket = NULL; 
} 
} 

void ClientSocket::OnClose(int nErrorCode) 
{ 
if(this->backSocket != NULL) 
{ 
    this->backSocket->Close(); 
} 

CAsyncSocket::OnClose(nErrorCode); 
} 

void ClientSocket::OnReceive(int nErrorCode) 
{ 
if(nErrorCode == 0) 
{ 
    char *buffer = new char[2049]; 
    int bufLen = sizeof(buffer)/sizeof(buffer[0]); 

    int received = this->Receive(buffer, bufLen-1, 0); 
    if(received == SOCKET_ERROR) 
    { 
     return ; 
    } 

    if(this->ConnectToback()) 
    { 
     if(backupData) 
     { 
      int backupLen; 
      char *backup = backupData->ToString(&backupLen); 
      this->backSocket->Send(backup, backupLen); 
      delete backupData; 
      delete [] backup; 
      backupData = NULL; 
     } 

     this->backSocket->Send(buffer, received); 
     delete buffer; 
    } 
    else 
    { 
     if(backupData == NULL) 
     { 
      backupData = new StringBuilder(); 
     } 
     backupData->Insert(buffer, received); 
    } 
} 

CAsyncSocket::OnReceive(nErrorCode); 
} 

,因爲我認爲這將是很好的任何費用我也沒有任何相關的GUI了這一點。 我不需要它。我也在主體中完成了AfxSocketIback(),並從一個線程啓動了另一個ListeningSocket。

netstat的-a顯示正確的聽力

// ListeningSocket繼承了大衆的CAsyncSocket

void ListeningSocket::OnAccept(int nErrorCode) 
{ 
#ifdef DEBUG 
std::cout << "\nOnAccepting Proxy Server :)"; 
#endif 
if(nErrorCode == 0) 
{ 
    ClientSocket *FromCliet = new ClientSocket(); 
    FromCliet->value = 100; 
    if(this->Accept(*FromCliet, NULL, NULL)) 
    { 
        // Connection just has ClientSocket * client 
     Connection * connection = new Connection(FromCliet); 
     // a list<Connection *> is stored in ListeningSocket 
        this->clients.push_front(connection); 
    } 
    else 
    { 
     std::cerr << "\nFailed to accept connection from Client"; 
    } 
} 

CAsyncSocket::OnAccept(nErrorCode); 
} 

當投入ListenSocket :: OnAccept brakepoints,它永遠不會到來這裏ListeningSocket的端口和狀態綁定。

編輯:

static DWORD WINAPI StartListening(LPVOID param) 
{ 
     ListeningSocket *app = (ListeningSocket *)param; 
    if(false == app->Create(7897, SOCK_STREAM, 31, "127.0.0.1")) 
    { 
    std::cerr << "\nCould not create\bind to port"; 
    delete app; 
    return -1; 
    } 
    if(false == app->Listen()) 
    { 
      std::cerr << "\nCould not listen"; 
     app->Close(); 
     delete app; 
     return -1; 
    } 
    return 0; 
} 

int ListeningSocket::Start() 
{ 
     if(NULL == CreateThread(NULL,0, StartListening, (LPVOID)this,0, NULL)) 
    { 
    return -1; 
    } 

    return 0; 
} 

我沒有像MFC嚮導的解決方案做到了。我有簡單的項目和main()。

My ListeningSocket Class is Singletone Class: 
class ListeningSocket : public CAsyncSocket 
{ 

    private: 
static ListeningSocket * ListeningSocket; 
std::list<Connection *> clients; 
ListeningSocket(void); 

    public: 
// overrides 
virtual void OnAccept(int); 
virtual void OnClose(int); 
static ListeningSocket * GetListeningSocket(); 
virtual ~ListeningSocket(void); 
virtual void Close(); 
int Start(void); 
    }; 
+0

我是新來的太Winsocks。 – 2012-08-15 18:59:53

+0

「bind()」和「listen()」的調用在哪裏? – 2012-08-15 19:21:28

+0

@Nikolai我編輯過的問題包括Create()和Listen()。請看一看。 – 2012-08-16 04:03:06

回答

2

CAsyncSocket類在內部使用Windows消息來觸發事件。您需要在帶消息循環的線程中創建CAsyncSocket派生類。在這種情況下,事件將被調用。僞代碼:

// This function runs in the context of worker thread 
void MyClass::ThreadFunction() 
{ 
    mySocket.Create(...); // creating CAsyncSocket-derived class 

    // Run message loop. 
    BOOL bRes = FALSE; 
    MSG msg; 

    while((bRes = GetMessage(&msg, NULL, 0, 0)) != 0) 
    { 
     if (bRes == -1) 
     { 
      break; 
     } 
     else 
     { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
     } 
    } 
} 

要停止此線程,請使用PostQuitMessage函數。

編輯。 我沒有發佈所有多線程的細節,假設你熟悉它們。通常,CreateThread需要全局函數作爲參數(或類靜態函數)。要調用常規類方法,請使用「this」作爲CreateThread參數,該參數作爲void *傳遞給全局線程函數。將其重新轉換爲類指針並調用常規的類方法。

+0

非常感謝。該函數對於CreateThread()的參數必須是靜態的。順便說一句我現在面臨着StackOverflowException。 – 2012-08-16 07:32:34

+0

答案已編輯。 – 2012-08-16 07:48:38

+0

我想通了:)從析構函數中刪除這個。我有性能問題。有小費嗎 ? – 2012-08-16 07:48:53

2

我也遇到過同樣的問題 - 有人重新實現CAsyncSocket,名爲CAsyncSocketEx - 構建爲CAsyncSocket的函數替換。

就在本週,我想我會看看我是否可以再次使用此代碼,並且遇到了同樣的問題。由於具有消息循環的線程中沒有創建異步窗口,該事件不會從WSAAsyncSelect()射擊...

看到這一點:http://support.microsoft.com/kb/90975