采用 SOCKET 参数的 C++ 线程
Posted
技术标签:
【中文标题】采用 SOCKET 参数的 C++ 线程【英文标题】:C++ Threading which takes a SOCKET parameter 【发布时间】:2014-03-07 01:40:05 【问题描述】:我目前正在做我的高级项目,该项目几乎完成了,但是我需要在不支持 C++11 的 VisualStudio 2010 中实现多线程。因此,我将其用作多线程的源(由我的讲师建议)http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx,我完全不知道如何使用 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() 中创建了该连接,但现在不确定将其放置在哪里
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() 中调用
if (connect(Connection, (SOCKADDR*)&Addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
cout << "Connection Failed" << endl;
在 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
【问题讨论】:
您遇到的实际问题是什么? @RemyLebeau 我不知道如何在 Sender 线程中调用连接函数,同时也已经创建了连接。基本上有没有办法调用Sender函数,它会创建连接并发送数据? 在我看来,C++11 根本不会让你的任务变得更容易,而且 VS2010 也有一些 C++11 的特性。您的问题与多线程相关,学习多线程不是几个小时或几天的课程,尤其是在 C/C++ 中。您链接的示例也是 C 示例而不是 C++ 示例。正确的 C++ 实现会将线程封装到一个线程类中,这会使事情变得更容易。 【参考方案1】:您要在线程中运行的代码需要在您传递给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;
【讨论】:
非常感谢你!对此,我真的非常感激!我整天都在为此头疼。你的男人!【参考方案2】:还有一点关于如何将线程封装到类中以获得真正面向对象和更可重用的代码的帮助:
#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;
【讨论】:
以上是关于采用 SOCKET 参数的 C++ 线程的主要内容,如果未能解决你的问题,请参考以下文章