2014-03-07 57 views
0

我目前正在研究我的高級項目,並且該項目幾乎完成,但是我需要在不支持C++ 11的VisualStudio 2010中實現多線程。因此,我將此用作多線程源(由我的教師建議)http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx,我完全喪失瞭如何使用SOCKET實現這一點。C++線程化,它需要一個SOCKET參數

我的問題是我怎樣才能使用我已經編碼的套接字與多線程。以下是我到目前爲止。

typedef struct SenderData { 

SOCKET socConnection; 

} SENDERDATA, *PSENDERDATA; 


DWORD WINAPI SenderThreadFunction(LPVOID lpParam){ 
HANDLE hStdout; 
PSENDERDATA pDataArray; 

TCHAR msgBuf[BUF_SIZE]; 
size_t cchStringSize; 
DWORD dwChars; 

// Make sure there is a console to receive output results. 

hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
if(hStdout == INVALID_HANDLE_VALUE) 
    return 1; 

// Cast the parameter to the correct data type. 
// The pointer is known to be valid because 
// it was checked for NULL before the thread was created. 

pDataArray = (PSENDERDATA)lpParam; 

return 0; 
} 

該函數的所有命令在telnet來啓動一個會話,並從文件

DWORD WINAPI Sender(LPVOID lpParam){ 
} 

下創建的連接,這是我最初有在main(),但我不能確定發送郵件在哪裏,如果我沒有使用線程

012現在把它

WSADATA wsaData; // Creates wsaData object 
WSAStartup(MAKEWORD(2, 2), &wsaData); //Initializes Winsock 
//Creates the socket object named "soc(Connection" 
SOCKET socConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

SOCKADDR_IN Addr; 
HOSTENT* Host = gethostbyname("smtp.com"); 
Addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(in_addr*)Host->h_addr_list[0])); 
Addr.sin_family = AF_INET; 
Addr.sin_port = htons(25); 

這將在main()被調用

在main()中執行以下代碼時,我將如何放置以前的代碼以啓動? 我在C++上非常新,我非常感謝任何幫助。先謝謝你。

hThreadArray[0] = CreateThread( 
     NULL,     // default security attributes 
     0,      // use default stack size 
     Sender,  // thread function name 
     pDataArray[0],   // argument to thread function 
     0,      // use default creation flags 
     &dwThreadIdArray[0]); // returns the thread identifier 
+0

什麼是實際問題,你是具有? –

+0

@RemyLebeau我不知道如何在Sender線程中調用connect函數,同時也創建了Connection。基本上有一種方法可以調用發件人功能,它會創建連接併發送數據? – EAZYEASTON

+0

在我看來,C++ 11不會讓你的任務變得更簡單,VS2010也有一些C++ 11的特性。你的問題是多線程相關的,學習多線程不是幾小時或幾天的過程,特別是在C/C++中。你鏈接的例子也是一個不是C++的例子。正確的C++實現會將線程封裝到線程類中,使事情變得更容易。 – pasztorpisti

回答

0

要在一個線程中運行的代碼必須要傳遞到CreateThread()Sender()函數內。因此,這將是所有套接字調用(除WSAStartup()WSACleanup()之外,應該只調用一次)。

事情是這樣的:

DWORD WINAPI Sender(LPVOID lpParam) 
{ 
    // Make sure there is a console to receive output results. 
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
    if(hStdout == INVALID_HANDLE_VALUE) 
     return 1; 

    HOSTENT* Host = gethostbyname("smtp.com"); 
    if (!Host) 
    { 
     cout << "Unable to resolve smtp.com" << endl; 
     return 1; 
    } 

    //Creates the socket object named "soc(Connection" 
    SOCKET socConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (socConnection == INVALID_SOCKET) 
    { 
     cout << "Socket Failed" << endl; 
     return 1; 
    } 

    SOCKADDR_IN Addr = {0}; 
    Addr.sin_family = AF_INET; 
    Addr.sin_addr = * (in_addr*) Host->h_addr_list[0]; 
    Addr.sin_port = htons(25); 

    if (connect(socConnection, (SOCKADDR*)&Addr, sizeof(Addr)) == SOCKET_ERROR) 
    { 
     cout << "Connection Failed" << endl; 
     closesocket(socConnection); 
     return 1; 
    } 

    ... 

    closesocket(socConnection); 
    return 0; 
} 

int main() 
{ 
    WSADATA wsaData; // Creates wsaData object 
    WSAStartup(MAKEWORD(2, 2), &wsaData); //Initializes Winsock 

    DWORD dwThreadId; 
    HANDLE hThread = CreateThread( 
     NULL,     // default security attributes 
     0,      // use default stack size 
     &Sender,    // thread function name 
     NULL,     // argument to thread function 
     0,      // use default creation flags 
     &dwThreadId); 

    ... 

    WaitForSingleObject(hThread, INFINITE); 

    DWORD ExitCode = 0; 
    GetExitCodeThread(hThread, &ExitCode); 

    CloseHandle(hThread); 

    if (ExitCode != 0) 
    { 
     ... 
    } 

    ... 

    WSACleanup(); 
    return 0; 
} 
+0

非常感謝你的男人!對此,我真的非常感激!我一整天都在b my我的腦袋。你的男人! – EAZYEASTON

0

而且還就如何封裝線爲類一點點幫助,使他們真正面向對象,更可重用代碼:

#include <windows.h> 
#include <stdio.h> 
#include <assert.h> 

class CThread 
{ 
public: 
    void Start() 
    { 
     assert(!m_Handle); 
     DWORD thread_id; 
     m_Handle = ::CreateThread(NULL, 0, StaticThreadProc, this, 0, &thread_id); 
     // this should be a fatal error/exit instead of a simple assert... 
     assert(m_Handle); 
    } 

    void Join() 
    { 
     assert(m_Handle); 
     ::WaitForSingleObject(m_Handle, INFINITE); 
    } 

protected: 
    virtual void Execute() = 0; 

    CThread() : m_Handle(NULL) {} 
    ~CThread() 
    { 
     if (m_Handle) 
     { 
      Join(); 
      ::CloseHandle(m_Handle); 
      m_Handle = NULL; 
     } 
    } 

private: 
    static DWORD WINAPI StaticThreadProc(LPVOID param) 
    { 
     CThread* thread = reinterpret_cast<CThread*>(param); 
     thread->Execute(); 
     return 0; 
    } 

private: 
    HANDLE m_Handle; 
}; 

class CMyThread : public CThread 
{ 
public: 
    CMyThread() 
    { 
     m_Sock = NULL; 
     m_Whatever = 0; 
     m_OtherParam = 0; 
     m_Result = 0; 
    } 

    // Use this to initialize the parameters for your thread before starting it... 
    // You could initialize from your constructor too if you wouldn't store your 
    // threads in an array by value... 
    void Init(SOCKET sock, int whatever_parameter_you_need, int other_param) 
    { 
     m_Sock = sock; 
     m_Whatever = whatever_parameter_you_need; 
     m_OtherParam = other_param; 
    } 

    int GetResult() const 
    { 
     return m_Result; 
    } 

protected: 
    virtual void Execute() override 
    { 
     // Use m_Sock, m_Whatever, m_OtherParam .... 
     // Fill out m_Result before returning from the Execute() method of the thread. 

     // You can also create the socket inside the thread if you want, 
     // noone forces you to pass it here as an init parameter. 
     m_Result = 5; 
    } 

private: 
    SOCKET m_Sock; 
    int m_Whatever; 
    int m_OtherParam; 
    int m_Result; 
}; 


int main() 
{ 
    // TODO: network init (WSAStartup) 

    const int NUM_THREADS = 3; 
    CMyThread threads[NUM_THREADS]; 

    // 1. Initializing threads with incoming parameters to work with 
    for (int i=0; i<NUM_THREADS; ++i) 
    { 
     //threads[i].Init(...) 
    } 

    // 2. Starting threads 
    for (int i=0; i<NUM_THREADS; ++i) 
     threads[i].Start(); 

    // 3. Waiting for threads to finish... 
    for (int i=0; i<NUM_THREADS; ++i) 
     threads[i].Join(); 

    // 4. Processing results if needed 
    int result0 = threads[0].GetResult(); 
    printf("%d\n", result0); 

    // TODO: Network Cleanup (WSACleanup) 

    return 0; 
} 
+0

很酷,謝謝你的信息。 – EAZYEASTON

相關問題