2014-03-07 10 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

相关问题