1. 程式人生 > >Windows socket之IOCP例項----IOCP開發駕照理論考試系統

Windows socket之IOCP例項----IOCP開發駕照理論考試系統

          Windows socket IO完成埠開發駕照理論考試系統例項

這一節我們講解如何利用套接字完成埠開發駕照理論考試系統。

該系統由伺服器和客戶端兩部分組成。

    伺服器負責對題庫和學生資訊的管理,主要包括以下功能:

      1:試卷管理:從題庫讀取試卷和向客戶端傳送試卷。

      2:客戶端管理(CClientManager類)。從資料庫讀取學生資訊,驗證學生資訊。

      3:監視考生考試狀態。

      4:評分。儲存學生考試狀態和成績。

    客戶端負責生成試卷,主要包括以下功能:

      1:登入伺服器。

      2:生成試卷。

      3:考試計時。考試時間結束考生停止答題。

主要步驟如下:

     客戶端成功連線伺服器後,向伺服器傳送學號。伺服器在收到學號後,會驗證該學號是否存在於資料庫中。如果存在且未登入過,則向客戶端傳送該學生姓名和試卷。否則,項客戶端傳送查無此人資訊。

     客戶端在收到試卷後,向考生顯示準備完成,是否開始答題。考生點選開始答題後,客戶端向伺服器傳送開始答卷訊息。考生開始答卷,客戶端進行計時。考試結束後,客戶端向伺服器傳送答題結果。伺服器在收到答題結果後,對該考生的試卷進行評分,並將結果儲存在資料庫。

    資料包設計:

    為了保證客戶端與伺服器之間資料的正確傳送與接收,在傳送資料時,先發送包頭後傳送包體。包頭指明包體的型別和長度。包頭定義如下:

  1. typedefstruct _header  
  2. {  
  3.    u_short type;//包型別。
  4.    u_short len;//包體長度。
  5. }HEADER;  

     客戶端傳送的資料包型別包括考生狀態和心跳包兩種。在考試期間為了監控考生狀態,客戶端定期向伺服器傳送心跳包,伺服器根據此心跳包判斷客戶端狀態。如果由於意外導致連線斷開,伺服器在一段時間內沒有收到心跳包則斷定客戶端斷線。

客戶端在傳送包頭後,傳送考生狀態,它包括以下幾種:

    登入:此時考生狀態為考生學號。LOGIN

    答卷:此時考生狀態沒有資料。DOING

    交卷:此時考生狀態為答題結果。DONE

    斷線:在伺服器一段時間沒有收到心跳包後,設定客戶端為斷線狀態。DISCONN

    伺服器傳送的資料包型別包括:

    考生姓名和試卷。

    伺服器在驗證考生學號後,向客戶端傳送該考生的姓名和試卷。

    工作流程:

    伺服器啟動後,呼叫InitSocket初始化監聽套接字。讀取資料庫,將試卷讀入記憶體,為傳送做準備。呼叫啟動服務函式,在啟動服務函式內建立接受客戶端請求執行緒和服務執行緒。建立監聽執行緒使用WSAEventSelect模型管理請求套接字。服務執行緒可以有多個,迴圈呼叫GetQueuedCompletionStatus函式,檢查是否有非同步IO已完成。     

    當有套接字請求時,接受執行緒接受請求,並建立CClient物件,加入CClientManager管理的客戶端連結串列。並呼叫CClientAsyRecvHeader執行接收包頭非同步IO操作。

    當有非同步IO完成時,GetQueuedCompletionStatus函式返回,根據IO操作型別IOType決定執行何種操作。

    如果是接收包頭非同步IO完成,根據包頭指定的型別判斷是心跳包,或是狀態包。

如是狀態包,則呼叫接受包體非同步IO函式。在接收包體函式完成後,前兩位元組指定的狀態,執行操作。如果狀態是LOGIN,則是登入狀態。包體長度為hdr.Len。前2位元組為當前狀態,兩位元組後為學號,長度為hdr.Len-2。接收到學號後,從資料庫查詢如果存在此學號,且此學號未登入則傳送姓名。否則傳送登入失敗。GetQueuedCompletionStatus返回時,收到傳送姓名非同步IO完成後,傳送試卷。客戶端收到試卷後對試卷進行解析,生成試卷。

    客戶端向伺服器傳送考試開始包,考試開始,伺服器更新考生狀態為正在考試。客戶端設定一個計時器,每10s向伺服器傳送一個心跳包,表明當前客戶端處於線上狀態,並未離線。伺服器也定義一個計時器,它每隔60s觸發一次,在響應函式內遍歷所有連線的客戶端,檢查它傳送心跳包的時間與當前時間差,如果大於60s則說明客戶端已掉線。將此客戶端從連結串列中刪除。並更新對應考生狀態為掉線。

    考生做完所有試題後,點選交卷,客戶端向伺服器傳送DONE包,包體部分為答案。伺服器更新考生狀態,並計算分數更新到列表控制元件和伺服器。然後刪除客戶端,整個過程結束。

  1. <span style="font-size:18px;">//客戶端向伺服器傳送的包型別。
  2. #define PULSE          107//心跳包。
  3. #define REQUEST          108//請求包。
  4. //伺服器向客戶端傳送的包型別:
  5. #define STUNAME        109//學生姓名。
  6. #define PAPER          110//試卷包。
  7. #define LOGINFAILED    111//登入失敗。</span>

     考試系統的試題型別為選擇題。它包括試題和答案兩部分。題號與問題之間使用:分割。每道題有四個答案,每個答案之間用|分割。試題之間用<>分割。如

<1:問題|A:答案|B:答案|C:答案|D:答案><:問題2|A:答案|B:答案|C:答案|D:答案><:問題3|A:答案|B:答案|C:答案|D:答案><:問題4|A:答案|B:答案|C:答案|D:答案>

資料庫設計

Access資料中儲存了考生資訊和試卷資訊。此處定義了兩張表,分別為StuInfo表和Paper表。。使用ODBC與資料庫連線。由於本文更偏重與介紹IOCP的機制,因此對於資料庫如何使用此處不再介紹。

   StuInfo表包括Stu_ID ,Stu_NO,Stu_Name,Stu_State,Stu_Grade欄位。Stu_ID為主鍵。

    Paper表包括PAP_IDPAP_QUESTIONPAP_ANSWERAPAP_ANSWERBPAP_ANSWERCPAP_ANSWERDPAP_ANSWER。

 伺服器設計:

    伺服器負責傳送試題和對考生考試資訊進行管理。它包括多執行緒設計和介面設計。

    多執行緒設計:

    主執行緒啟動後,建立一個接受客戶端連線請求的執行緒和多個服務執行緒。服務執行緒使用套接字的IO完成埠模型對伺服器的IO操作進行管理。監聽執行緒使用套接字的WSAEventSelect模型實現對接受客戶端請求進行管理。

    當伺服器退出時,主執行緒通知接受客戶端執行緒和服務執行緒退出,然後主執行緒退出。

在接受客戶端連線請求執行緒中,接受客戶端的連線請求後,立即發出一個接受客戶端資料包頭的非同步請求。在服務執行緒取出IO操作結果後,再發起另一個非同步IO操作。

    一:主執行緒:負責初始化介面、讀取資料庫、更新介面、更新資料庫、建立完成埠和通知接受請求執行緒和服務執行緒退出。

    二:接受客戶端請求執行緒,利用WSAEventSelect模型實現對客戶端請求的管理。主要任務為:

    1:接受客戶端連線請求。

    2:將完成埠與套接字關聯起來。

    3:發起非同步接收客戶端資料操作。

    三:服務執行緒,利用IO完成埠實現對IO操作管理。主要任務為:

    1:管理客戶端。

    2:傳送考生姓名和試卷。

    3:接收客戶端資料。

    4:考試結束後,對考生答卷進行評分。

   伺服器程式是基於單文件的MFC應用程式。主要包括一下幾個類:

    1:CCServerView類:檢視類,實現伺服器的主要功能。

2:CClient類:實現與客戶端通訊功能。

3:CClientManager類,實現對連線的客戶端進行管理功能。

    4:CServerAddrDlg類:實現IP地址輸入視窗。

CCServerView類:

     OnInitialUpdate函式實現伺服器初始化功能:初始化列表試圖控制元件、更新列表試圖控制元件和讀取試卷。

     OnStartService實現啟動服務功能。它建立監聽套接字、建立完成埠、建立監聽事件物件和接受客戶端請求執行緒和服務執行緒。

      在伺服器儲存一定數量的習題。在OnInitialUpdate函式中會將這些試題讀入到m_cPaper陣列中。

     CCServerView類的使用者自定義部分為:

  1. public:  
  2.     staticDWORD WINAPI AcceptClientThread(PVOID ppram);  
  3.     staticDWORD WINAPI ServiceThread(PVOID ppram);  
  4.     bool InitSocket();//初始化套接字。
  5.     bool StartService();//開始服務。
  6.     bool StopService();//停止服務。
  7.     CString AuthenticateStuNo(char*);//驗證學號。
  8.     bool ReadPaper();//從資料庫讀取試卷資訊。
  9.     bool ReadStuInfo();//從資料庫讀取學生資訊。
  10.     void ContructPaperBuffer();//構造
  11.     void UpdateClientState(CClient *pClient,USHORT state);  
  12.     void Destroy();  
  13.     bool SaveGradeIntoDB(CClient*pClient);//儲存成績到資料庫。
  14.     bool IsAlreadyLogin(CString StuName);//判斷考生是否已登入。
  15. public:  
  16.     HANDLE m_hIOCP;//完成埠控制代碼。
  17.     HANDLE m_hEvent;//監聽套接字對應事件物件。
  18.     HANDLE m_h[SERVICE_NUMBER+1];//執行緒控制代碼。
  19.     SOCKET m_sListenSocket;//監聽套接字。
  20.     bool m_IsRunning;//判斷伺服器是否執行。
  21.     CDatabase m_StuInfoDB;//考生資訊資料庫類。
  22.     CDatabase m_PaperDB;//試卷資料庫類。
  23.     CListCtrl m_listCrtl;//列表控制元件。
  24.     PaperItem *m_pPaperArray;//試題陣列。PaperItem定義馬上介紹。
  25.     UINT m_numOfPaperItem;//試卷試題數量。
  26.     CString m_PaperBuff;//試卷緩衝區。    
  27.     afx_msg void OnTimer(UINT_PTR nIDEvent);//計時器函式,用於檢查心跳包
  28.     afx_msg void OnStartService();//伺服器開始執行。

     實現為:

  1. // CIOCPDriverLisenceExamServerView 訊息處理程式
  2. void CIOCPDriverLisenceExamServerView::OnInitialUpdate()  
  3. {  
  4.     CView::OnInitialUpdate();  
  5.     // TODO: 在此新增專用程式碼和/或呼叫基類
  6.     m_hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);  
  7.     CString sDriver = TEXT("MICROSOFT ACCESS DRIVER (*.mdb)");  
  8.     CString sDsnStuInfo;  
  9.     CString sFileStuInfo = TEXT("E://DriverLiscenceExam.mdb");//Change path here  
  10.     sDsnStuInfo.Format(TEXT("ODBC;DRIVER={%s};DSN='';DBQ=%s"),sDriver,sFileStuInfo);  
  11.     bool ret=m_StuInfoDB.Open(NULL,false,false,sDsnStuInfo);  
  12.     if(!ret)  
  13.     {  
  14.         MessageBox(TEXT("連線資料庫失敗!"));  
  15.     }  
  16.     InitSocket();  
  17.     ReadPaper();  
  18.     ReadStuInfo();  
  19.     ContructPaperBuffer();  
  20. }  
  21. bool CIOCPDriverLisenceExamServerView::InitSocket()  
  22. {  
  23.     WSAData wsadata;  
  24.     WSAStartup(MAKEWORD(2,2),&wsadata);  
  25.     m_sListenSocket=socket(AF_INET,SOCK_STREAM,0);  
  26.     if(m_sListenSocket==INVALID_SOCKET)  
  27.     {  
  28.         closesocket(m_sListenSocket);  
  29.         WSACleanup();  
  30.         returnfalse;  
  31.     }  
  32. 相關推薦

    Windows socketIOCP例項----IOCP開發駕照理論考試系統

              Windows socket IO完成埠開發駕照理論考試系統例項 這一節我們講解如何利用套接字完成埠開發駕照理論考試系統。 該系統由伺服器和客戶端兩部分組成。     伺服器負責對題庫和學生資訊的管理,主要包括以下功能:       1:試卷管理:從題庫讀取試卷和向客戶

     Windows socketIO完成埠(IOCP)模型開發

           Windows socket之IO完成埠(IOCP)模型開發      IO完成埠是一種核心物件。利用完成埠,套接字應用程式能夠管理數百上千個套接字。應用程式建立完成埠物件後,通過指定一定數量的服務執行緒,為已經完成的重疊IO操作提供服務。該模型可以達到最後的系統性能。       完成埠是一種

    Windows socketSelect模型開發

                                           Windows socket select模型開發。       套接字select模型是一種比較常用的IO模型。利用該模

    Windows socketWSAEventSelect模型

                     WSAEventSelect模型      WSAEventSelect模型是Windows socekts提供的另一個有用非同步IO模型。該模型允許在一個或多個套接字上接收以事件為基礎的網路事件通知。Windows sockets應用程式可以通過呼叫WSAEventSe

    windows api 複製檔案到指定目錄和獲得系統資訊

    #include <iostream> #include <WINDOWS.H> using namespace std; void copySelf() { char szSelfName[MAX_PATH] ; char szDestNa

    Python網路程式設計socket模組基礎例項

    [linux 公社]https://www.linuxidc.com/Linux/2018-12/155920.htm 1、引言 本文呢主要對Python網路程式設計中用到的socket模組進行初步總結。首先從網路基礎理論出發,介紹了TCP協議和UDP協議;然後總結了sock

    Python網路程式設計socket模組基礎例項

      TCP是流協議,而UDP是資料報協議。換句話說,TCP在客戶機和伺服器之間建立持續的開放連線,在該連線的生命期內,位元組可以通過該連線寫出(並且保證順序正確)。然而,通過 TCP 寫出的位元組沒有內建的結構,所以需要高層協議在被傳輸的位元組流內部分隔資料記錄和欄位。 UD

    Socket程式設計TCP例項(附C/C++程式碼詳解)

    說明: 主要分步驟給出Windows平臺下socket程式設計的一個TCP例項;使用WINDOWS下網路程式設計規範Winsock完成網路通訊; 對程式各部分細節進行描述。 套接字有三種傳輸型別SOCK_STREAM    SOCK_DGRAM   SOCK_RAW;

    Windows Socket程式設計UDP實現大檔案的傳輸

    前言:本文實現以下功能:在客戶端,使用者選擇本地的某個檔案,併發送到伺服器端。在伺服器端,接收客戶端傳輸的資料流,並按IP 地址儲存在伺服器端(文件名重複的,可以覆蓋)。如果傳輸過程中伺服器端發現客戶端斷開,伺服器端應刪除檔案,並在螢幕上提示,如“IP:1.2.3.4 發來a

    windows Socket程式設計重疊IO模型

    上一篇文章我們講了EventSelect網路模型,它已經解決了等待資料到來的這一大部分時間,但是它還有一小部分時間沒有節省下來。那就是把資料從網絡卡的緩衝區拷貝到我們應用程式的緩衝區裡邊。而這一篇的重疊IO模型就是將這一小部分的時間也給節省了下來。 首先,我們在主執行緒裡邊

    windows Socket程式設計UDP的服務端和客戶端

    上一篇講了TCP的服務端和客戶端,本篇文章來介紹一下UDP的服務端和客戶端。 相比TCP來說,UDP相對比較簡單,剛開始的時候,和TCP一樣都需要先進行網路環境的初始化,即呼叫WSAStartup函式。然後呢,我們也需要建立一個socket,這個socket和TCP的那個s

    AndroidWindows下搭建React Native Android開發環境(差不多搞了一天)

    Android之Windows下搭建React Native Android開發環境               窮逼買不起mac,但是他們都說React Native Android只能在mac下面執行,然後到網上各種找資料看能不能在Windows下面搭建開發環境,找了幾

    activeMq Windows環境部署及例項開發

    ActiveMQ 是Apache出品,最流行的,能力強勁的開源訊息匯流排。ActiveMQ 是一個完全支援JMS1.1(Java訊息服務)和J2EE 1.4規範的 JMS Provider實現。 1、ActiveMQ下載 有windows和linux兩

    Windows Phone 開發學習筆記(五) Hello Windows Phone虎頭蛇尾

    在上一篇中,只查了下 x:Class="HelloWindowsPhone.MainPage" 的解釋,初步瞭解了XAML和CS檔案之間的關係。而在MainPage.xaml中,還有很多行語句沒有分析 xmlns="http://schemas.microsoft.com/

    Windows Socket 非阻塞模式開發

                                                                      非阻塞套接字            非阻塞模式是指:套接字在執行操作時,呼叫的函式不管操作是否完成都會立即返回的工作模式。     非阻塞套接字在處理同時建立的多個連線等方面具

    Windows Socket程式設計TCP實現大檔案的傳輸

    前言: 本文實現以下功能: 在客戶端,使用者選擇本地的某個檔案,併發送到伺服器端。 在伺服器端,接收客戶端傳輸的資料流,並按IP 地址儲存在伺服器端(文 件名重複的,可以覆蓋)。 如果傳輸過程中伺服器端發現客戶端斷開,伺服器端應刪除檔案,並在螢幕 上提示,如“IP:1.

    Ruby系列文章2 --- Windows下安裝Ruby on Rails 開發環境

    很多童鞋在Windows下安裝Ruby on Rails會遇到各種各樣的問http://題,因此銳氣大大的受到了挫折,所以一直在尋找一種神一樣的方法。 它就是 安裝Ruby on Rails從此不在折騰,非常簡單方便 這個方法是一條龍安裝,包括了Ruby和

    PHP開發Windows桌面應用程式例項

    PHP_GTK2.0 開發桌面應用程式 php gtk 官方網站 http://gtk.php.net/ 官方有gtk的中文手冊 具體安裝請參見 手冊 更簡單的方法是用另外一款軟體 名字叫做gnope 下載地址:http://www.gnope.org/download.p

    Windows伺服器高併發處理IOCP(完成埠)詳細說明

    本系列裡完成埠的程式碼在兩年前就已經寫好了,但是由於許久沒有寫東西了,不知該如何提筆,所以這篇文件總是在醞釀之中……醞釀了兩年之後,終於決定開始動筆了,但願還不算晚…..         這篇文件我非常詳細並且圖文並茂的介紹了關於網路程式設計模型中完成埠的方方面

    Windows Phone 開發學習筆記(二) Hello Windows Phone不費功夫

    現在這個時代,各種技術層出不窮。很長一段時間裡,在開發程式時我首先是搜尋功能相近的例程,以它為基礎,修改實現自己的功能。可這樣只解決一時問題,一旦需要擴充套件功能或者程式出現問題,解決起來毫無頭緒。慢慢意識到基礎的重要,也想仔細讀讀書。可每部書都特別厚,字典一樣,從頭到尾讀