• Tidak ada hasil yang ditemukan

Client and Server (DirectX)

N/A
N/A
Protected

Academic year: 2025

Membagikan "Client and Server (DirectX)"

Copied!
30
0
0

Teks penuh

(1)

Client and Server (DirectX)

Client and Server Client and Server

(DirectX) (DirectX)

Vishnu

Vishnu Kotrajaras Kotrajaras

Server scalability

• Your game can handle more players at a time (Over internet, most peer-to- peer can only handle about 6 players)

• All depend on server power

• Too many people-> just upgrade

server (client does not have to do

much configuration)

(2)

Firewalls

• Peer-to-peer needs many holes in the firewall, but firewalls allow only a few ports to open

• Client/server only needs one port open

Simplicity

• Clients only worry about themselves

• Server can be left with a simple interface

• Server can run on many OS

(3)

IDirectPlay8Server Interface

• Initialize COM with CoInitialize()

• Then it must be created with CoCreateInstance()

• The methods are like what you ’ ve seen for peers

IDirectPlay8Server functions (1)

• Initialize- sets up the interface to receive messages for connections

• Close- disconnects and closes the server from the current session

• Host- creates the session in which

clients can connect

(4)

IDirectPlay8Server functions (2)

• SendTo- transmits data to one or many players within the session

• EnumServiceProviders- enumerates service providers available to the server

• SetApplicationDesc- changes particular application settings for an existing session

• CreateGroup- creates a new group to which players can be added

• DestroyGroup

IDirectPlay8Server functions (3)

• AddPlayerToGroup

• RemovePlayerFromGroup

• GetGroupInfo

• GetClientInfo

• DestroyClient

• GetClientAddress- get DPlay address

(5)

IDirectPlay8Server functions (4)

• GetLocalHostAddresses- get DPlay address used to host the local server

• GetSendQueueInfo- monitors the send message queue for a particular client

• GetConnectionInfo- gets info about the connection with a particular client

• GetApplicationDesc

After CoCreateInstance() of server

• Init IDirectPlay8Server Message Handler (all messages will be sent here)

HRESULT Initialize(

PVOID Const pvUserContext, PFNDPNMESSAGEHANDLER pfn, DWORD dwFlags

);

Pointer to message handler

(6)

After Initialize()

• Set up device address (for the host)

• Set the address ’ service provider

• The code is very similar to the code for peers

hosting

1. Set up the server info with SetServerInfo()

2. Set up application description with the DPN_APPLICATION_DESC data

structure

3. Set up the address to handle things with AddComponent()

4. Call the Host() function

(7)

SetServerInfo()

HRESULT SetServerInfo(

const DPN_PLAYER_INFO *const pdpnPlayerInfo, PVOID const pvAsynContext,

DPNHANDLE *const phAsyncHandle, const DWORD dwFlags

)

Server info, e.g.name

User context (opt)

DPNSETSERVERINFO_SYNC ->process synchronously

//// Setup our player information

//DXUtil_ConvertGenericStringToWide( wszServerName, "DPChat Server" );

ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );

dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);

dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;

dpPlayerInfo.pwszName = wszServerName;

// Set us up to be non-asynchronous if( FAILED( hReturn = g_pDPServer-

>SetServerInfo( &dpPlayerInfo, NULL, NULL, DPNSETSERVERINFO_SYNC ) ) ) {

MessageBox( hWindow, "Failed to SetServerInfo()", "Unknown Error", MB_ICONERROR );

return -1;

(8)

Set up

DPN_APPLICATION_DESC

• Use just like you used peers, but dwFlags change to

DPNSESSION_CLIENT_SERVER

// Setup the application description

DXUtil_ConvertGenericStringToWide( wszSessionName, "DPChat Session" );

ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );

dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);

dnAppDesc.guidApplication = GUID_CHATSERVER;

dnAppDesc.pwszSessionName = wszSessionName;

dnAppDesc.dwMaxPlayers = MAX_PLAYERS;

dnAppDesc.dwFlags = DPNSESSION_CLIENT_SERVER;

(9)

Set up the address

• Need to add server’s host port number

• Clients communicate through here //// Add port number to host address //hReturn = g_pDeviceAddress-

>AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),DPNA_

DATATYPE_DWORD);

if( hReturn != S_OK ) {

MessageBox( hWindow, "Failed to AddComponent()",

"hrHostGame()", MB_ICONERROR );

return -1;

}

Tell the port number

Host()

HRESULT Host(

const DPN_APPLICATION_DESC *const pdnAppDesc, IDirectPlay8Address **const prgDeviceInfo,

const DWORD cDeviceInfo,

const DPN_SECURITY_DESC *const pdpSecurity,

const DPN_SECURITY_CREDENTIALS *const pdpCredentials, VOID *const pvPlayerContext,

const DWORD dwFlags );

The app.desc you created

Device you just added port number How many devices in the second parameter

Not used by DirectX8 Optional

user context Hosting flags

(10)

hReturn = g_pDPServer->Host(

&dnAppDesc,

&g_pDeviceAddress, 1,

NULL,

NULL, NULL, NULL );

if( FAILED( hReturn ) ) {

MessageBox( hWindow, "Failed to Host()", "DirectPlay Error", MB_ICONERROR );

return -1;

}

Managing Players

• When a player connects to your game, he passes you a creation message

• You need to add him to your table of

active players

(11)

HRESULT hrCreatePlayer( PVOID pvUserContext, PVOID pMsgBuffer )

{ HRESULT hReturn = S_OK;

PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;

char strName[256];

char szOutput[256];

DWORD dwSize = 0;

DPN_PLAYER_INFO *pdpPlayerInfo = NULL;

int i;

// Get a Create Message pointer to the buffer pCreatePlayerMsg =

(PDPNMSG_CREATE_PLAYER)pMsgBuffer;

// Get the peer info and extract its name

hReturn = g_pDPServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );

if( FAILED(hReturn) && hReturn != DPNERR_BUFFERTOOSMALL ) { if( hReturn == DPNERR_INVALIDPLAYER ) {

vShowText(hLB_Output,"Adding Ourselves");

}hReturn = -1;

}else {

pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];

ZeroMemory( pdpPlayerInfo, dwSize );

pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);

hReturn = g_pDPServer->GetClientInfo( pCreatePlayerMsg-

>dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );

if( FAILED(hReturn) ) {

GET SIZE

(12)

HRESULT GetClientInfo(

const DPNID dpnid, // belongs to the client that we want info

DPN_PLAYER_INFO *const pdpnPlayerInfo, //this will hold the soon- to- //be-retrieved player info DWORD *const pdwSize, //size of the information retrieved.

//If the buffer size is too small,

//DPNERR_BUFFERTOOSMALL is returned const DWORD dwFlags //DPNINFO_NAME or DPNINFO_DATA );

vShowText(hLB_Output,"Error Getting Client Info");

hReturn = -1;

}else {

EnterCriticalSection( &g_csModifyPlayer );

// Convert player name to ANSI

DXUtil_ConvertWideStringToGeneric( strName, pdpPlayerInfo-

>pwszName );

// Add player to list

for( i = 0 ; i < MAX_PLAYERS ; i++ ) { if( !PlayerInfo[i].bActive ) {

PlayerInfo[i].bActive = 1;

PlayerInfo[i].dpnidPlayer = pCreatePlayerMsg-

>dpnidPlayer;

strcpy(PlayerInfo[i].szPlayerName,strName);

break;

} }

// Check if no free slot found

(13)

vShowText(hLB_Output,"No free slots in game!");

}// Check if we are adding ourselves else if( pdpPlayerInfo->dwPlayerFlags &

DPNPLAYER_LOCAL ) {

g_dpnidLocalPlayer = pCreatePlayerMsg-

>dpnidPlayer;

sprintf(szOutput,"<Slot%d> Added Ourselves",i);

vShowText(hLB_Output,szOutput);

}else {

sprintf(szOutput,"<Slot%d><%s> Is In The Game",i,strName);

vShowText(hLB_Output,szOutput);

}

SAFE_DELETE_ARRAY( pdpPlayerInfo );

// Update the number of active players in a thread safe way if( i != MAX_PLAYERS )

InterlockedIncrement( &g_lNumberOfActivePlayers );

LeaveCriticalSection( &g_csModifyPlayer );

} }

return hReturn;

}

(14)

Destroy Player

• Must check for

DPN_MSGID_DESTROY_PLAYER

• CALL hrDestroyPlayer() to process it

HRESULT hrDestroyPlayer( PVOID pvUserContext, PVOID pMsgBuffer )

{ PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;

HRESULT hReturn = S_OK;

int i;

char szOutput[256];

// Get a Destroy Message pointer to the buffer pDestroyPlayerMsg =

(PDPNMSG_DESTROY_PLAYER)pMsgBuffer;

// Update the number of active players in a thread safe way InterlockedDecrement( &g_lNumberOfActivePlayers );

EnterCriticalSection( &g_csModifyPlayer );

Use this, so that we can find the players ID

(15)

for( i = 0 ; i < MAX_PLAYERS ; i++ ) { if( PlayerInfo[i].bActive ) {

if( PlayerInfo[i].dpnidPlayer ==

pDestroyPlayerMsg->dpnidPlayer ) {

PlayerInfo[i].bActive = 0;

sprintf(szOutput,"<Slot%d><%s> Left The Game",i,PlayerInfo[i].szPlayerName);

vShowText(hLB_Output,szOutput);

break;

} } }

LeaveCriticalSection( &g_csModifyPlayer );

return(hReturn);

}

Receiving messages from client

case DPN_MSGID_RECEIVE:

{ PDPNMSG_RECEIVE pReceiveMsg;

PacketGeneric *PGen;

pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;

PGen = (PacketGeneric*)pReceiveMsg->pReceiveData;

// Ignore the packet if we sent it originally

if( pReceiveMsg->dpnidSender == g_dpnidLocalPlayer ) break;

// If it is a chat packet, send it out to all of the players In LoginDirectPlayMessageHandler

DWORD dwType;

DWORD dwSize;

(16)

void *packet;

PacketChat *ChatMsg;

// Convert the packet to a void stream ChatMsg = (PacketChat*)pReceiveMsg-

>pReceiveData;

packet = (VOID*)ChatMsg;

// Send the chat packet to all clients hrSendServerMessage(DPNID_ALL_PLAYERS_GROUP,P ACKET_TYPE_CHAT,packet);

// Output it on our screen

vShowText(hLB_Output,ChatMsg-

>szText);

}break;

}

hrSendServerMessage()

HRESULT hrSendServerMessage(

int player, //slot number that you want to send the message //to. Use DPNID_ALL_PLAYERS_GROUP to //send message to all clients

DWORD dwMessageType, //message type, defined in //DPChatServer.h

PVOID pMsgBuffer //void pointer to the contents of the //message. Void pointer allows any type //of data for this parameter

(17)

HRESULT hrSendServerMessage( int player, DWORD dwMessageType, PVOID pMsgBuffer )

{ DPNHANDLE hAsync;

DWORD dwLength;

DPN_BUFFER_DESC bufferDesc;

PacketGeneric *PGen;

// Cast to a generic packet to get the size PGen = (PacketGeneric*)pMsgBuffer;

dwLength = PGen->dwSize;

if( dwLength == 0 ) return(0);

bufferDesc.dwBufferSize = dwLength;

bufferDesc.pBufferData = (BYTE*)pMsgBuffer;

// Broadcast it if player set to zero if( player == DPNID_ALL_PLAYERS_GROUP )

g_pDPServer->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 0, NULL,

&hAsync, DPNSEND_NOLOOPBACK );

else g_pDPServer->SendTo( PlayerInfo[player].dpnidPlayer, &bufferDesc, 1, 0, NULL, &hAsync, 0 );

return S_OK;

}

Exit because we don’t want to send empty message

Set up buffer

SendTo()

HRESULT SendTo(

const DPNID dpnid, //client you want to send to const DPN_BUFFER_DESC *const pBufferDesc,

//this is the actual message data const DWORD cBufferDesc, //how many msg buffers to

//send with this call

const DWORD dwTimeOut, //time out, set to 0 if you want //to keep sending the lost message void *const pvAsyncContext, //NULL

DPNHANDLE *const phAsyncHandle, //can use it to cancel send //but if we set it to

//DPNSEND_SYNC, this value //must be null

const DWORD dwFlags // SEE next page

(18)

SendTo -> flags (1)

• DPNSEND_GUARANTEED – Guarantees message delivery

• DPNSEND_NOLOOPBACK

– Keeps the server from receiving its own messages

• DPNSEND_PRIORITY_LOW

– Queues the message with low priority

• DPNSEND_PRIORITY_HIGH

– Queues the message with high priority

SendTo -> flags (2)

• DPNSEND_NOCOPY

– Keeps DirectPlay from making a copy of the

DPN_BUFFER_DESC before sending the message. You cannot use DPNSEND_NOCOMPLETE with this

• DPNSEND_SYNC

– Process the send synchronously

• DPNSEND_NOCOMPLETE

– Keeps DPN_MSGID_SEND_COMPLETE message from being generated

– Cannot use DPNSEND_NOCOPY and

DPNSEND_GUARANTEED flags with this one, and the

(19)

SendTo -> flags (3)

• DPNSEND_NONSEQUENTIAL

– Lets messages arrive at the client’s computer in any possible order -> only use this flag for non-critical packets

• DPNSEND_COMPLETEONPROCESS – Causes DirectPlay to send a

DPN_MSGID_SEND_COMPLETE message upon completion of a message being received by the client. You have to set the

DPNSEND_GUARANTEED flag in conjunction with this flag

IDirectPlay8 Client interface

• Initialize and do things as before

(20)

HRESULT hrInitializeDirectPlay( HWND hWindow ) { HRESULT hReturn;

// Initialize COM

hReturn = CoInitialize( NULL );

if( FAILED(hReturn) ) {

MessageBox( hWindow, "Error Initializing COM", "DirectPlay Error", MB_ICONERROR );

return hReturn;

}

// Create IDirectPlay8Client Object

if( FAILED( hReturn = CoCreateInstance( CLSID_DirectPlay8Client, NULL,

CLSCTX_INPROC_SERVER, IID_IDirectPlay8Client, (LPVOID*) &g_pDP ) ) )

MessageBox( hWindow, "Can't Create DPlayClient", "DirectPlay Error", MB_ICONERROR );

// Init IDirectPlay8Client Message Handler

if( FAILED( hReturn = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) ) { MessageBox( hWindow, "Failed to Message Handler", "DirectPlay Error", MB_ICONERROR );

return -1;

}

// Create a device address

hReturn = CoCreateInstance( CLSID_DirectPlay8Address,

NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)

&g_pDeviceAddress );

if( FAILED(hReturn) ) {

MessageBox( hWindow, "Failed to Create Device", "CoCreateInstance()", MB_ICONERROR );

return -1;

}

// Set our service provider to TCP/IP

if( FAILED( hReturn = g_pDeviceAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) {

(21)

// Create a host address

hReturn = CoCreateInstance( CLSID_DirectPlay8Address,

NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)

&g_pHostAddress );

if( FAILED(hReturn) ) {

MessageBox( hWindow, "Failed to Create Host Address()", "Invalid Param", MB_ICONERROR );

return -1;

}// Set the host address to TCP/IP

if( FAILED( hReturn = g_pHostAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { MessageBox( hWindow, "Failed to SetSP() for Host Address", "Invalid Param", MB_ICONERROR );

return -1;

}

// Create connection complete event for later use

g_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

vShowText(hLB_Output,"<<--TCP INITED-->>");

return S_OK;

}

Joining the server session

• A user click the join button -> msg is sent

• hrJoinGame() is called

(22)

LRESULT CALLBACK fnMessageProcessor ( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )

{ char szMessage[256];

char szCompMessage[256];

char szMyName[32];

HRESULT hReturn;

void *packet;

PacketChat ChatMsg;

switch (iMsg)

{ case WM_COMMAND:

{ // Check for child window messages switch(LOWORD(wParam))

{ // Check if the user clicked the button case IDC_hBU_Join:

hrJoinGame( hWnd );

break;

} }

} See next page

HRESULT hrJoinGame( HWND hWnd )

{ HRESULT hReturn = S_OK;

WCHAR wszHostName[256];

WCHAR wszClientName[256];

char szClientName[256];

char szIP[256];

char szPort[256];

DWORD dwPort;

DWORD dwLength = 256;

DPN_APPLICATION_DESC dpnAppDesc;

DPN_PLAYER_INFO dpPlayerInfo;

vShowText(hLB_Output,"Attempting Connection...");

// Set the Client info

GetWindowText(hEB_InputName,szClientName,36); // Get name from Window Edit Box

(23)

ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );

dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);

dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;

dpPlayerInfo.pwszName = wszClientName;

// Make this a synchronous call

if( FAILED( hReturn = g_pDP->SetClientInfo( &dpPlayerInfo, NULL, NULL, DPNSETCLIENTINFO_SYNC ) ) ) {

vShowText(hLB_Output,"Failed to set client info");

return -1;

}

// Prepare the application description ZeroMemory( &dpnAppDesc, sizeof(

DPN_APPLICATION_DESC ) );

dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC );

dpnAppDesc.guidApplication = GUID_CHATSERVER;

Setup info for the player who joins

If your client applications GUID does not match the servers Then a connection cannot be made

HRESULT setClientInfo(

const DPN_PLAYER_INFO *const pdpnPlayerInfo,

//stores player name and other info about client PVOID const pvAsyncContext, //NULL

DPNHANDLE *const phAsyncHandle, // a handle that lets you cancel //this operation

const DWORD dwFlags //1 flag -> DPNSETCLIENTINFO_SYNC, //which tells the function to process //synchronously

);

(24)

// Get IP from edit box

GetWindowText(hEB_InputServerIP,szIP,32);

// Get Port from edit box

GetWindowText(hEB_InputServerPort,szPort,6);

// Convert the IP to a wide string

DXUtil_ConvertGenericStringToWide( wszHostName, szIP );

// Convert the port string to a DWORD dwPort = atol(szPort);

// Add host name to address hReturn = g_pHostAddress-

>AddComponent(DPNA_KEY_HOSTNAME,wszHostName,(wcslen(

wszHostName)+1)*sizeof(WCHAR),DPNA_DATATYPE_STRING);

if( hReturn != S_OK ) {

MessageBox( hWnd, "Failed to AddComponent()",

"hrJoinGame()", MB_ICONERROR );

return -1;

}

Created in hrInitializeDirectPlay()

// Add port number to address hReturn = g_pHostAddress-

>AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),D PNA_DATATYPE_DWORD);

if( hReturn != S_OK ) {

MessageBox( hWnd, "Failed to AddComponent()",

"hrJoinGame()", MB_ICONERROR );

return -1;

}// Connect to the session

hReturn = g_pDP->Connect( &dpnAppDesc, g_pHostAddress, g_pDeviceAddress, NULL,

NULL, NULL,

(25)

if( hReturn != E_PENDING && FAILED(hReturn) ) { vShowText(hLB_Output,"Failed to Connect");

return -1;

}

SetTimer( hWnd, TIMERID_CONNECT_COMPLETE, 100, NULL );

return(hReturn);

}

HRESULT Connect(

const DPN_APPLICATION_DESC *const pdnAppDesc, //the application description we set up earlier

IDirectPlay8Address *const pHostAddr, //host address interface IDirectPlay8Address *const pDeviceInfo, //device address for the client

//connection that you defined in //hrInitializeDirectPlay() const DPN_SECURITY_DESC *const pdnSecurity, //for future, therefore

//NULL

const DPN_SECURITY_CREDENTIALS *const pdnCredentials, //NULL const void *const pvUserConnectData, //send additional connect information to

//the server. If you specify this, the //server receives a

//DPN_MSGID_INDICATE_CONNECT //message

const DWORD dwUserConnectDataSize, //size of the 6thparameter void *const pvAsyncContext, //user created context to be passed when

//DPN_MSGID_CONNECT_COMPLETE message is //processed

DPHANDLE *const phAsyncHandle, //must be NULL if you set //DPNCONNECT_SYNC

(26)

Set up the connection timer

• Let it goes off every 0.1 second

• i.e. the system sends a WM_TIMER message to the main message loop every 0.1 second

• This saves the program from having to do a loop-intensive waiting

• The part of the code that handles

WM_TIMER is in fnMessageProcessor()

case WM_TIMER:

if( wParam == TIMERID_CONNECT_COMPLETE ) {

// Check if the message is telling us our connection is complete if( WAIT_OBJECT_0 == WaitForSingleObject(

g_hConnectCompleteEvent, 0 ) ) {

if( FAILED( g_hrConnectComplete ) ) {

vShowText(hLB_Output,"<<----CONNECTION IN-COMPLETE---->>");

} else {

vShowText(hLB_Output,"<<----CONNECTION COMPLETE---->>");

}

KillTimer( hWnd, TIMERID_CONNECT_COMPLETE );

} }

Check if this is the timer that we created

(27)

• In DirectPlayMessageHandler(),

DPN_MSGID_CONNECT_COMPLETE is received by clientr once the server has accepted the connection

• When you get this message, you should signal the g_hConnectCompleteEvent with the SetEvent()

– Before you do that it is best to set the return state of the connection to find out whether the server accepted or rejected the connection

case DPN_MSGID_CONNECT_COMPLETE:

{

PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;

pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;

g_hrConnectComplete = pConnectCompleteMsg->hResultCode;

SetEvent( g_hConnectCompleteEvent );

break;

}

(28)

Sending messages to the server

• Look in fnMessageProcessor()

switch(HIWORD(wParam))

{ case EN_UPDATE:

// Get the text from the edit box

GetWindowText(hEB_InputField,szMessage,256);

// Check if they pressed enter

if( szMessage[strlen(szMessage)-1] == 10 ) { // Get rid of trailing garbage

szMessage[strlen(szMessage)-2] = '\0';

GetWindowText(hEB_InputName,szMyName,32);

sprintf(szCompMessage,"<%s> %s", szMyName, szMessage);

// clear input field

SetWindowText(hEB_InputField,"");

//// Send a chat packet to the server //ChatMsg.dwSize = sizeof(PacketChat);

ChatMsg.dwType = PACKET_TYPE_CHAT;

strcpy(ChatMsg.szText,szCompMessage);

// Convert the packet to a void stream packet = (VOID*)&ChatMsg;

(29)

HRESULT hrSendClientMessage( DWORD dwMessageType, PVOID pMsgBuffer )

{ DPNHANDLE hAsync;

DWORD dwLength;

DPN_BUFFER_DESC bufferDesc;

PacketGeneric *PGen;

// Cast to a generic packet to get the size PGen = (PacketGeneric*)pMsgBuffer;

dwLength = PGen->dwSize;

if( dwLength == 0 ) return(0);

bufferDesc.dwBufferSize = dwLength;

bufferDesc.pBufferData = (BYTE*)pMsgBuffer;

g_pDP->Send( &bufferDesc, 1, 0, NULL, &hAsync, 0 );

return S_OK;

} Use Send() instead of SendTo()

-client can only send to server, so no need to tell Who it sends to

IDirectPlay8Client::Send()

HRESULT Send(

const DPN_BUFFER_DESC *const pBufferDesc,

//the DPN_BUFFER_DESC data structure that contains the //message to send

const DWORD cBufferDesc, //number of buffers passed in //the first parameter (currently //you can only send 1)

const DWORD dwTimeOut, //milliseconds, if 0-> keep sending void *const pvAsyncContext, //NULL

DPNHANDLE *const phAsyncHandle, //if you use

//DPSEND_SYNC, you

(30)

Review

• Server

– Initialize COM

– Create IDirectPlay8Server interface – Create a device address

– Set TCP/IP as the service provider – Set the server information using

IDirectPlay8Server::SetServerInfo() – Initialize the application description

– Add the port number to the device address – Call the IDirectPlay8Server::Host()

• Client

– Initialize COM

– Create IDirectPlay8Client interface – Create a device address

– Set TCP/IP as the service provider – Create a host address

– Set TCP/IP as the service provider – Create a completion event

– Set the client information using IDirectPlay8Client::SetClientInfo() – Initialize the application description

– Add the host port number and IP address to the host address

– Call the IDirectPlay8Client::Connect()

Referensi

Dokumen terkait

A number of data from 35 Bali bulls were collected from BPTU Bali Cattle to obtain growth traits, carcass characteristics, and blood samples.. Polymorphism of CAST gene in Bali

Project Jxta defines a set of six protocols that can be used to construct P2P systems using a centralized, brokered or decentralized approach but its main aim is to facilitate

This book is written for web application developers who are are familiar with the Java programming language, as well as HTML, JavaScript, and CSS.. It is geared toward those who

Bintang Gasing Persada terdapat 4 laporan yaitu: a Laporan Data Karyawan, Laporan data karyawan merupakan laporan yang didapat dari hasil form data karyawan, laporan ini dibuat untuk

Other Benefits of Computer Network  Increased speed  Reduced cost  Improved security  Centralized software managements  Electronic mail  Flexible access Disadvantages of

Table 3: Response Time Client 1 and android on the sensor motion HC-SR505 when online There exists a delay in response time because when the client sends data results of a sensor to

• THE BENEFIT OF SUCH AN ARRANGEMENT IS THAT THE SERVER, WHICH TENDS TO BE A MORE POWERFUL COMPUTER, HANDLES THE MORE DEMANDING DATA MANIPULATION TASKS.. HOWEVER, THE SERVER DOESN'T

There were a lot of subjects with DPN who had normal ABI score that it was statistically difficult to establish its significant correlation with DPN severity degree that was assessed