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

📄 gsocket.cpp

📁 一个非常有用的开源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*	Copyright (C) 2006, Mike Gashler	This library is free software; you can redistribute it and/or	modify it under the terms of the GNU Lesser General Public	License as published by the Free Software Foundation; either	version 2.1 of the License, or (at your option) any later version.	see http://www.gnu.org/copyleft/lesser.html*/#include "GSocket.h"#include <time.h>#include "GSpinLock.h"#include "GArray.h"#include "GMacros.h"#include "GThread.h"#include "GString.h"#include "GPointerQueue.h"#include "GBits.h"#include <stdarg.h>#include <wchar.h>#ifdef WIN32#include "GWindows.h"#include <Ws2tcpip.h>#else // WIN32#include <unistd.h>#include <time.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#include <stdlib.h>#include <sys/ioctl.h>#include <errno.h>#define SOCKET_ERROR -1#endif // !WIN32wchar_t* g_wszErrorMessage = NULL;void ThrowError(const wchar_t* wszFormat, ...){	// Measure the required buffer size--todo: there might be a function like "vscwprintf" that does this, but I couldn't find it so I kludged my own	int nSize = 0;	{		va_list args;		const wchar_t* wsz = wszFormat;		va_start(args, wszFormat);		{			while(*wsz != L'\0')			{				if(*wsz == L'%')				{					wsz++;					switch(*wsz)					{						case L'c':							nSize += 2;							va_arg(args, int/*wchar_t*/);							break;						case L's':							nSize += wcslen(va_arg(args, wchar_t*));							break;						case L'd':							nSize += 10;							va_arg(args, int);							break;						case L'l':							nSize += 20;							va_arg(args, double);							break;						case L'f':							nSize += 20;							va_arg(args, double/*float*/);							break;						default:							nSize += 20; // take a guess							break;					}				}				wsz++;				nSize++;			}		}		va_end (args);	}	nSize++;	// Allocate the buffer	delete(g_wszErrorMessage);	g_wszErrorMessage = new wchar_t[nSize + 1];	// Format the message	{		va_list args;		va_start(args, wszFormat);		{#ifdef _MBCS			int res = vswprintf(g_wszErrorMessage, wszFormat, args);#else			int res = vswprintf(g_wszErrorMessage, nSize, wszFormat, args);#endif			if(res < 0)			{				GAssert(false, "Error formatting string");			}		}		va_end (args);	}	// Throw the error	throw (const wchar_t*)g_wszErrorMessage;}const wchar_t* gsocket_GetLastError(){	const wchar_t* wszMsg = NULL;#ifdef WIN32	int n = WSAGetLastError();	switch(n)	{		case WSAECONNRESET: 		wszMsg = L"An incoming connection was indicated, but was subsequently terminated by the remote peer prior to accepting the call."; break;		case WSAEFAULT: 			wszMsg = L"The addrlen parameter is too small or addr is not a valid part of the user address space."; break;		case WSAEINTR: 				wszMsg = L"A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall."; break;		case WSAEINVAL: 			wszMsg = L"The listen function was not invoked prior to accept."; break;		case WSAEINPROGRESS: 		wszMsg = L"A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function."; break;		case WSAEMFILE: 			wszMsg = L"The queue is nonempty upon entry to accept and there are no descriptors available."; break;		case WSAENETDOWN: 			wszMsg = L"The network subsystem has failed."; break;		case WSAENOBUFS: 			wszMsg = L"No buffer space is available."; break;		case WSAENOTSOCK: 			wszMsg = L"The descriptor is not a socket."; break;		case WSAEOPNOTSUPP: 		wszMsg = L"The referenced socket is not a type that supports connection-oriented service."; break;		case WSAEWOULDBLOCK: 		wszMsg = L"The socket is marked as nonblocking and no connections are present to be accepted."; break;		case WSANOTINITIALISED:		wszMsg = L"A successful WSAStartup must occur before using this function.";   break;		case WSAEALREADY:			wszMsg = L"A nonblocking connect call is in progress on the specified socket.";   break;		case WSAEADDRNOTAVAIL:		wszMsg = L"The remote address is not a valid address (such as ADDR_ANY).";   break;		case WSAEAFNOSUPPORT:		wszMsg = L"Addresses in the specified family cannot be used with this socket.";   break;		case WSAECONNREFUSED:		wszMsg = L"The attempt to connect was forcefully rejected.";   break;		case WSAEISCONN:			wszMsg = L"The socket is already connected (connection-oriented sockets only).";   break;		case WSAENETUNREACH:		wszMsg = L"The network cannot be reached from this host at this time.";   break;		case WSAETIMEDOUT:			wszMsg = L"Attempt to connect timed out without establishing a connection.";   break;		case WSASYSNOTREADY:		wszMsg = L"network subsystem not ready for communication.";   break;		case WSAVERNOTSUPPORTED:	wszMsg = L"The version of Windows Sockets support requested is not provided by this implementation.";   break;		case WSAEPROCLIM:			wszMsg = L"Limit on the number of tasks supported has been reached.";   break;		case WSAEHOSTUNREACH:		wszMsg = L"Host unreacheable"; break;		case WSAENOTCONN:			wszMsg = L"Not Connected"; break;		case WSAECONNABORTED:		wszMsg = L"Connection Aborted"; break;		case 0x2740:				wszMsg = L"Port already in use"; break;		case WSAHOST_NOT_FOUND: 	wszMsg = L"Authoritative answer host not found."; break;		case WSATRY_AGAIN: 			wszMsg = L"Nonauthoritative host not found, or server failure."; break;		case WSANO_RECOVERY: 		wszMsg = L"A nonrecoverable error occurred."; break;		case WSANO_DATA: 			wszMsg = L"Valid name, no data record of requested type."; break;		default:					wszMsg = L"An unrecognized socket error occurred"; break;	}#else // WIN32	switch(errno)	{		case EBADF:			wszMsg = L"not a valid socket descriptor."; break;		case EINVAL:		wszMsg = L"The socket is already bound to an address or addrlen is wrong."; break;		case EACCES:		wszMsg = L"Access permission is denied."; break;		case ENOTSOCK:		wszMsg = L"Argument is a descriptor for a file, not a socket."; break;		case EROFS:			wszMsg = L"The  socket inode would reside on a read-only file system."; break;		case EFAULT:		wszMsg = L"the addr parameter points outside the user's accessible address space."; break;		case ENAMETOOLONG:	wszMsg = L"A component of a pathname exceeded {NAME_MAX} characters, or an entire path name exceeded {PATH_MAX} characters."; break;		case ENOENT:		wszMsg = L"The file or named socket does not exist."; break;		case ENOMEM:		wszMsg = L"Insufficient kernel memory was available."; break;		case ENOTDIR:		wszMsg = L"A component of the path prefix is not a directory."; break;		case ELOOP:			wszMsg = L"Too many symbolic links were encountered in resolving my_addr."; break;		case EOPNOTSUPP:	wszMsg = L"The referenced socket is not of type SOCK_STREAM."; break;		case EWOULDBLOCK:	wszMsg = L"The socket is marked non-blocking and no connections are present to be accepted."; break;		case EMFILE:		wszMsg = L"The per-process descriptor table is full."; break;		case ENFILE:		wszMsg = L"The system file table is full."; break;		case EADDRNOTAVAIL:	wszMsg = L"The specified address is not available on this machine."; break;		case EAFNOSUPPORT:	wszMsg = L"Addresses in the specified address family cannot be used with this socket."; break;		case EISCONN:		wszMsg = L"The socket is already connected."; break;		case ETIMEDOUT:		wszMsg = L"Connection establishment timed out without establishing a connection."; break;		case ECONNREFUSED:	wszMsg = L"The attempt to connect was forcefully rejected."; break;		case ENETUNREACH:	wszMsg = L"The network isn't reachable from this host."; break;		case EADDRINUSE:	wszMsg = L"The address is already in use."; break;		case EINPROGRESS:	wszMsg = L"The socket is non-blocking and the connection cannot be completed immediately.  It is possible to select(2) for completion by selecting the socket for writing."; break;		case EALREADY:		wszMsg = L"The socket is non-blocking and a previous connection attempt has not yet been completed."; break;		case HOST_NOT_FOUND:	wszMsg = L"The specified host is unknown."; break;		case NO_ADDRESS:	wszMsg = L"The requested name is valid but does not have an IP address."; break;		case NO_RECOVERY:	wszMsg = L"A non-recoverable name server error occurred."; break;		//case TRY_AGAIN:		wszMsg = L"A temporary error occurred on an authoritative name server.  Try again later."; break;		default:		wszMsg = L"An unrecognized socket error occurred"; break;	}#endif // else WIN32	return wszMsg;}void gsocket_LogError(){	const wchar_t* wszErrorMessage = gsocket_GetLastError();	ThrowError(wszErrorMessage);}inline void SetSocketToBlockingMode(SOCKET s){	unsigned long ulMode = 0;#ifdef WIN32	if(ioctlsocket(s, FIONBIO, &ulMode) != 0)#else // WIN32	if(ioctl(s, FIONBIO, &ulMode) != 0)#endif // !WIN32	{		gsocket_LogError();	}}inline void SetSocketToNonBlockingMode(SOCKET s){	unsigned long ulMode = 1;#ifdef WIN32	if(ioctlsocket(s, FIONBIO, &ulMode) != 0)#else // WIN32	if(ioctl(s, FIONBIO, &ulMode) != 0)#endif // WIN32		gsocket_LogError();}inline void CloseSocket(SOCKET s){#ifdef WIN32	closesocket(s);#else	close(s);#endif // WIN32}#ifdef WIN32bool gsocket_InitWinSock(){	// Initializing Winsock	WORD wVersionRequested;	WSADATA wsaData;	int err; 	wVersionRequested = MAKEWORD(1, 1); 	err = WSAStartup( wVersionRequested, &wsaData );	if ( err != 0 ) 	{		GAssert(false, "Failed to find a usable WinSock DLL\n");		return false;	}	// Confirm that the WinSock DLL supports 2.2.	// Note that if the DLL supports versions greater	// than 2.2 in addition to 2.2, it will still return	// 2.2 in wVersion since that is the version we	// requested.	if ( LOBYTE( wsaData.wVersion ) != 1 ||			HIBYTE( wsaData.wVersion ) != 1 ) 	{		int n1 = LOBYTE( wsaData.wVersion );		int n2 = HIBYTE( wsaData.wVersion );		GAssert(false, "Found a Winsock DLL, but it only supports an older version.  It needs to support version 2.2");		WSACleanup();		return false; 	}	return true;}#endif // WIN32// ------------------------------------------------------------------------------GSocketClientBase::GSocketClientBase(bool bUDP){	m_hListenThread = BAD_HANDLE;	m_s = INVALID_SOCKET;	m_bKeepListening = true;	m_bUDP = bUDP;#ifdef WIN32	if(!gsocket_InitWinSock())		throw "Error initializing WinSock";#endif // WIN32}GSocketClientBase::~GSocketClientBase(){	Disconnect();}void GSocketClientBase::JoinListenThread(){	m_bKeepListening = false;	time_t tStart;	time_t tNow;	time(&tStart);	while(m_hListenThread != BAD_HANDLE)	{		GThread::sleep(0);		time(&tNow);		if(tNow - tStart > 4)		{			GAssert(false, "Error, took too long for the listen thread to exit");			break;		}	}}void GSocketClientBase::JoinListenThread(int nConnectionNumber){	GAssert(false, "Error, not implemented yet");}void GSocketClientBase::Listen(){	char szReceiveBuff[520];	SOCKET s = m_s;	// Mark the socket as blocking so we can call "recv" which is a blocking operation	SetSocketToBlockingMode(s);	// Start receiving messages	unsigned long dwBytesReadyToRead;	int nBytesRead = 0;	while(m_bKeepListening)	{		// See how much data is ready to be received#ifdef WIN32		GWindows::YieldToWindows(); // This is necessary because incoming packets go through the Windows message pump		if(ioctlsocket(s, FIONREAD, &dwBytesReadyToRead) != 0)			gsocket_LogError();#else // WIN32		if(ioctl(s, FIONREAD, &dwBytesReadyToRead) != 0)			gsocket_LogError();#endif // !WIN32		if(dwBytesReadyToRead > 0)		{			nBytesRead = recv(s, szReceiveBuff, 512, 0); // read from the queue (This blocks until there is some to read or connection is closed, but we already know there is something to read)			if(nBytesRead > 0) // recv reads in as much data as is currently available up to the size of the buffer				Receive((unsigned char*)szReceiveBuff, nBytesRead);			else				break; // The socket has been closed		}		else		{			// There's nothing to receive, so let's sleep for a while			GThread::sleep(50);		}	}#ifdef WIN32	if(nBytesRead == SOCKET_ERROR)	{		int n = WSAGetLastError();		switch(n)		{			case WSAECONNABORTED:	break;			case WSAECONNRESET:		break;			default:				gsocket_LogError();		break;		}	}#endif // WIN32	OnCloseConnection();	shutdown(m_s, 2);	CloseSocket(m_s);	m_s = INVALID_SOCKET;	m_hListenThread = BAD_HANDLE;}unsigned int ListenThread(void* pData){	((GSocketClientBase*)pData)->Listen();	return 0;}/*virtual*/ void GSocketClientBase::OnCloseConnection(){}bool GSocketClientBase::IsThisAnIPAddress(const char* szHost){	int n;	for(n = 0; szHost[n] != '.' && szHost[n] != '\0'; n++)	{		if(szHost[n] < '0' || szHost[n] > '9')			return false;	}	if(szHost[n] == '.')	{		for(n++; szHost[n] != '.' && szHost[n] != '\0'; n++)		{			if(szHost[n] < '0' || szHost[n] > '9')				return false;		}	}	return true;}// This is for parsing a URL//staticvoid GSocketClientBase::ParseURL(const char* szUrl, int* pnHostIndex, int* pnPortIndex, int* pnPathIndex, int* pnParamsIndex){	// Find the host	int nHost = 0;	int i;	for(i = 0; szUrl[i] != ':' && szUrl[i] != '?' && szUrl[i] != '\0'; i++)	{	}	if(strncmp(&szUrl[i], "://", 3) == 0)		nHost = i + 3;	// Find the port	int nPort = -1;	for(i = nHost; szUrl[i] != ':' && szUrl[i] != '?' && szUrl[i] != '\0'; i++)	{	}	if(szUrl[i] == ':')		nPort = i;	// Find the path	int nPath;	for(nPath = MAX(nHost, nPort); szUrl[nPath] != '/' && szUrl[nPath] != '?' && szUrl[nPath] != '\0'; nPath++)	{	}	if(nPort < 0)		nPort = nPath;	// Find the params	if(pnParamsIndex)	{		int nParams;		for(nParams = nPath; szUrl[nParams] != '?' && szUrl[nParams] != '\0'; nParams++)		{		}		*pnParamsIndex = nParams;	}	// Set the return values	if(pnHostIndex)		*pnHostIndex = nHost;	if(pnPortIndex)		*pnPortIndex = nPort;	if(pnPathIndex)		*pnPathIndex = nPath;}//staticint GSocketClientBase::ParseUrlParams(const char* szParams, int nMaxParams, char** pNames, int* pNameLengths, char** pValues, int* pValueLengths){	if(*szParams == '?')		szParams++;	int nParams = 0;	while(true)	{		if(*szParams == '\0' || nParams >= nMaxParams)			return nParams;		pNames[nParams] = (char*)szParams;		pNameLengths[nParams] = 0;		while(*szParams != '\0' && *szParams != '=' && *szParams != '&')		{			szParams++;			pNameLengths[nParams]++;		}		if(*szParams == '=')			szParams++;		pValues[nParams] = (char*)szParams;		pValueLengths[nParams] = 0;		while(*szParams != '\0' && *szParams != '&')		{			szParams++;			pValueLengths[nParams]++;		}		if(*szParams == '&')			szParams++;		nParams++;	}}/*in_addr GSocketClientBase::StringToAddr(const char* szURL){	// Extract the host and port from the URL	GTEMPBUF(szHost, strlen(szURL));	ParseURL(szURL, NULL, szHost, NULL, NULL, NULL);	// Determine if it is a friendly-URL or an IP address	if(IsThisAnIPAddress(szHost))	{		in_addr iaTmp;#ifdef WIN32		iaTmp.S_un.S_addr = inet_addr(szHost);#else // WIN32		iaTmp.s_addr = inet_addr(szHost);#endif // else WIN32		return iaTmp;	}	else	{		struct hostent* psh = gethostbyname(szHost);		if(!psh)		{			gsocket_LogError();			in_addr iaTmp;#ifdef WIN32			iaTmp.S_un.S_addr = NULL;#else // WIN32            iaTmp.s_addr = 0;#endif // else WIN32			return iaTmp;		}		return *(in_addr*)psh->h_addr_list[0];	}}*/bool GSocketClientBase::Connect(const char* szHost, unsigned short nPort){	// *** If you use VisualStudio 6.0 and you get an error that	// says 'hints' uses undefined struct 'addrinfo' on the next	// code line then you need to get the Feb 2003 update of the	// Platform SDK. (This is the last version that supports VS6).	struct addrinfo hints, *res, *res0;	int error;	memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_UNSPEC;	hints.ai_socktype = SOCK_STREAM;	char szPort[32];	itoa(nPort, szPort, 10);	error = getaddrinfo(szHost, szPort, &hints, &res0);	if (error)	{		GAssert(false, gai_strerror(error));		gsocket_LogError();	}	m_s = INVALID_SOCKET;	for(res = res0; res; res = res->ai_next)	{//printf("Attempting to connect to %d.%d.%d.%d on port %d... ", ((unsigned char*)&res->ai_addr->sa_data)[2], ((unsigned char*)&res->ai_addr->sa_data)[3], ((unsigned char*)&res->ai_addr->sa_data)[4], ((unsigned char*)&res->ai_addr->sa_data)[5], nPort);

⌨️ 快捷键说明

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