📄 netplay.cpp
字号:
}
// Frame control
// 懍偡偓偐丠
if( m_nRecvSize < SOCKET_BLOCK_SIZE ) {
return -1; // 彮偟懸偭偰偔傟
}
// 抶偡偓偐丠
if( m_nRecvSize > ((m_nLatency+2)*SOCKET_BLOCK_SIZE) ) {
return 1; // 彮偟恑傔偰偔傟
}
return 0;
}
// 摨婜慜張棟(儗僀僥儞僔偺暘偩偗愭偵憲怣偟偰摨婜傪庢傞)
INT CNetPlay::Sync()
{
BYTE senddata[SOCKET_BLOCK_SIZE];
DEBUGOUT( "CNetPlay::Sync\n" );
ZEROMEMORY( senddata, sizeof(senddata) );
m_nFrameCount = 0;
m_nRingPtr = m_nSendPtr = m_nRecvPtr = 0;
m_nRecvSize = 0;
DEBUGOUT( "CNetPlay::Sync sending...\n" );
// 僨乕僞憲怣
for( INT i = 0; i < m_nLatency+1; i++ ) {
while( TRUE ) {
if( ::send( m_SocketData, (char*)senddata, SOCKET_BLOCK_SIZE, 0 ) == SOCKET_ERROR ) {
// 僽儘僢僋偝傟偨偐傕抦傟側偄偺偱嵞搙挧愴
if( ::WSAGetLastError() == WSAEWOULDBLOCK ) {
DEBUGOUT( "send::WSAEWOULDBLOCK!!\n" );
::Sleep(0); // 屌傑傜側偄慬抲
continue;
} else {
// 抳柦揑僄儔乕偭傐偄
DEBUGOUT( "CNetPlay:Sync send failed. [%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
Disconnect();
return -1L;
}
} else {
break;
}
}
m_nSendPtr = (m_nSendPtr+SOCKET_BLOCK_SIZE) & SOCKET_BUFFER_SIZE-1;
}
// 憡庤僨乕僞偺僶僢僼傽儕儞僌僨乕僞懸偪(10昩偱僞僀儉傾僂僩)
DWORD dwTime = ::timeGetTime();
while( m_nRecvSize < (m_nLatency+1)*SOCKET_BLOCK_SIZE ) {
if( !RecvBuffer() ) {
DEBUGOUT( "CNetPlay:recv error.\n" );
Disconnect();
return -1;
}
if( (::timeGetTime()-dwTime) > 10*1000 ) {
DEBUGOUT( "CNetPlay:Sync recv timeout.\n" );
Disconnect();
return -1;
}
::Sleep( 1 );
}
DEBUGOUT( "CNetPlay::Sync OK!\n" );
return 0;
}
// 僾儗僀儎乕僉乕偺峏怴
INT CNetPlay::ModifyPlayer( LPBYTE p1, LPBYTE p2 )
{
if( !m_hWnd || !m_bConnect || m_SocketData == INVALID_SOCKET )
return -1L;
// 憲傞傋偒億僀儞僩偱憲怣
if( m_nFrameCount == 0 ) {
while( TRUE ) {
if( ::send( m_SocketData, (char*)p1, SOCKET_BLOCK_SIZE, 0 ) == SOCKET_ERROR ) {
// 僽儘僢僋偝傟偨偐傕抦傟側偄偺偱嵞搙挧愴
if( ::WSAGetLastError() == WSAEWOULDBLOCK ) {
DEBUGOUT( "send::WSAEWOULDBLOCK!!\n" );
::Sleep(0); // 屌傑傜側偄慬抲
continue;
} else {
// 抳柦揑僄儔乕偭傐偄
DEBUGOUT( "CNetPlay:ModifyPlayer send failed. code=%d\n", ::WSAGetLastError() );
Disconnect();
return -1L;
}
} else {
break;
}
}
// 僶僢僼傽偵曻傝崬傓
for( INT i = 0; i < SOCKET_BLOCK_SIZE; i++ ) {
m_SendBuffer[ m_nSendPtr ] = p1[i];
m_nSendPtr = (m_nSendPtr+1) & SOCKET_BUFFER_SIZE-1;
}
}
// 憡庤僨乕僞懸偪(10昩偱僞僀儉傾僂僩)
DWORD dwTime = ::timeGetTime();
while( m_nRecvSize < SOCKET_BLOCK_SIZE ) {
if( !RecvBuffer() ) {
DEBUGOUT( "CNetPlay:ModifyPlayer recv error.\n" );
Disconnect();
return -1;
}
if( (::timeGetTime()-dwTime) > 10*1000 ) {
DEBUGOUT( "CNetPlay:ModifyPlayer recv timeout.\n" );
Disconnect();
return -1;
}
::Sleep( 1 );
}
// 忣曬峏怴
INT p = m_nRingPtr;
for( INT i = 0; i < SOCKET_BLOCK_SIZE; i++ ) {
p1[i] = m_SendBuffer[ p ];
p2[i] = m_RecvBuffer[ p ];
p = (p+1) & SOCKET_BUFFER_SIZE-1;
}
INT Count = m_nFrameCount;
// 僗僥僢僾峏怴
if( ++m_nFrameCount > m_nFrameStep ) {
m_nFrameCount = 0;
m_nRingPtr = (m_nRingPtr+SOCKET_BLOCK_SIZE) & SOCKET_BUFFER_SIZE-1;
m_nRecvSize -= SOCKET_BLOCK_SIZE;
}
return Count;
}
void CNetPlay::ChatSend( LPCSTR lpStr )
{
if( !m_hWnd || !m_bConnect || m_SocketChat == INVALID_SOCKET )
return;
if( m_bServer ) {
DEBUGOUT( "ChatSend Server:%s", lpStr );
if( ::sendto( m_SocketChat, (char*)lpStr, ::strlen(lpStr)+1, 0, (struct sockaddr *)&m_SAddr_Client, sizeof(m_SAddr_Client) ) == SOCKET_ERROR ) {
DEBUGOUT( "ChatSend failed. Server:[%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
}
} else {
DEBUGOUT( "ChatSend Client:%s", lpStr );
if( ::sendto( m_SocketChat, (char*)lpStr, ::strlen(lpStr)+1, 0, (struct sockaddr *)&m_SAddr_Server, sizeof(m_SAddr_Server) ) == SOCKET_ERROR ) {
DEBUGOUT( "ChatSend failed. Server:[%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
}
}
}
HRESULT CNetPlay::WndProc( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
// 僄儔乕丠
if( WSAGETSELECTERROR(lParam) ) {
DEBUGOUT( "CNetPlay::WndProc error.[%s]\n", SocketErrorDump( WSAGETSELECTERROR(lParam) ) );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_CLOSE, 0, 0 );
}
return 0L;
}
switch( WSAGETSELECTEVENT(lParam) ) {
case FD_ACCEPT: {
DEBUGOUT( "Accepting...." );
ZEROMEMORY( &m_SAddr_Client, sizeof(m_SAddr_Client) );
int len = sizeof(m_SAddr_Client);
m_SocketData = ::accept( m_SocketConnect, (sockaddr*)&m_SAddr_Client, &len );
// 愙懕梡僜働僢僩偼暵偠傞
::shutdown( m_SocketConnect, SD_BOTH );
CLOSESOCKET( m_SocketConnect );
if( m_SocketData == INVALID_SOCKET ) {
DEBUGOUT( "failed.\n" );
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
DEBUGOUT( "done.\n" );
// Nagle傾儖僑儕僘儉偺柍岠壔
unsigned long ulOpt = 1;
if( ::setsockopt( m_SocketData, IPPROTO_TCP, TCP_NODELAY, (const char*)&ulOpt, sizeof(ulOpt) ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:setsockopt failed.\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
// 僽儘僢僉儞僌儌乕僪愝掕
unsigned long ulArg = 1;
if( ::ioctlsocket( m_SocketData, FIONBIO, &ulArg ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:ioctlsocket failed.\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
// 旕摨婜僀儀儞僩偺愝掕
if( ::WSAAsyncSelect( m_SocketChat, m_hWnd, WM_NETPLAY, FD_READ ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.[CONNECT chat]\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
// 旕摨婜僀儀儞僩偺愝掕
if( ::WSAAsyncSelect( m_SocketData, m_hWnd, WM_NETPLAY, FD_CLOSE ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.[ACCEPT data]\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
m_bConnect = TRUE;
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ACCEPT, 0, 0 );
}
break;
}
case FD_CONNECT: {
DEBUGOUT( "Connection done.\n" );
// 1僶僀僩偩偗僟儈乕僨乕僞傪憲傞(壗偐娫堘偭偰傞婥傕偡傞乧)
if( ::sendto( m_SocketChat, (char*)"", 1, 0, (struct sockaddr *)&m_SAddr_Server, sizeof(m_SAddr_Server) ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:send failed. Client:[%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
// 旕摨婜僀儀儞僩偺愝掕
if( ::WSAAsyncSelect( m_SocketChat, m_hWnd, WM_NETPLAY, FD_READ ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.[CONNECT chat]\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
// 旕摨婜僀儀儞僩偺愝掕
if( ::WSAAsyncSelect( m_SocketData, m_hWnd, WM_NETPLAY, FD_CLOSE ) == SOCKET_ERROR ) {
DEBUGOUT( "CNetPlay:WSAAsyncSelect failed.[CONNECT data]\n" );
Disconnect();
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_ERROR, 0, 0 );
}
return 0L;
}
m_bConnect = TRUE;
if( m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_CONNECT, 0, 0 );
}
break;
}
case FD_CLOSE: {
DEBUGOUT( "Connection close.\n" );
if( m_bConnect && m_hWndMsg ) {
::PostMessage( m_hWndMsg, WM_NETPLAY_CLOSE, 0, 0 );
}
Disconnect();
break;
}
case FD_READ: {
// error is ignored :p
// DEBUGOUT( "FD_READ\n" );
INT recvsize = 0;
INT size = sizeof(struct sockaddr_in);
CHAR szBuf[256+1];
if( m_bServer ) {
recvsize = ::recvfrom( m_SocketChat, (char*)szBuf, sizeof(szBuf)-1, 0, (struct sockaddr *)&m_SAddr_Client, &size );
} else {
recvsize = ::recvfrom( m_SocketChat, (char*)szBuf, sizeof(szBuf)-1, 0, (struct sockaddr *)&m_SAddr_Server, &size );
}
if( recvsize == SOCKET_ERROR ) {
if( m_bServer ) {
DEBUGOUT( "FD_READ failed. Server [%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
} else {
DEBUGOUT( "FD_READ failed. Client [%s]\n", SocketErrorDump( ::WSAGetLastError() ) );
}
} else if( recvsize > 0 ) {
szBuf[recvsize] = '\0';
if( m_hWndChat && ::IsWindow( m_hWndChat ) ) {
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.lpData = (void*)szBuf;
cds.cbData = ::strlen(szBuf)+1; // 廔抂偺NULL傕憲傞
// 暥帤楍憲怣
::SendMessage( m_hWndChat, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds );
}
}
break;
}
default:
DEBUGOUT( "Unknown message.\n" );
break;
}
return 0L;
}
static char* SocketErrorDump( int eno )
{
switch( eno ) {
case 0: return "No error";
#if defined(_DEBUG)||defined(_DEBUGOUT)
case WSAEINTR: return "Interrupted system call";
case WSAEBADF: return "Bad file number";
case WSAEACCES: return "Permission denied";
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open sockets";
case WSAEWOULDBLOCK: return "Operation would block";
case WSAEINPROGRESS: return "Operation now in progress";
case WSAEALREADY: return "Operation already in progress";
case WSAENOTSOCK: return "Socket operation on non-socket";
case WSAEDESTADDRREQ: return "Destination address required";
case WSAEMSGSIZE: return "Message too long";
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAEOPNOTSUPP: return "Operation not supported on socket";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT: return "Address family not supported";
case WSAEADDRINUSE: return "Address already in use";
case WSAEADDRNOTAVAIL: return "Can't assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Net connection reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Can't send after socket shutdown";
case WSAETOOMANYREFS: return "Too many references, can't splice";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAELOOP: return "Too many levels of symbolic links";
case WSAENAMETOOLONG: return "File name too long";
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAENOTEMPTY: return "Directory not empty";
case WSAEPROCLIM: return "Too many processes";
case WSAEUSERS: return "Too many users";
case WSAEDQUOT: return "Disc quota exceeded";
case WSAESTALE: return "Stale NFS file handle";
case WSAEREMOTE: return "Too many levels of remote in path";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSASYSNOTREADY: return "Network system is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock version out of range";
case WSANOTINITIALISED: return "WSAStartup not yet called";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSATRY_AGAIN: return "WSATRY_AGAIN";
case WSANO_RECOVERY: return "WSANO_RECOVERY";
case WSANO_DATA: return "No host data of that type was found";
#endif
default: return "Unknown";
break;
}
return "";
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -