HRESULT AnimObject::LoadMeshFromXFile(char* filename){ if(!MeshType && !myMesh){ MeshType = new AnimMesh(GetDevice()); if(FAILED(MeshType->LoadModelsFromXFile(filename , false))){ DisplayErrMsg("モデルの読み込みに失敗しました"); return(E_FAIL); } }else{ DisplayErrMsg("すでにモデルが登録されているアニメーションメッシュにモデルを読み込もうとしました。"); return E_FAIL; } oldAnim= MeshType->GetAnimation(0); myMesh = true; return S_OK; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); //生成 App* app = NULL; try{ app = new App(hInstance,FALSE); }catch(char *str){ DisplayErrMsg(str); SAFE_DELETE(app); return(0); } //実行 app->Run(); //消去 SAFE_DELETE(app); return(0); }
DWORD CInternet::GetFileLength(HINTERNET hInt) { TCHAR szErrMsg[512]; char szLength[32]; DWORD dwLength=0,dwBuffLen=sizeof(szLength); if(HttpQueryInfo (hInt, HTTP_QUERY_CONTENT_LENGTH, &szLength,&dwBuffLen, NULL)==FALSE) { _stprintf_s(szErrMsg, TEXT("%s: %d\n"), TEXT("HttpQueryInfo Error"),GetLastError()); OutputDebugString(szErrMsg); DisplayErrMsg(); return 0; } dwLength = (DWORD)atol(szLength); #ifdef _DEBUG wsprintf (szErrMsg, TEXT("File Size %d\n"),dwLength); OutputDebugString(szErrMsg); #endif return dwLength; }
void SendPacket(const int index, const unsigned char* packet) { int retval = 0; OverlapEx *sendOverlap = new OverlapEx; memset(sendOverlap, 0, sizeof(OverlapEx)); sendOverlap->operation = OP_SEND; memset(&sendOverlap->originalOverlap, 0, sizeof(WSAOVERLAPPED)); ZeroMemory(sendOverlap->buffer, MAX_BUFF_SIZE); sendOverlap->wsaBuf.buf = reinterpret_cast<CHAR*>(sendOverlap->buffer); sendOverlap->wsaBuf.len = packet[0]; memcpy(sendOverlap->buffer, packet, packet[0]); Client *clientData = nullptr; gClientInfoSet->Search(index, &clientData); retval = WSASend(clientData->socket, &sendOverlap->wsaBuf, 1, NULL, 0, &sendOverlap->originalOverlap, NULL); if (0 != retval) { int errNo = WSAGetLastError(); if (WSA_IO_PENDING != errNo) DisplayErrMsg("SendPacket :: WSASend", errNo); if (WSAECONNABORTED == errNo) { clientData->isConnect = false; closesocket(clientData->socket); // ToDo : 10054 error 처리 // 각 플레이어에게 플레이어 접속 종료 알림 Packet::Disconnect packet; packet.size = sizeof(Packet::Disconnect); packet.type = PacketType::Disconnect; packet.id = index; BroadcastingExceptIndex(index, reinterpret_cast<unsigned char*>(&packet)); gClientInfoSet->Remove(index); DisplayDebugText("SendPacket :: Process error 10053."); } } return; }
void WorkerThreadFunc(void) { DWORD ioSize, key; OverlapEx *overlap; BOOL result; Client *clientData = nullptr; while (true) { result = GetQueuedCompletionStatus(ghIOCP, &ioSize, reinterpret_cast<PULONG_PTR>(&key), reinterpret_cast<LPOVERLAPPED*>(&overlap), INFINITE); if (false == result || 0 == ioSize) { if (false == result) DisplayErrMsg("WorkerThread :: GetQueuedCompletionStatus Fail !!", GetLastError()); if (WSAENOTSOCK == GetLastError() || ERROR_NETNAME_DELETED == GetLastError() || 0 == ioSize) { gClientInfoSet->Search(key, &clientData); clientData->isConnect = false; closesocket(clientData->socket); // ToDo : 10054 error 처리 // 각 플레이어에게 플레이어 접속 종료 알림 Packet::Disconnect packet; packet.size = sizeof(Packet::Disconnect); packet.type = PacketType::Disconnect; packet.id = key; BroadcastingExceptIndex(key, reinterpret_cast<unsigned char*>(&packet)); gClientInfoSet->Remove(key); std::string debugText = "WorkerThread :: Disconnect " + std::to_string(key) + " client. :("; DisplayDebugText(debugText); } continue; } if (OP_RECV == overlap->operation) { gClientInfoSet->Search(key, &clientData); unsigned char *buf_ptr = overlap->buffer; int remained = ioSize; while (0 < remained) { if (0 == clientData->recvOverlap.packetSize) clientData->recvOverlap.packetSize = buf_ptr[0]; int required = clientData->recvOverlap.packetSize - clientData->previousDataSize; // 패킷을 완성 시킬 수 있는가? 없는가? if (remained >= required) { // 완성을 시킬 수 있는 상황이면 // 패킷을 어떠한 공간에다가 고이 모셔와야 한다. // 그래서 패킷을 완성시키는 저장공간이 별도로 있어야한다. // 데이터가 패킷단위로 오는 것이 아니기 때문에 패킷단위로 처리하고 남은데이터는 그 별도의 공간에 저장해야 // 다음의 온 데이터가 온전하지 못한 채로 오게되면 별도의 공간에 집어넣고 하나의 패킷으로 마저 만들어 주어야 한다. memcpy(clientData->packetBuf + clientData->previousDataSize, buf_ptr, required); // +하는 이유는 지난번에 받은 데이터 이후에 저장을 해야하기 때문에 그 시작위치로 옮겨줌. ProcessPacket(key, clientData->packetBuf); // Packet 처리 remained -= required; // 날아 있는 것은 필요한 것을 제외하고 buf_ptr += required; // ??? clientData->recvOverlap.packetSize = 0; } else { // 패킷을 완성 시킬 수 없는 크기이다. memcpy(clientData->packetBuf + clientData->previousDataSize, buf_ptr, remained); // buf_ptr의 모든 것을 packet에 저장한다. clientData->previousDataSize += remained; // 이전의 데이터가 남아있는 사이즈만큼 늘어났다. remained = 0; // 현재 recv의 남아있는 size는 이미 저장을 해두었으므로 초기화 } } DWORD flags = 0; WSARecv(clientData->socket, &clientData->recvOverlap.wsaBuf, 1, NULL, &flags, reinterpret_cast<LPWSAOVERLAPPED>(&clientData->recvOverlap), NULL); } else if (OP_SEND == overlap->operation) { // ioSize하고 실제 보낸 크기 비교 후 소켓 접속 끊기 BYTE packetType = overlap->buffer[1]; BYTE packetSize = overlap->buffer[0]; if (BeCompeletedSendPacket(packetType, packetSize)) delete overlap; else { std::string debugText = "WorkerThread :: " + std::to_string(key) + " client don't send " + std::to_string(packetType) + "No. packet"; DisplayDebugText(debugText); } } else { DisplayDebugText("WorkerThread :: Unknown Event on worker_thread"); continue; } } return; }
void AcceptThreadFunc(void) { int retval = 0; struct sockaddr_in listenAddr; int newID = -1; SOCKET acceptSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (INVALID_SOCKET == acceptSocket) { DisplayErrMsg("AcceptThread :: acceptSocket Fail !!", WSAGetLastError()); return; } // bind() : 소켓의 지역 IP주소와 지역 포트 번호를 결정, C++11의 bind라는 함수와 혼동 때문에::범위확인 연산자와 같이 사용. // msdn - The bind functio associates a local address with a socket // listenAddr : 소켓 주소 구조체를 지역 IP주소와 지역 포트 번호로 초기화하여 전달한다. // AF_INET : 인터넷 주초 체계(IPv4)를 사용한다는 의미 // INADDR_ANY : 서버의 지역 IP주소를 설정하는데 있어 다음과 같이 설정을 하면 서버가 IP주소를 2 개 이상 보유한 경우 // (multihomed host라고 부름), 클라이언트가 어느 IP 주소로 접속하든 받아들일 수 있음 // bind 함수의 2번째 인자는 항상 (SOCKADDR*)형으로 반환해야 함 ZeroMemory(&listenAddr, sizeof(listenAddr)); listenAddr.sin_family = AF_INET; listenAddr.sin_addr.s_addr = htonl(INADDR_ANY); listenAddr.sin_port = htons(MY_SERVER_PORT); ZeroMemory(&listenAddr.sin_zero, 8); retval = ::bind(acceptSocket, reinterpret_cast<sockaddr*>(&listenAddr), sizeof(listenAddr)); if (SOCKET_ERROR == retval) { DisplayErrMsg("AcceptThread :: bind Fail !!", WSAGetLastError()); exit(1); } // listen() : 소켓의 TCP 포트 상태를 LISTENING으로 바꾼다. 이는 클라이언트 접속을 받아들일 수 있는 상태가 됨을 의미 // msdn - The listen function places a socket in a state in which it is listening for an incomming connection. // SOMAXCONN : 클라이언트의 접속 정보는 연결 큐에 저장되는데, backlog는 이 연결 큐의 길이를 나타냄. // SOMAXCONN의 의미는 하부 프로토콜에서 지원 가능한 최댓값을 사용 listen(acceptSocket, SOMAXCONN); if (SOCKET_ERROR == retval) { DisplayErrMsg("AcceptThread :: listen Fail !!", WSAGetLastError()); exit(1); } while (true) { struct sockaddr_in clientAddr; int addrSize = sizeof(clientAddr); // 접속한 클라이언트의 새 ID // accept() : 접속한 클라이언트와 통신할 수 있도록 새로운 소켓을 생성해서 리턴 또한 접속한 클라이언트의 주소정보도 알려줌 // : 서버입장에서는 원격 IP주소와 원격 포트번호, 클라이언트 입장에서는 지역 IP 주소와 지역 포트 번호 // WSAAccept() : ? // msdn - The WSAAccept function conditionally accepts a connection based on the return value of a condition, // provides quality of service flow specifications, and allows the transfer of connection data. SOCKET newClientSocket = WSAAccept(acceptSocket, reinterpret_cast<sockaddr*>(&clientAddr), &addrSize, NULL, NULL); if (INVALID_SOCKET == newClientSocket) { DisplayErrMsg("AcceptThread :: WSAAccept Fail !!", WSAGetLastError()); break; } // 접속한 클라이언트의 새로운 ID 부여하는 구간 newID++; // Accept를 받은 이후에 등록을 해주어야 함 HANDLE result = CreateIoCompletionPort(reinterpret_cast<HANDLE>(newClientSocket), ghIOCP, newID, 0); if (NULL == result) { DisplayErrMsg("AcceptThread :: CreateIoCompletionPort Fail !!", WSAGetLastError()); closesocket(newClientSocket); continue; } gClientInfoSet->Add(newID); Player playerData; playerData.roomNo = 0; playerData.pos.x = DEFAULT_POS_X; playerData.pos.y = DEFAULT_POS_Y; playerData.pos.z = DEFAULT_POS_Z; gClientInfoSet->Update(newID, playerData); Client *clientData = nullptr; gClientInfoSet->Search(newID, &clientData); clientData->socket = newClientSocket; // error code 64를 해결하기 위한 delay를 줌. Sleep(10); // 새로운 클라이언트 접속 알림 Packet::SetID clientSetIDPacket; clientSetIDPacket.size = sizeof(Packet::SetID); clientSetIDPacket.type = (BYTE)PacketType::SetID; clientSetIDPacket.id = newID; SendPacket(newID, reinterpret_cast<unsigned char*>(&clientSetIDPacket)); // 새로운 소켓 Recv 수행 DWORD flags = 0; // WSARecv() : 5번째, 6번째 두 인자를 NULL 값으로 사용하면 recv() 함수처럼 동기 함수로 동작 retval = WSARecv(newClientSocket, &clientData->recvOverlap.wsaBuf, 1, NULL, &flags, &clientData->recvOverlap.originalOverlap, NULL); if (0 != retval) { int errNo = WSAGetLastError(); if (WSA_IO_PENDING != errNo) { DisplayErrMsg("AcceptThread :: WSARecv", errNo); } } // Output std::string debugText = "AcceptThread :: ID " + std::to_string(newID) + " client Accept Success !!"; DisplayDebugText(debugText); } return; }