多线程异步TCP客户端实现

本文介绍了一个简单的TCP客户端实现,包括初始化、发送接收消息的线程处理,并展示了如何设置回调函数来处理接收到的消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其中使用到的其他头文件地址:

线程:http://blog.youkuaiyun.com/tujiaw/article/details/8795014

阻塞队列:http://blog.youkuaiyun.com/tujiaw/article/details/8779466

消息:http://blog.youkuaiyun.com/tujiaw/article/details/8665610

#define DISALLOW_COPY_AND_ASSIGN(ClassName) \
private: \
ClassName(const ClassName&); \
ClassName& operator= (const ClassName&)

#include <WinSock2.h>
#include <assert.h>
#include <string>
#include <memory>
#include "Def.h"
#include "Thread.h"
#include "Message.h"
#include "BlockQueue.h"

#pragma comment(lib, "Ws2_32.lib")
class WsaGuard
{
public:
	WsaGuard() { int iret = WSAStartup(MAKEWORD(2, 2), &wsaData_); assert(0 == iret); }
	~WsaGuard() { WSACleanup(); }

private:
	WSADATA wsaData_;
};

typedef std::tr1::function<void(MessagePtr&)> MessageCallback;

class TcpClient
{
	DISALLOW_COPY_AND_ASSIGN(TcpClient);
public:
	TcpClient(const std::string& ip, unsigned short port);
	~TcpClient();
	void setSendCallback(const MessageCallback& func) { sendCallback = func; }
	void setRecvCallback(const MessageCallback& func) { recvCallback_ = func; }
	int start();
	void sendMessage(MessagePtr& msgPtr);

private:
	void sendLoop();
	void recvLoop();

private:
	WsaGuard *init_;
	SOCKET sock_;
	std::string ip_;
	unsigned short port_;
	typedef std::tr1::shared_ptr<Thread> ThreadPtr;
	ThreadPtr sendPtr_;
	ThreadPtr recvPtr_;
	MessageCallback sendCallback;
	MessageCallback recvCallback_;
	BlockQueue<MessagePtr> sendQueue_;
};

#include "stdafx.h"
#include "Net.h"
#include <sstream>

TcpClient::TcpClient(const std::string& ip, unsigned short port)
	: init_(NULL), sock_(INVALID_SOCKET), ip_(ip), port_(port)
{
	init_ = new WsaGuard();
}

TcpClient::~TcpClient()
{
	closesocket(sock_);
	if (init_) { delete init_; }
}

int TcpClient::start()
{
	sock_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_)
	{
		return RET_CREATE_SOCKET;
	}

	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port_);
	sin.sin_addr.S_un.S_addr = inet_addr(ip_.c_str());
	int iconn = connect(sock_, (SOCKADDR*)&sin, sizeof(sin));
	if (SOCKET_ERROR == iconn)
	{
		closesocket(sock_);
		return RET_CONNECT_SERVER;
	}
	
	sendPtr_.reset(new Thread(std::tr1::bind(&TcpClient::sendLoop, this), "send"));
	sendPtr_->start();
	recvPtr_.reset(new Thread(std::tr1::bind(&TcpClient::recvLoop, this), "recv"));
	recvPtr_->start();

	return RET_SUCCESS;
}

void TcpClient::sendMessage(MessagePtr& msg) // FIXME
{
	OutputDebugStringA("send message");
	sendQueue_.put(msg);
}

void TcpClient::sendLoop()
{
	while (1)
	{
		OutputDebugStringA("111");
		MessagePtr msgPtr = sendQueue_.take();
		int isend = send(sock_, (char*)msgPtr->get(), msgPtr->count(), 0);
		if (SOCKET_ERROR == isend)
		{
			return;
		}
	}
}

void TcpClient::recvLoop()
{
	const int bufferLen = 4096;
	char buffer[bufferLen];
	while (1)
	{
		memset(buffer, 0, bufferLen);
		int irecv = recv(sock_, buffer, bufferLen, 0);
		if (SOCKET_ERROR == irecv)
		{
			return;
		}
		MessagePtr msgPtr(new Message((unsigned char*)buffer, irecv));
		recvCallback_(msgPtr);
	}
}



// 使用片段
typedef std::tr1::shared_ptr<TcpClient> TcpClientPtr;
TcpClientPtr m_clientPtr;
// ...
m_clientPtr.reset(new TcpClient(GetIp().c_str(), GetPort()));
m_clientPtr->setRecvCallback(std::tr1::bind(&CSpendDlg::OnMessage, this, std::tr1::placeholders::_1));
int iret = m_clientPtr->start();
// ...
m_clientPtr->sendMessage(msg);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值