亚洲精品中文字幕无乱码_久久亚洲精品无码AV大片_最新国产免费Av网址_国产精品3级片

培訓(xùn)考試

網(wǎng)絡(luò)游戲制作技術(shù)培訓(xùn)考試題

時(shí)間:2024-05-27 17:41:48 培訓(xùn)考試 我要投稿
  • 相關(guān)推薦

網(wǎng)絡(luò)游戲制作技術(shù)培訓(xùn)考試題

  網(wǎng)絡(luò)游戲的程序開發(fā)從某種意義上來看,最重要的應(yīng)該在于游戲服務(wù)器端的設(shè)計(jì)和制作。對(duì)于服務(wù)器端的制作。將分為以下幾個(gè)模塊進(jìn)行:

網(wǎng)絡(luò)游戲制作技術(shù)培訓(xùn)考試題

  1.網(wǎng)絡(luò)通信模塊

  2.協(xié)議模塊

  3.線程池模塊

  4.內(nèi)存管理模塊

  5.游戲規(guī)則處理模塊

  6.后臺(tái)游戲仿真世界模塊。

  現(xiàn)在就網(wǎng)絡(luò)中的通信模塊處理談一下自己的看法!!

  在網(wǎng)絡(luò)游戲客戶端和服務(wù)器端進(jìn)行交互的雙向I/O模型中分別有以下幾種模型:

  1. Select模型

  2. 事件驅(qū)動(dòng)模型

  3. 消息驅(qū)動(dòng)模型

  4. 重疊模型

  5. 完成端口重疊模型。

  在這樣的幾種模型中,能夠通過硬件性能的提高而提高軟件性能,并且能夠同時(shí)處理成千上百個(gè)I/O請(qǐng)求的模型。服務(wù)器端應(yīng)該采用的最佳模型是:完成端口 模型。然而在眾多的模型之中完成端口的處理是最復(fù)雜的,而它的復(fù)雜之處就在于多服務(wù)器工作線程并行處理客戶端的I/O請(qǐng)求和理解完成端口的請(qǐng)求處理過程。

  對(duì)于服務(wù)器端完成端口的處理過程總結(jié)以下一些步驟:

  1. 建立服務(wù)器端SOCKET套接字描述符,這一點(diǎn)比較簡(jiǎn)單。

  例如:

  SOCKET server_socket;

  Server_socket = socket(AF_INET,SOCK_STREAM,0);

  2.綁定套接字server_socket。

  Const int SERV_TCP_PORT = 5555;

  struct sockaddr_in server_address.

  memset(&server_address, 0, sizeof(struct sockaddr_in));

  server_address.sin_family = AF_INET;

  server_address.sin_addr.s_addr = htonl(INADDR_ANY);

  server_address.sin_port = htons(SERV_TCP_PORT);

  //綁定

  Bind(serve_socket,( struct sockaddr *)&server_address, sizeof(server_address));

  2. 對(duì)于建立的服務(wù)器套接字描述符偵聽。

  Listen(server_socket ,5);

  3. 初始化我們的完成端口,開始的時(shí)候是產(chǎn)生一個(gè)新的完成端口。

  HANDLE hCompletionPort;

  HCompletionPort = CreateIoCompletionPort(NULL,NULL,NULL,0);

  4. 在我們已經(jīng)產(chǎn)生出來新的完成端口之后,我們就需要進(jìn)行系統(tǒng)的偵測(cè)來得到系統(tǒng)的硬件信息。從而來定出我們的服務(wù)器完成端口工作線程的數(shù)量。

  SYSTEM_INFO system_info;

  GetSystemInfo(&system_info);

  在我們知道我們系統(tǒng)的信息之后,我們就需要做這樣的一個(gè)決定,那就是我們的服務(wù)器系統(tǒng)該有多少個(gè)線程進(jìn)行工作,我一般會(huì)選擇當(dāng)前處理器的2倍來生成我 們的工作線程數(shù)量(原因考慮線程的阻塞,所以就必須有后備的線程來占有處理器進(jìn)行運(yùn)行,這樣就可以充分的提高處理器的利用率)。

  代碼:

  WORD threadNum = system_info. DwNumberOfProcessors*2+2;

  for(int i=0;I

  {

  HANDLE hThread;

  DWORD dwthreadId;

  hThread = _beginthreadex(NULL,ServerWorkThrea, (LPVOID)hCompletePort,0,&dwthreadId);

  CloseHandle(hThread);

  }

  CloseHandle(hThread)在程序代碼中的作用是在工作線程在結(jié)束后,能夠自動(dòng)銷毀對(duì)象作用。

  6. 產(chǎn)生服務(wù)器檢測(cè)客戶端連接并且處理線程。

  HANDLE hAcceptThread;

  DWORD dwThreadId;

  hAcceptThread= _beginthreadex(NULL,AcceptWorkThread,NULL, &dwThreadId);

  CloseHandle(hAcceptThread);

  7.連接處理線程的處理,在線程處理之前我們必須定義一些屬于自己的數(shù)據(jù)結(jié)構(gòu)體來進(jìn)行網(wǎng)絡(luò)I/O交互過程中的數(shù)據(jù)記錄和保存。

  首先我要將如下幾個(gè)函數(shù)來向大家進(jìn)行解析:

  1.

  HANDLE CreateIoCompletionPort (

  HANDLE FileHandle, // handle to file

  HANDLE ExistingCompletionPort, // handle to I/O completion port

  ULONG_PTR CompletionKey, // completion key

  DWORD NumberOfConcurrentThreads // number of threads to execute concurrently

  );

  參數(shù)1:

  可以用來和完成端口聯(lián)系的各種句柄,在這其中可以包括如下一些:

  套接字,文件等。

  參數(shù)2:

  已經(jīng)存在的完成端口的句柄,也就是在第三步我們初始化的完成端口的句柄就可以了。

  參數(shù)3:

  這個(gè)參數(shù)對(duì)于我們來說將非常有用途。這就要具體看設(shè)計(jì)者的想法了, ULONG_PTR對(duì)于完成端口而言是一個(gè)單句柄數(shù)據(jù),同時(shí)也是它的完成鍵值。同時(shí)我們?cè)谶M(jìn)行

  這樣的GetQueuedCompletionStatus(….)(以下解釋)函數(shù)時(shí)我們可以完全得到我們?cè)诖寺?lián)系函數(shù)中的完成鍵,簡(jiǎn)單的說也就是我們 在CreateIoCompletionPort(…..)申請(qǐng)的內(nèi)存塊,在GetQueuedCompletionStatus(……)中可以完封不動(dòng) 的得到這個(gè)內(nèi)存塊,并且使用它。這樣就給我們帶來了一個(gè)便利。也就是我們可以定義任意數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)我們的信息。在使用的時(shí)候只要進(jìn)行強(qiáng)制轉(zhuǎn)化就可以了。

  參數(shù)4:

  引用MSDN上的解釋

  [in] Maximum number of threads that the operating system allows to concurrently process I/O completion packets for the I/O completion port. If this parameter is zero, the system allows as many concurrently running threads as there are processors in the system.

  這個(gè)參數(shù)我們?cè)谑褂弥兄恍枰獙⑺跏蓟癁?就可以了。上面的意思我想大家應(yīng)該也是了解的了!嘿嘿!!

  我要向大家介紹的第二個(gè)函數(shù)也就是

  2.

  BOOL GetQueuedCompletionStatus(

  HANDLE CompletionPort, // handle to completion port

  LPDWORD lpNumberOfBytes, // bytes transferred

  PULONG_PTR lpCompletionKey, // file completion key

  LPOVERLAPPED *lpOverlapped, // buffer

  DWORD dwMilliseconds // optional timeout value

  );

  參數(shù)1:

  我們已經(jīng)在前面產(chǎn)生的完成端口句柄,同時(shí)它對(duì)于客戶端而言,也是和客戶端SOCKET連接的那個(gè)端口。

  參數(shù)2:

  一次完成請(qǐng)求被交換的字節(jié)數(shù)。(重疊請(qǐng)求以下解釋)

  參數(shù)3:

  完成端口的單句柄數(shù)據(jù)指針,這個(gè)指針將可以得到我們?cè)贑reateIoCompletionPort(………)中申請(qǐng)那片內(nèi)存。

  借用MSDN的解釋:

  [out] Pointer to a variable that receives the completion key value associated with the file handle whose I/O operation has completed. A completion key is a per-file key that is specified in a call to CreateIoCompletionPort.

  所以在使用這個(gè)函數(shù)的時(shí)候只需要將此處填一相應(yīng)數(shù)據(jù)結(jié)構(gòu)的空指針就可以了。上面的解釋只有大家自己擺平了。

  參數(shù)4:

  重疊I/O請(qǐng)求結(jié)構(gòu),這個(gè)結(jié)構(gòu)同樣是指向我們?cè)谥丿B請(qǐng)求時(shí)所申請(qǐng)的內(nèi)存塊,同時(shí)和lpCompletionKey,一樣我們也可以利用這個(gè)內(nèi)存塊來存儲(chǔ)我們要保存的任意數(shù)據(jù)。以便于我們來進(jìn)行適當(dāng)?shù)姆⻊?wù)器程序開發(fā)。

  [out] Pointer to a variable that receives the address of the OVERLAPPED structure that was specified when the completed I/O operation was started.(MSDN)

  3.

  int WSARecv(

  SOCKET s,

  LPWSABUF lpBuffers,

  DWORD dwBufferCount,

  LPDWORD lpNumberOfBytesRecvd,

  LPDWORD lpFlags,

  LPWSAOVERLAPPED lpOverlapped,

  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

  );

  這個(gè)函數(shù)也就是我們?cè)谶M(jìn)行完成端口請(qǐng)求時(shí)所使用的請(qǐng)求接受函數(shù),同樣這個(gè)函數(shù)可以用ReadFile(………)來代替,但不建議使用這個(gè)函數(shù)。

  參數(shù)1:

  已經(jīng)和Listen套接字建立連接的客戶端的套接字。

  參數(shù)2:

  用于接受請(qǐng)求數(shù)據(jù)的緩沖區(qū)。

  [in/out] Pointer to an array of WSABUF structures. Each WSABUF structure contains a pointer to a buffer and the length of the buffer.(MSDN)。

  參數(shù)3:

  參數(shù)2所指向的WSABUF結(jié)構(gòu)的數(shù)量。

  [in] Number of WSABUF structures in the lpBuffers array.(MSDN)

  參數(shù)4:

  [out] Pointer to the number of bytes received by this call if the receive operation completes immediately. (MSDN)

  參數(shù)5:

  [in/out] Pointer to flags.(MSDN)

  參數(shù)6:

  這個(gè)參數(shù)對(duì)于我們來說是比較有作用的,當(dāng)它不為空的時(shí)候我們就是提出我們的重疊請(qǐng)求。同時(shí)我們申請(qǐng)的這樣的一塊內(nèi)存塊可以在完成請(qǐng)求后直接得到,因此我們同樣可以通過它來為我們保存客戶端和服務(wù)器的I/O信息。

  參數(shù)7:

  [in] Pointer to the completion routine called when the receive operation has been completed (ignored for nonoverlapped sockets).(MSDN)

  4.

  int WSASend(

  SOCKET s,

  LPWSABUF lpBuffers,

  DWORD dwBufferCount,

  LPDWORD lpNumberOfBytesSent,

  DWORD dwFlags,

  LPWSAOVERLAPPED lpOverlapped,

  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

  );

  參數(shù)解釋可以參考上面或者M(jìn)SDN。在這里就不再多說了。

  下面就關(guān)client端用戶連接(connect(……..))請(qǐng)求的處理方式進(jìn)行

  舉例如下:

  const int BUFFER_SIZE = 1024;

  typedef struct IO_CS_DATA

  {

  SOCKET clisnt_s; //客戶端SOCKET

  WSABUF wsaBuf;

  Char inBuffer[BUFFET_SIZE];

  Char outBuffer[BUFFER_SIZE];

  Int recvLen;

  Int sendLen;

  SYSTEM_TIME start_time;

  SYSTEM_TIME start_time;

  }IO_CS_DATA;

  UINT WINAPI ServerAcceptThread(LPVOID param)

  {

  SOCKET client_s;

  HANDLE hCompltPort = (HANDLE) param;

  struct sockaddr_in client_addr;

  int addr_Len = sizeof(client_addr);

  LPHANDLE_DATA hand_Data = NULL;

  while(true)

  {

  If((client_s=accept(server_socket,NULL,NULL)) == SOCKET_ERROR)

  {

  printf("Accept() Error: %d",GetLastError());

  return 0;

  }

  hand_Data = (LPHANDLE_DATA)malloc(sizeof(HANDLE_DATA));

  hand_Data->socket = client_s;

  if(CreateIoCompletionPort((HANDLE)client_s,hCompltPort,(DWORD)hand_Data,0)==NULL)

  {

  printf("CreateIoCompletionPort()Error: %d", GetLastError());

  }

  else

  {

  game_Server->RecvDataRequest(client_s);

  }

  }

  return 0;

  }

  在這個(gè)例子中,我們要闡述的是使用我們已經(jīng)產(chǎn)生的接受連接線程來完成我們響應(yīng)Client端的connect請(qǐng)求。關(guān)于這個(gè)線程我們同樣可以用我們線程池的方式來進(jìn)行生成多個(gè)線程來進(jìn)行處理,其他具體的函數(shù)解釋已經(jīng)在上面解釋過了,希望不懂的自己琢磨。

  關(guān)于game_Sever object的定義處理將在下面進(jìn)行介紹。

  class CServerSocket : public CBaseSocket

  {

  public:

  CServerSocket();

  virtual ~CServerSocket();

  bool StartUpServer(); //啟動(dòng)服務(wù)器

  void StopServer(); //關(guān)閉服務(wù)器

  //發(fā)送或者接受數(shù)據(jù)(重疊請(qǐng)求)

  bool RecvDataRequest(SOCKET client_s);

  bool SendDataRequest(SOCKET client_s,char *buf,int b_len);

  void ControlRecvData(SOCKET client_s,char *buf,int b_len);

  void CloseClient(SOCKET client_s);

  private:

  friend UINT WINAPI GameServerThread(LPVOID completionPortID); //游戲服務(wù)器通信工作線程

  private:

  void Init();

  void Release();

  bool InitComplePort();

  bool InitServer();

  bool CheckOsVersion();

  bool StartupWorkThread();

  bool StartupAcceptThread();

  private:

  enum { SERVER_PORT = 10006};

  UINT cpu_Num; //處理器數(shù)量

  CEvent g_ServerStop; //服務(wù)器停止事件

  CEvent g_ServerWatch; //服務(wù)器監(jiān)視事件

  public:

  HANDLE hCompletionPort; //完成端口句柄

  };

  在上面的類中,是我們用來處理客戶端用戶請(qǐng)求的服務(wù)器端socket模型。

【網(wǎng)絡(luò)游戲制作技術(shù)培訓(xùn)考試題】相關(guān)文章:

教育技術(shù)培訓(xùn)考試題10-30

2014現(xiàn)代教育技術(shù)培訓(xùn)考試題06-28

PHP考試題10-08

鄉(xiāng)村醫(yī)生考試題11-02

煤礦培訓(xùn)的考試題06-25

OA培訓(xùn)考試題07-18

OA培訓(xùn)考試題09-03

職員培訓(xùn)考試題09-20

鉗工培訓(xùn)考試題09-14

煤礦培訓(xùn)考試題10-22