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

📄 netplay.cpp

📁 著名的任天堂FC游戏机模拟器VirtuaNes 085版的源码!
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 僱僢僩僾儗僀僋儔僗
//
// 柧帵揑偵WinSock Lib傪儕儞僋
#pragma comment(lib, "wsock32.lib")

#include "DebugOut.h"
#include "NetPlay.h"

#define	CLOSESOCKET(soc) if((soc)!=INVALID_SOCKET){::closesocket((soc));(soc)=INVALID_SOCKET;}

static	char*	SocketErrorDump( int eno );

CNetPlay	NetPlay;

CNetPlay::CNetPlay()
{
	m_hWnd = m_hWndMsg = m_hWndChat = NULL;
	m_bConnect = FALSE;

	m_SocketConnect = INVALID_SOCKET;
	m_SocketData = INVALID_SOCKET;
	m_SocketChat = INVALID_SOCKET;

	m_nLatency = 0;
	m_nFrameCount = 0;
	m_nFrameStep = 0;

	m_hASyncTask = NULL;
}

CNetPlay::~CNetPlay()
{
	// 偲傝偁偊偢
	Release();
}

BOOL	CNetPlay::Initialize( HWND hWnd )
{
	// 偲傝偁偊偢
	Release();

	// WinSock DLL偺弶婜壔
	if( ::WSAStartup( MAKEWORD(1,1), &m_WSAdata ) )
		return	FALSE;

	// 僶乕僕儑儞堘偆偠傖乣傫
	if( m_WSAdata.wVersion != MAKEWORD(1,1) ) {
		::WSACleanup();
		return	FALSE;
	}

	m_hWnd = hWnd;
	return	TRUE;
}

void	CNetPlay::Release()
{
	Disconnect();

	if( m_hWnd ) {
		::WSACleanup();
		m_hWnd = NULL;
	}
}

INT	CNetPlay::ASyncHostCheck( HWND hWnd, const char* lpszHost )
{
DEBUGOUT( "CNetPlay:ASyncHostCheck [%s]\n", lpszHost );

	unsigned long IP_address = ::inet_addr( lpszHost );
	if( IP_address != INADDR_NONE ) {
		DEBUGOUT( "CNetPlay:惗IP偭偡\n" );
		return	0;
	}

	m_hWndASync = hWnd;

	// 儂僗僩専嶕奐巒
	m_hASyncTask = ::WSAAsyncGetHostByName( hWnd, WM_NETPLAY_HOSTBYNAME, lpszHost, m_HostEntry, MAXGETHOSTSTRUCT );

	if( m_hASyncTask ) {
		return	1;
	}

	return	-1;
}

HRESULT	CNetPlay::ASyncWndProc( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
DEBUGOUT( "CNetPlay:ASyncWndProc\n" );

	if( WSAGETASYNCERROR(lParam) ) {
DEBUGOUT( "CNetPlay:ASyncWndProc error.[%s]\n", SocketErrorDump( WSAGETASYNCERROR(lParam) ) );
		m_hWndASync = NULL;
		return	0;
	}

	if( m_hASyncTask == (HANDLE)wParam ) {
		if( m_hWndASync ) {
			m_hWndASync = NULL;

			return	*((unsigned long *)((((struct hostent FAR *)m_HostEntry)->h_addr_list)[0]));
		}
	}

	return	0L;
}

BOOL	CNetPlay::Connect( BOOL bServer, const char* lpszIP, unsigned short Port )
{
	if( !m_hWnd )
		return	FALSE;

	m_bServer = bServer;

	if( bServer ) {
	// Server
		// 愙懕捠抦僜働僢僩嶌惉
		if( m_SocketConnect == INVALID_SOCKET ) {
			m_SocketConnect = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
			if( m_SocketConnect == INVALID_SOCKET ) {
				DEBUGOUT( "CNetPlay:socket failed.\n" );
				return	FALSE;
			}
		}

		// 嵞棙梡傪嫋壜偟偰傒傞
		unsigned long ulOpt = 1;
		if( ::setsockopt( m_SocketConnect, SOL_SOCKET, SO_REUSEADDR, (const char*)&ulOpt, sizeof(ulOpt) ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:setsockopt failed. (SO_REUSEADDR)\n" );
			CLOSESOCKET( m_SocketConnect );
			return	FALSE;
		}

		// 億乕僩偲寢傃偮偗傞
		ZEROMEMORY( &m_SAddr_Server, sizeof(m_SAddr_Server) );
		m_SAddr_Server.sin_family      = AF_INET;
		m_SAddr_Server.sin_addr.s_addr = ::htonl( INADDR_ANY );
		m_SAddr_Server.sin_port        = ::htons( Port );
		if( ::bind( m_SocketConnect, (struct sockaddr *)&m_SAddr_Server, sizeof(m_SAddr_Server) ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:bind failed.\n" );
			CLOSESOCKET( m_SocketConnect );
			return	FALSE;
		}
//-----------------
		// 僠儍僢僩梡僜働僢僩嶌惉
		m_SocketChat = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
		if( m_SocketChat == INVALID_SOCKET ) {
			DEBUGOUT( "create socket failed.[chat]\n" );
			Disconnect();
			return	FALSE;
		}
		// 億乕僩偵愙懕
		if( ::bind( m_SocketChat, (struct sockaddr *)&m_SAddr_Server, sizeof(m_SAddr_Server) ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:connect failed. [chat]\n" );
			Disconnect();
			return	FALSE;
		}
		// 僽儘僢僉儞僌儌乕僪愝掕
		unsigned long ulArg = 1;
		if( ::ioctlsocket( m_SocketChat, FIONBIO, &ulArg ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:ioctlsocket failed.[chat]\n" );
			Disconnect();
			return	FALSE;
		}
//-----------------
		// 愙懕梫媮僀儀儞僩偺愝掕
		if( ::WSAAsyncSelect( m_SocketConnect, m_hWnd, WM_NETPLAY, FD_ACCEPT ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.\n" );
			CLOSESOCKET( m_SocketConnect );
			return	FALSE;
		}

		// 愙懕梫媮庴晅奐巒偟偰傒傞
		if( ::listen( m_SocketConnect, 1 ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:listen failed.\n" );
			CLOSESOCKET( m_SocketConnect );
			return	FALSE;
		}
	} else {
	// Client
		unsigned long	ulOpt;
		// IP傾僪儗僗丠
		unsigned long IP_address = ::inet_addr( lpszIP );
		if( IP_address == INADDR_NONE ) {
			DEBUGOUT( "CNetPlay:IP傾僪儗僗偑晄惓偱偡丅\"%s\"\n", lpszIP );
			return	FALSE;
		}

		// 僨乕僞捠怣僜働僢僩嶌惉
		m_SocketData = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
		if( m_SocketData == INVALID_SOCKET ) {
			DEBUGOUT( "CNetPlay:socket failed.\n" );
			return	FALSE;
		}

		// 嵞棙梡傪嫋壜偟偰傒傞
		ulOpt = 1;
		if( ::setsockopt( m_SocketData, SOL_SOCKET, SO_REUSEADDR, (const char*)&ulOpt, sizeof(ulOpt) ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:setsockopt failed. (SO_REUSEADDR)\n" );
			CLOSESOCKET( m_SocketData );
			return	FALSE;
		}

		// Nagle傾儖僑儕僘儉偺柍岠壔
		ulOpt = 1;
		if( ::setsockopt( m_SocketData, IPPROTO_TCP, TCP_NODELAY, (const char*)&ulOpt, sizeof(ulOpt) ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:setsockopt failed.\n" );
			CLOSESOCKET( m_SocketData );
			return	FALSE;
		}

		// 僽儘僢僉儞僌儌乕僪愝掕
		unsigned long	ulArg = 1;
		if( ::ioctlsocket( m_SocketData, FIONBIO, &ulArg ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:ioctlsocket failed.\n" );
			CLOSESOCKET( m_SocketData );
			return	FALSE;
		}

//-----------------
		// 僠儍僢僩梡僜働僢僩嶌惉
		m_SocketChat = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
		if( m_SocketChat == INVALID_SOCKET ) {
			DEBUGOUT( "create socket failed.[chat]\n" );
			Disconnect();
			return	FALSE;
		}
		// 僽儘僢僉儞僌儌乕僪愝掕
//		unsigned long ulArg = 1;
		ulArg = 1;
		if( ::ioctlsocket( m_SocketChat, FIONBIO, &ulArg ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:ioctlsocket failed.[chat]\n" );
			Disconnect();
			return	FALSE;
		}
//-----------------

		// 愙懕姰椆僀儀儞僩偺愝掕
		if( ::WSAAsyncSelect( m_SocketData, m_hWnd, WM_NETPLAY, FD_CONNECT ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.\n" );
			CLOSESOCKET( m_SocketData );
			return	FALSE;
		}

		// 愙懕傪梫媮偟偰傒傞
		ZEROMEMORY( &m_SAddr_Server, sizeof(m_SAddr_Server) );
		m_SAddr_Server.sin_family      = AF_INET;
		m_SAddr_Server.sin_addr.s_addr = IP_address;
		m_SAddr_Server.sin_port        = ::htons( Port );
		if( ::connect( m_SocketData, (struct sockaddr *)&m_SAddr_Server, sizeof(m_SAddr_Server) ) == SOCKET_ERROR ) {
			if( ::WSAGetLastError() != WSAEWOULDBLOCK ) {
				DEBUGOUT( "CNetPlay:connect failed.\n" );
				CLOSESOCKET( m_SocketData );
				return	FALSE;
			}
		}
	}

	return	TRUE;
}

void	CNetPlay::Disconnect()
{
#if	defined(_DEBUG)||defined(_DEBUGOUT)
if( m_bConnect ) {
DEBUGOUT( "CNetPlay::Disconnect\n" );
}
#endif
	if( m_hASyncTask ) {
		::WSACancelAsyncRequest( m_hASyncTask );
		m_hASyncTask = NULL;
	}

	// 僜働僢僩傪僔儍僢僩僟僂儞偟偰攋婞
	if( m_SocketConnect != INVALID_SOCKET ) {
		::shutdown( m_SocketConnect, SD_BOTH );
		CLOSESOCKET( m_SocketConnect );
	}
	if( m_SocketData != INVALID_SOCKET ) {
		::shutdown( m_SocketData, SD_BOTH );
		CLOSESOCKET( m_SocketData );
	}
	if( m_SocketChat != INVALID_SOCKET ) {
		::shutdown( m_SocketChat, SD_BOTH );
		CLOSESOCKET( m_SocketChat );
	}

	m_bConnect = FALSE;
}

INT	CNetPlay::Send( BYTE data )
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	-1L;

	while( TRUE ) {
		if( ::send( m_SocketData, (char*)&data, sizeof(BYTE), 0 ) == SOCKET_ERROR ) {
			// 僽儘僢僋偝傟偨偐傕抦傟側偄偺偱嵞搙挧愴
			if( ::WSAGetLastError() == WSAEWOULDBLOCK ) {
				::Sleep(0);	// 屌傑傜側偄慬抲
				continue;
			} else {
			// 抳柦揑僄儔乕偭傐偄
				DEBUGOUT( "CNetPlay:send failed. code=%d\n", ::WSAGetLastError() );
				Disconnect();
				return	-1L;
			}
		} else {
			break;
		}
	}
	return	0L;
}

INT	CNetPlay::Recv( BYTE& data )
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	-1L;

	// 僨乕僞偑撏偄偰偄傞偐傪妋擣
	unsigned long	len = 0;
	if( ::ioctlsocket( m_SocketData, FIONREAD, (unsigned long*)&len ) == SOCKET_ERROR ) {
		DEBUGOUT( "CNetPlay:ioctlsocket failed.\n" );
		Disconnect();
		return	-1L;
	}

	if( !len ) {
		// 僨乕僞偑撏偄偰偄側偄
		return	0L;
	} else {
		// 1僶僀僩撉傒崬傒
		if( ::recv( m_SocketData, (char*)&data, sizeof(BYTE), 0 ) == SOCKET_ERROR ) {
			DEBUGOUT( "CNetPlay:recv failed.\n" );
			Disconnect();
			return	-1L;
		}
	}

	return	len;
}

INT	CNetPlay::RecvTime( BYTE& data, unsigned long timeout )
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	-1L;

	INT	ret;
	DWORD	dwTimeOut = ::timeGetTime();
	while( (ret = NetPlay.Recv( data )) == 0 ) {
		// 屌傑傜側偄慬抲
		::Sleep( 0 );
		// 僞僀儉傾僂僩偺僠僃僢僋
		if( (::timeGetTime()-dwTimeOut) > timeout ) {
			return	-1;
		}
	}
	return	ret;
}

BOOL	CNetPlay::RecvBuffer()
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	FALSE;

	BYTE	buf[SOCKET_RECEIVE_SIZE];
	INT	recvsize = ::recv( m_SocketData, (char*)buf, SOCKET_RECEIVE_SIZE, 0 );
	if( recvsize == 0 ) {
		return	FALSE;
	} else if( recvsize == SOCKET_ERROR ) {
		if( ::WSAGetLastError() == WSAEWOULDBLOCK ) {
			return	TRUE;
		} else {
DEBUGOUT( "CNetPlay::RecvBuffer failed. [%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
			return	FALSE;
		}
	} else {
		INT	p = m_nRecvPtr;
		for( INT i = 0; i < recvsize; i++ ) {
			m_RecvBuffer[p] = buf[i];
			p = (p+1) & SOCKET_BUFFER_SIZE-1;
		}
		m_nRecvPtr = p;
		m_nRecvSize += recvsize;
	}
	return	TRUE;
}

INT	CNetPlay::GetRecvBufferSize()
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	0;

	return	m_nRecvSize;
}

BOOL	CNetPlay::BufferCheck()
{
	if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
		return	0;

	// LAN
	if( m_nLatency == 0 && m_nRecvSize < SOCKET_BLOCK_SIZE ) {
		return	-1;

⌨️ 快捷键说明

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