现在的位置: 首页 > 综合 > 正文

套接字包装器

2018年03月31日 ⁄ 综合 ⁄ 共 5939字 ⁄ 字号 评论关闭

对于网络的调用的包装一直都是做为一个工程的支撑,使用ACE固然是不错的选择,但是对于一个小工程来说未免有些喧宾夺主的味道。ACE中使用面向对象的技术去避免很多接口的误用,却造成了整个工程的规模变得很庞大难用。下面给出一个简单的实现。

SocketImp.h

#ifndef _SOCKETIMP_H_
#define _SOCKETIMP_H_


#include <string>

typedef int SOCKET;

class SocketImp
{

public:
	SOCKET	sock;

	SocketImp();
	~SocketImp();
	
	bool isBound();
	bool close();
	bool setReuseAddress(bool on);
	void setTimeout(int timeout);


	static const int STREAM;

	static const int DGRAM;
	
	void setSocket(SOCKET value)
	{
		sock = value;
	}

	SOCKET getSocket()
	{
		return sock;
	}

	void setLocalAddress(const char *addr)
	{
		localAddr = (addr != NULL) ? addr : "";
		//StripIPv6ScopeID(addr, localAddr);
	}

	const char *getLocalAddress()
	{
		return localAddr.c_str();
	}

	void setLocalPort(int port)
	{
		localPort = port;
	}

	int getLocalPort()
	{
		return localPort;
	}
	

	int getType()

	{

		return type;

	}

protected:	

	void setType(int value)

	{

		type = value;

	}
private:

	int type;
	std::string localAddr;
	int localPort;

};

void SocketStartup();
void SocketCleanup();

#endif

SocketImp.cpp

#include <net/SocketImp.h>
#include <net/SocketUtil.h>
#include <net/HostInterface.h>
#include <util/Mutex.h>
#include <util/StringUtil.h>
#include <fcntl.h>
#include <signal.h>

////////////////////////////////////////////////
//	Constants
////////////////////////////////////////////////

const int SocketImp::STREAM = 1;
const int SocketImp::DGRAM = 2;

////////////////////////////////////////////////
//	SocketInit/Close
////////////////////////////////////////////////

static int socketCnt = 0;
static Mutex sockMutex;

void CyberNet::SocketStartup()
{
	sockMutex.lock();
	if (socketCnt == 0) {
		signal(SIGPIPE, SIG_IGN);
	}
	socketCnt++;
	sockMutex.unlock();
}

void CyberNet::SocketCleanup()
{
	sockMutex.lock();
	socketCnt--;
	if (socketCnt <= 0) {
		signal(SIGPIPE, SIG_DFL);
	}
	sockMutex.unlock();
}

////////////////////////////////////////////////
//	Constructor/Destructor
////////////////////////////////////////////////

SocketImp::SocketImp()
{
	SocketStartup();
	setType(0);
	setLocalAddress("");
	setLocalPort(0);
	setSocket(-1);
}

SocketImp::~SocketImp()
{
	SocketCleanup();
}

bool SocketImp::isBound()
{
	return (0 <= sock) ? true : false;
}

////////////////////////////////////////////////
//	close
////////////////////////////////////////////////

bool SocketImp::close()
{
	if (isBound() == true)
		return true;
	int flag = fcntl(sock, F_GETFL, 0);
	if (0 <= flag)
		fcntl(sock, F_SETFL, flag | O_NONBLOCK);
	shutdown(sock, 2);
	::close(sock);
	setSocket(-1);

	return true;
}

////////////////////////////////////////////////
//	Socket Option
////////////////////////////////////////////////

bool SocketImp::setReuseAddress(bool flag)
{
	int sockOptRet;
	int optval = (flag == true) ? 1 : 0;
	sockOptRet = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof(optval));
	setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char *)&optval, sizeof(optval));
	return (sockOptRet == 0) ? true : false;
}

void SocketImp::setTimeout(int timeout)
{
	setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));
	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
}

以上是Socket的一个代理的基类,下面是流式的Socket

Socket.h

#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <net/SocketImp.h>

class Socket : public SocketImp
{

public:
	Socket();
	~Socket();

	bool listen();

	bool bind(int port, const char *addr);

	bool accept(Socket *socket);

	bool connect(const char *addr, int port);

	int send(const char *cmd, int cmdLen);
	int send(const char *cmd);

	int recv(char *buffer, int bufferLen);

};

#endif

Socket.cpp

#include <net/Socket.h>
#include <util/StringUtil.h>
#include <util/TimeUtil.h>
#include <net/SocketUtil.h>
#include <stdio.h>



////////////////////////////////////////////////
//	Socket
////////////////////////////////////////////////

Socket::Socket()
{
	setType(STREAM);

}

Socket::~Socket()
{
	close();

}

////////////////////////////////////////////////
//	listen
////////////////////////////////////////////////

bool Socket::listen()
{

	int ret = ::listen(sock, SOMAXCONN);

	return (ret == 0) ? true: false;

}

////////////////////////////////////////////////
//	bind
////////////////////////////////////////////////

bool Socket::bind(int bindPort, const char *bindAddr)
{
	setLocalAddress("");
	setLocalPort(0);

	if (bindPort <= 0 || bindAddr == NULL)
		return false;
	struct addrinfo *addrInfo;
	if (toSocketAddrInfo(SOCK_STREAM, bindAddr, bindPort, &addrInfo, true) == false)
		return false;
	sock = socket(addrInfo->ai_family, addrInfo->ai_socktype, 0);
	if (sock == -1) {
		close();
		return false;
	}
	int ret = ::bind(sock, addrInfo->ai_addr, addrInfo->ai_addrlen);
	freeaddrinfo(addrInfo);

	if (ret != 0)
		return false;

	setLocalAddress(bindAddr);
	setLocalPort(bindPort);

	return true;
}

////////////////////////////////////////////////
//	accept
////////////////////////////////////////////////

bool Socket::accept(Socket *socket)
{

	SOCKET clientSock;
	struct sockaddr_storage sockClientAddr;
	socklen_t nLength = sizeof(sockClientAddr);
	clientSock = ::accept(sock, (struct sockaddr *)&sockClientAddr, &nLength);
	if (clientSock < 0)
		return false;

	socket->setSocket(clientSock);
	socket->setLocalAddress(getLocalAddress());
	socket->setLocalPort(getLocalPort());

	return true;
}

////////////////////////////////////////////////
//	connect
////////////////////////////////////////////////

bool Socket::connect(const char *addr, int port)
{
	struct addrinfo *toaddrInfo;
	if (toSocketAddrInfo(SOCK_STREAM, addr, port, &toaddrInfo, true) == false)
		return false;

	if (isBound() == false)
		sock = socket(toaddrInfo->ai_family, toaddrInfo->ai_socktype, 0);

	int ret = ::connect(sock, toaddrInfo->ai_addr, toaddrInfo->ai_addrlen);
	freeaddrinfo(toaddrInfo);

	return (ret == 0) ? true : false;
}

////////////////////////////////////////////////
//	recv
////////////////////////////////////////////////

int Socket::recv(char *buffer, int bufferLen)
{
	int recvLen;

	recvLen = ::recv(sock, buffer, bufferLen, 0);

	return recvLen;

}



////////////////////////////////////////////////
//	send
////////////////////////////////////////////////

const int CG_NET_SOCKET_SEND_RETRY_CNT = 10;
const int CG_NET_SOCKET_SEND_RETRY_WAIT_MSEC = 1000;

int Socket::send(const char *cmd, int cmdLen)
{
	if (cmdLen <= 0)
		return 0;
	int nTotalSent = 0;
	int cmdPos = 0;
	int retryCnt = 0;
	do {

		int nSent = ::send(sock, cmd + cmdPos, cmdLen, 0);
		if (nSent <= 0) {
			retryCnt++;
			if (CG_NET_SOCKET_SEND_RETRY_CNT < retryCnt)
				break;
			WaitRandom(CG_NET_SOCKET_SEND_RETRY_WAIT_MSEC);
			continue;
		}
		nTotalSent += nSent;
		cmdPos += nSent;
		cmdLen -= nSent;
		retryCnt = 0;
	} while (0 < cmdLen);
	return nTotalSent;
}

int Socket::send(const char *cmd)
{
	return send(cmd, StringLength(cmd));
}

【上篇】
【下篇】

抱歉!评论已关闭.