⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpsocket.cpp

📁 一个简单实用的开源C++消息中间件SAFMQ - [软件开发] - [开源 消息中间件 SAFMQ ] 2006-11-23 在很多网络应用中
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 Copyright 2005 Matthew J. Battey

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software distributed
	under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
	CONDITIONS OF ANY KIND, either express or implied. See the License for the
	specific language governing permissions and limitations under the License.




This software implements a platform independent C++ interface to TCP/IP socket
communications.
*/
#pragma warning(disable: 4786)

#include "tcpsocket.h"
#ifdef _WIN32
	#define EWOULDBLOCK             WSAEWOULDBLOCK
	#define EINPROGRESS             WSAEINPROGRESS
	#define EALREADY                WSAEALREADY
	#define ENOTSOCK                WSAENOTSOCK
	#define EDESTADDRREQ            WSAEDESTADDRREQ
	#define EMSGSIZE                WSAEMSGSIZE
	#define EPROTOTYPE              WSAEPROTOTYPE
	#define ENOPROTOOPT             WSAENOPROTOOPT
	#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
	#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
	#define EOPNOTSUPP              WSAEOPNOTSUPP
	#define EPFNOSUPPORT            WSAEPFNOSUPPORT
	#define EAFNOSUPPORT            WSAEAFNOSUPPORT
	#define EADDRINUSE              WSAEADDRINUSE
	#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
	#define ENETDOWN                WSAENETDOWN
	#define ENETUNREACH             WSAENETUNREACH
	#define ENETRESET               WSAENETRESET
	#define ECONNABORTED            WSAECONNABORTED
	#define ECONNRESET              WSAECONNRESET
	#define ENOBUFS                 WSAENOBUFS
	#define EISCONN                 WSAEISCONN
	#define ENOTCONN                WSAENOTCONN
	#define ESHUTDOWN               WSAESHUTDOWN
	#define ETOOMANYREFS            WSAETOOMANYREFS
	#define ETIMEDOUT               WSAETIMEDOUT
	#define ECONNREFUSED            WSAECONNREFUSED
	#define ELOOP                   WSAELOOP
	#define EHOSTDOWN               WSAEHOSTDOWN
	#define EHOSTUNREACH            WSAEHOSTUNREACH
	#define EPROCLIM                WSAEPROCLIM
	#define EUSERS                  WSAEUSERS
	#define EDQUOT                  WSAEDQUOT
	#define ESTALE                  WSAESTALE
	#define EREMOTE                 WSAEREMOTE
	typedef int socklen_t;
	#define SOCERRNO				h_errno

	struct _WSAINIT {
		_WSAINIT() {
			WSADATA data;
			::WSAStartup(MAKEWORD( 2, 0 ), & data);
		}
		~_WSAINIT() {
			::WSACleanup();
		}
	} _INITTER;

	#ifdef min
		#undef min
		#define min _cpp_min
	#endif
	#ifdef max
		#undef max
		#define max _cpp_max
	#endif


#else
	#include <netdb.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <arpa/inet.h>
	#include <unistd.h>
	#include <sys/time.h>
	#include <fcntl.h>
	#define SOCERRNO				errno
#endif
#include <new>

#include <iostream>
using namespace std;

namespace tcpsocket {

static void sleep(int milliseconds)
{
#ifdef _WIN32
	::Sleep(milliseconds);
#else
	timespec ts = { 0, milliseconds*1000*1000 };
	::nanosleep(&ts,NULL);
#endif
}

// /////////////////////////////////////////////////////////////////////////////
// SocketException Implementation
// /////////////////////////////////////////////////////////////////////////////
/**
Provides the error message from the exception
@return A string depicting the error.
*/
const char* SocketException::what()
{ 
#define RETS(s,m) case s: return #s": "m;
#ifdef _WIN32
#define SRETS(s,m) case s+WSABASEERR: return #s": "m;
#else
#define SRETS(s,m) RETS(s,m)
#endif

	switch (m_err) {
		RETS(EWOULDBLOCK,"Resource temporarily unavailable")
		RETS(EINPROGRESS,"Operation now in progress")
		RETS(EALREADY,"Operation already in progress")
		RETS(ENOTSOCK,"Socket operation on nonsocket")
		RETS(EDESTADDRREQ,"Destination address required")
		RETS(EMSGSIZE,"Message too long")
		RETS(EPROTOTYPE,"Protocol wrong type for socket")
		RETS(ENOPROTOOPT,"Bad protocol option")
		RETS(EPROTONOSUPPORT,"Protocol not supported")
		RETS(ESOCKTNOSUPPORT,"Socket type not supported")
		RETS(EOPNOTSUPP,"Operation not supported")
		RETS(EPFNOSUPPORT,"Protocol family not supported")
		RETS(EAFNOSUPPORT,"Address family not supported by protocol family")
		RETS(EADDRINUSE,"Address already in use")
		RETS(EADDRNOTAVAIL,"Cannot assign requested address")
		RETS(ENETDOWN,"Network is down")
		RETS(ENETUNREACH,"Network is unreachable")
		RETS(ENETRESET,"Network dropped connection on reset")
		RETS(ECONNABORTED,"Software caused connection abort")
		RETS(ECONNRESET,"Connection reset by peer")
		RETS(ENOBUFS,"No buffer space available")
		RETS(EISCONN,"Socket is already connected")
		RETS(ENOTCONN,"Socket is not connected")
		RETS(ESHUTDOWN,"Cannot send after socket shutdown")
		RETS(ETIMEDOUT,"Connection timed out")
		RETS(ECONNREFUSED,"Connection refused")
		RETS(EHOSTDOWN,"Host is down")
		RETS(EHOSTUNREACH,"No route to host")
		//RETS(EPROCLIM,"Too many processes")
		SRETS(EINTR,"Operation interrupted")
		SRETS(EBADF,"Bad file number")
		SRETS(EACCES,"Permission denied")
		SRETS(EFAULT,"Bad address")
		SRETS(EINVAL,"Invalid argument")
		SRETS(EMFILE,"Too many files opened")
		//RETS(ETOOMANYREFS,"")
		//RETS(ELOOP,"")
		//RETS(EUSERS,"")
		//RETS(EDQUOT,"")
		//RETS(ESTALE,"")
		//RETS(EREMOTE,"")
	}
#undef RETS
#undef SRETS
	return "Unknown Error";
}

// ////////////////////////////////////////////////////////////////////
// Socket Implementation
// ////////////////////////////////////////////////////////////////////
/**
Constructs the socket and opens a connection to a server.
@param host [in] The address of the server or DNS name
@param port [in] The TCP port to connect to
*/
Socket::Socket(const char* host, short port) throw (SocketException)
{
	struct sockaddr_in	dest;
	init();

	m_socket = (int)::socket(AF_INET, SOCK_STREAM, 0);

	if (m_socket == -1)
		throw SocketException(SOCERRNO);

	unsigned long addr;
	if ( (addr = ::inet_addr(host)) == (INADDR_NONE))  {
		struct hostent*	hp = ::gethostbyname(host);
		if (hp)
			addr = *(unsigned long*)hp->h_addr;
		else
			throw SocketException(ENOENT);
	}

	::memset(&dest, 0, sizeof(dest));
	dest.sin_addr	= *(struct in_addr*)&addr;
	dest.sin_family	= AF_INET;
	dest.sin_port	= htons(port);

	if (::connect(m_socket, (struct sockaddr*)&dest, sizeof(dest)) != 0) {
		int err = SOCERRNO;
		close();
		throw SocketException(err);
	}
}

/**
Destroys the socket.  Note: does not close the socket handle
*/
Socket::~Socket()
{

}

/**
Sends data over the socket.  Sends exactly <code>length</code> bytes.

@param sendBuffer [in] A buffer containing the data to be sent
@param length [in] The number of bytes in the buffer
@return The number of bytes sent, -1 on error, and 0 if the connection was closed
@exception SocketException if the connection was closed and the throw on close flag was set.
*/
size_t Socket::send(const char* sendBuffer, size_t length)	throw (SocketException)
{
	int	sent = 0;
	int	isent;

	while ( sent < (int)length ) {
		isent = ::send(m_socket,sendBuffer+sent,(int)length-sent,0);
		if (isent == 0) {
			if (m_throwOnClose)
				throw SocketException(ECONNRESET);
			break;
		} else if (isent < 0) {
			int err = SOCERRNO;
			if (err == EWOULDBLOCK) {
				sleep(200);
			} else
				throw SocketException(err);
		} else {
			sent += isent;
		}
	}
	return sent;
}

/**
Receives data from the socket.  Receives exactly <code>length</code> bytes or
less if the socket is closed early.

@param sendBuffer [out] A buffer receiving the data 
@param length [in] The maximum number of bytes in the buffer
@return The number of bytes received, -1 on error, and 0 if the connection was closed
@exception SocketException if the connection was closed and the throw on close flag was set.
*/
size_t Socket::receive(char* readBuffer, size_t length)		throw (SocketException)
{
	int	nread = 0;
	int	iread;

	while ( nread < (int)length ) {
		iread = ::recv(m_socket,readBuffer+nread,(int)length-nread,0);
		if (iread == 0) {
			if (m_throwOnClose)
				throw SocketException(ECONNRESET);
			break;
		} else if (iread < 0) {
			int err = SOCERRNO;
			if (err == EWOULDBLOCK) {
				sleep(10);
			} else
				throw SocketException(err);
		} else {
			nread += iread;
		}
	}
	return nread;

}

/**
Receives data from the socket.  Receives upto <code>length</code> bytes.

@param sendBuffer [out] A buffer receiving the data 
@param length [in] The maximum number of bytes in the buffer
@return The number of bytes received, -1 on error, and 0 if the connection was closed
@exception SocketException if the connection was closed and the throw on close flag was set.
*/
size_t Socket::receiveSome(char* readBuffer, size_t length)	throw (SocketException)
{
	int	nread = 0;
	int	iread;
	
	while ( nread == 0 ) {
		iread = ::recv(m_socket,readBuffer+nread,(int)length-nread,0);
		if (iread == 0) {
			int err = SOCERRNO;
			if (m_throwOnClose)
				throw SocketException(ECONNRESET);
			break;
		} else if (iread < 0) {
			int err = SOCERRNO;
			if (err == EWOULDBLOCK) {
				sleep(10);
			} else
				throw SocketException(err);
		} else {
			nread += iread;
		}
	}
	return nread;
}

/**
Closes the socket handle.
*/
void Socket::close() throw (SocketException)
{
	if (m_socket == -1)
		return;
#ifdef _WIN32
	::closesocket(m_socket);
#else
	::shutdown(m_socket,SHUT_RDWR);
	::close(m_socket);
#endif
}

void Socket::sleep(int milliseconds)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -