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

📄 socketcomm.cpp

📁 网络通信方面的代码书非常经典欢迎大家下载并学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			if (uOptions & SO_REUSEADDR)
			{
				//设定相关选项
				BOOL optval = TRUE;
				if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof( BOOL ) ) )
				{
					closesocket( sock );
					return false;
				}
			}
			//如果是UDP协议
			if (nType == SOCK_DGRAM)
			{
				//如果允许广播
				if (uOptions & SO_BROADCAST)
				{
					// 允许广播
					BOOL optval = TRUE;
					if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof( BOOL ) ) )
					{
						closesocket( sock );
						return false;
					}

					// 设定变量
					m_bBroadcast = true;
				}

				// 如果需要广播,则需要设定进程互斥
				m_hMutex = CreateMutex(NULL, FALSE, NULL);
				if (NULL == m_hMutex)
				{
					closesocket( sock );
					return false;
				}

			}

			// 绑定一个本地地址
			if ( SOCKET_ERROR == bind(sock, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)))
			{
				closesocket( sock );
				m_bBroadcast = false;
				if (NULL != m_hMutex)
					CloseHandle( m_hMutex );
				m_hMutex = NULL;
				return false;
			}

			// 如果是TCP连接
			if (SOCK_STREAM == nType)
			{
				if ( SOCKET_ERROR == listen(sock, SOMAXCONN))
				{
					closesocket( sock );
					return false;
				}
			}

			// 保存socket
			m_hComm = (HANDLE) sock;
			return true;
		}
		else
			SetLastError(ERROR_INVALID_PARAMETER); //不能找到端口

		// 删除socket
		closesocket( sock );
	}

	return false;
}


///////////////////////////////////////////////////////////////////////////////
// ConnectTo
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//				Establish connection with a server service or port
// PARAMETERS:
//	LPCTSTR strDestination: hostname or address to connect (in .dot format)
//	LPCTSTR strServiceName: Service name or port number
//	int nProtocol: protocol to use (set to AF_INET)
//	int nType: type of socket to create (SOCK_STREAM, SOCK_DGRAM)
///////////////////////////////////////////////////////////////////////////////

//建立连接
bool CSocketComm::ConnectTo(LPCTSTR strDestination, LPCTSTR strServiceName, int nProtocol, int nType)
{
	// 如果socket已经打开
	if ( IsOpen() )
		return false;

	SOCKADDR_IN sockAddr = { 0 };

	//创建一个socket
	SOCKET sock = socket(nProtocol, nType, 0);
	if (INVALID_SOCKET != sock)
	{
		// 让socket绑定一个地址
		TCHAR strHost[HOSTNAME_SIZE] = { 0 };
		if (false == CSocketComm::GetLocalName( strHost, sizeof(strHost)/sizeof(TCHAR)))
		{
			closesocket( sock );
			return false;
		}
		//AfxMessageBox(strHost);
		sockAddr.sin_addr.s_addr = htonl( CSocketComm::GetIPAddress( strHost ) );
		sockAddr.sin_family = nProtocol;

		if ( SOCKET_ERROR == bind(sock, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)))
		{
			closesocket( sock );
			return false;
		}

		// 获得目标地址
		if ( strDestination[0]) {
			sockAddr.sin_addr.s_addr = htonl(CSocketComm::GetIPAddress( strDestination ) );
		}

		// 获得端口
		sockAddr.sin_port = htons( GetPortNumber( strServiceName ) );
		if ( 0 != sockAddr.sin_port )
		{
			// 连接服务器
			if (SOCKET_ERROR == connect( sock, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)))
			{
				closesocket( sock );
				return false;
			}

			// 保存socket
			m_hComm = (HANDLE) sock;
			return true;
		}
	}
	return false;
}


///////////////////////////////////////////////////////////////////////////////
// CloseComm
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		Close Socket Communication
// PARAMETERS:
//		None
///////////////////////////////////////////////////////////////////////////////

//关闭socket
void CSocketComm::CloseComm()
{
	if (IsOpen())
	{
		//调用ShutdownConnection关闭
		ShutdownConnection((SOCKET)m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
		m_bBroadcast = false;
	}
}


///////////////////////////////////////////////////////////////////////////////
// WatchComm
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		Starts Socket Communication Working thread
// PARAMETERS:
//		None
///////////////////////////////////////////////////////////////////////////////

//启动socket通信线程
bool CSocketComm::WatchComm()
{
	//首先判断是否启动
	if (!IsStart())
	{
		//判断是否打开通信,即socket是否成功创建
		if (IsOpen())
		{
			HANDLE hThread;
			UINT uiThreadId = 0;
			//启动线程,使用_beginthreadex
			hThread = (HANDLE)_beginthreadex(NULL,	// 安全参数
									  0,	// 堆栈
						SocketThreadProc,	// 线程程序
									this,	// 线程参数
						CREATE_SUSPENDED,	//创建模式
							&uiThreadId);	// 线程ID
			//如果线程不为空
			if ( NULL != hThread)
			{
				//继续线程
				ResumeThread( hThread );
				m_hThread = hThread;
				return true;
			}
		}
	}
	return false;
}


///////////////////////////////////////////////////////////////////////////////
// StopComm
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		Close Socket and Stop Communication thread
// PARAMETERS:
//		None
///////////////////////////////////////////////////////////////////////////////
void CSocketComm::StopComm()
{
	// Close Socket
	if (IsOpen())
	{
		CloseComm();
		Sleep(50);
	}

	// Kill Thread
	if (IsStart())
	{
		if (WaitForSingleObject(m_hThread, 5000L) == WAIT_TIMEOUT)
			TerminateThread(m_hThread, 1L);
		CloseHandle(m_hThread);
		m_hThread = NULL;
	}

	// Clear Address list
	if (!m_AddrList.empty())
		m_AddrList.clear();

	// Destroy Synchronization objects
	if (NULL != m_hMutex)
	{
		CloseHandle( m_hMutex );
		m_hMutex = NULL;
	}

}


///////////////////////////////////////////////////////////////////////////////
// ReadComm
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		Reads the Socket Communication
// PARAMETERS:
//		LPBYTE lpBuffer: buffer to place new data
//		DWORD dwSize: maximum size of buffer
//		DWORD dwTimeout: timeout to use in millisecond
///////////////////////////////////////////////////////////////////////////////

//读入数据
DWORD CSocketComm::ReadComm(LPBYTE lpBuffer, DWORD dwSize, DWORD dwTimeout)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( lpBuffer != NULL );

	if (lpBuffer == NULL || dwSize < 1L)
		return 0L;

	fd_set	fdRead  = { 0 };
	TIMEVAL	stTime;
	TIMEVAL	*pstTime = NULL;

	if ( INFINITE != dwTimeout ) {
		stTime.tv_sec = 0;
		stTime.tv_usec = dwTimeout*1000;
		pstTime = &stTime;
	}

	SOCKET s = (SOCKET) m_hComm;
	// 设定描述符
	if ( !FD_ISSET( s, &fdRead ) )
		FD_SET( s, &fdRead );

	// 选择函数,设定超时时间
	DWORD dwBytesRead = 0L;
	int res = select( s+1, &fdRead, NULL, NULL, pstTime );
	if ( res > 0)
	{
		if (IsBroadcast() || IsSmartAddressing())
		{
			SOCKADDR_IN sockAddr = { 0 }; // 获得地址
			int nOffset = IsSmartAddressing() ? sizeof(sockAddr) : 0; 
			int nLen = sizeof(sockAddr);
			if ( dwSize < (DWORD) nLen)	// 缓冲区太小
			{
				SetLastError( ERROR_INVALID_USER_BUFFER );
				return -1L;
			}
			//获得数据
			res = recvfrom( s, (LPSTR)&lpBuffer[nOffset], dwSize, 0, (LPSOCKADDR)&sockAddr, &nLen);

			// clear 'sin_zero', we will ignore them with 'SockAddrIn' anyway!
			memset(&sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
			
			if ( res >= 0)
			{
				LockList(); //锁定地址列表 

				// 删除调重复地址
				SockAddrIn sockin;
				sockin.SetAddr( &sockAddr );
				m_AddrList.remove( sockin );
				m_AddrList.insert(m_AddrList.end(), sockin);
				
				if (IsSmartAddressing())
				{
					memcpy(lpBuffer, &sockAddr, sizeof(sockAddr));
					res += sizeof(sockAddr);
				}

				UnlockList(); // 解开地址列表
			}
		}
		else
		{
			res = recv( s, (LPSTR)lpBuffer, dwSize, 0);
		}

		dwBytesRead = (DWORD)((res > 0)?(res) : (-1));
	}

	return dwBytesRead;
}


///////////////////////////////////////////////////////////////////////////////
// WriteComm
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		Writes data to the Socket Communication
// PARAMETERS:
//		const LPBYTE lpBuffer: data to write
//		DWORD dwCount: maximum characters to write
//		DWORD dwTimeout: timeout to use in millisecond
///////////////////////////////////////////////////////////////////////////////

//发送数据
DWORD CSocketComm::WriteComm(const LPBYTE lpBuffer, DWORD dwCount, DWORD dwTimeout)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( NULL != lpBuffer );

	// 如果没有建立连接或者缓冲区为空,则返回
	if (!IsOpen() || NULL == lpBuffer)
		return 0L;
	//fd_set 是一个结构体,可以被很多的windows socket函数使用,如select,在socket2.0中使用
	//typedef struct fd_set {
	//u_int    fd_count;                 // 数量
	//SOCKET   fd_array[FD_SETSIZE];     //socket 数组
	//} fd_set;

	fd_set	fdWrite  = { 0 };
	TIMEVAL	stTime;
	TIMEVAL	*pstTime = NULL;

	if ( INFINITE != dwTimeout ) {
		stTime.tv_sec = 0;
		stTime.tv_usec = dwTimeout*1000;
		pstTime = &stTime;
	}

	SOCKET s = (SOCKET) m_hComm;
	// 设定描述符
	if ( !FD_ISSET( s, &fdWrite ) )
		FD_SET( s, &fdWrite );

	// 选择函数设定超时时间
	DWORD dwBytesWritten = 0L;
	int res = select( s+1, NULL, &fdWrite, NULL, pstTime );
	if ( res > 0)
	{
		// 发送消息广播或者点对点发送
		if (IsBroadcast() || IsSmartAddressing())
		{
			// use offset for Smart addressing
			int nOffset = IsSmartAddressing() ? sizeof(SOCKADDR_IN) : 0;
			if (IsSmartAddressing())
			{
				if ( dwCount < sizeof(SOCKADDR_IN))	// error - buffer to small
				{
					SetLastError( ERROR_INVALID_USER_BUFFER );
					return -1L;
				}

				// 从缓冲区中获得地址
				SockAddrIn sockAddr;
				sockAddr.SetAddr((SOCKADDR_IN*) lpBuffer);

				// 获得地址然后发送
				if (sockAddr.sockAddrIn.sin_addr.s_addr != htonl(INADDR_BROADCAST))
				{
					res = sendto( s, (LPCSTR)&lpBuffer[nOffset], dwCount-nOffset, 0,
						(LPSOCKADDR)sockAddr, sockAddr.Size());
					dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
					return dwBytesWritten;
				}
			}

			// 向所有用户广播
			LockList(); // 锁住地址列表
			
			CSockAddrList::iterator iter = m_AddrList.begin();
			for( ; iter != m_AddrList.end(); )
			{
				//循环发送信息
				res = sendto( s, (LPCSTR)&lpBuffer[nOffset], dwCount-nOffset, 0, (LPSOCKADDR)(*iter), iter->Size());
				if (res < 0)
				{
					CSockAddrList::iterator deladdr = iter;
					++iter;	// 下一个
					m_AddrList.erase( deladdr );
				}
				else
					++iter;	// 下一个
			}

			UnlockList(); // 解锁

			// UDP总是返回true
			res = (int) dwCount - nOffset;
		}
		else // 发送到单个客户端
			res = send( s, (LPCSTR)lpBuffer, dwCount, 0);

		dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
	}

	return dwBytesWritten;
}


///////////////////////////////////////////////////////////////////////////////
// Run
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//		This function runs the main thread loop
//		this implementation can be overloaded.
//      This function calls CSocketComm::OnDataReceived() (Virtual Function)
// PARAMETERS:
// NOTES:
//		You should not wait on the thread to end in this function or overloads
///////////////////////////////////////////////////////////////////////////////

//该函数由主线程来循环调用
void CSocketComm::Run()
{
	BYTE	buffer[BUFFER_SIZE];
	DWORD	dwBytes  = 0L;

	HANDLE	hThread = GetCurrentThread();
	DWORD	dwTimeout = DEFAULT_TIMEOUT;

	// 是否运行服务器模式
	if (IsServer())
	{
		//是否广播模式
		if (!IsBroadcast())
		{
			SOCKET sock = (SOCKET) m_hComm;
			sock = WaitForConnection( sock );

			// 等待新的连接
			if (sock != INVALID_SOCKET)
			{
				//关闭连接
				ShutdownConnection( (SOCKET) m_hComm);
				m_hComm = (HANDLE) sock;
				OnEvent( EVT_CONSUCCESS ); // connect
			}
			else
			{
				// 如果已经关闭则不发送事件,否则发送
				if (IsOpen())
					OnEvent( EVT_CONFAILURE ); // 等待失败
				return;
			}
		}
	}

	//如果socket已经创建
	while( IsOpen() )
	{
		// 采用阻塞式socket,等待事件通知
		dwBytes = ReadComm(buffer, sizeof(buffer), dwTimeout);

		// 如果有错误发生
		if (dwBytes == (DWORD)-1)
		{
			// 如果要关闭,则不发送事件
			if (IsOpen())
				OnEvent( EVT_CONDROP ); // 失去连接
			break;
		}

		// 是否有数据收到
		if (IsSmartAddressing() && dwBytes == sizeof(SOCKADDR_IN))
			OnEvent( EVT_ZEROLENGTH );
		else if (dwBytes > 0L)
		{
			OnDataReceived( buffer, dwBytes);
		}

		Sleep(0);
	}
}


///////////////////////////////////////////////////////////////////////////////
// SocketThreadProc
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
//     Socket Thread function.  This function is the main thread for socket
//     communication - Asynchronous mode.
// PARAMETERS:
//     LPVOID pParam : Thread parameter - a CSocketComm pointer
// NOTES:
///////////////////////////////////////////////////////////////////////////////

//socket线程
UINT WINAPI CSocketComm::SocketThreadProc(LPVOID pParam)
{
	//reinterpret_cast用于各种指针的转化
	CSocketComm* pThis = reinterpret_cast<CSocketComm*>( pParam );
	_ASSERTE( pThis != NULL );

	pThis->Run();

	return 1L;
} 

⌨️ 快捷键说明

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