1. 程式人生 > >使用C(或C++)語言編寫網路通訊模擬程式

使用C(或C++)語言編寫網路通訊模擬程式

實驗題目

綜合實驗

一、實驗目的

熟悉和掌握網路程式設計的基本方法和步驟;進一步理解 client/server 互動模式;加深學生對於網路協議概念的理解以及協議的設計和實現方法。

 

二、裝置與環境

微型計算機、Windows 系列作業系統 、Visual C++6.0軟體

 

三、實驗內容

使用C(或C++)語言編寫網路通訊模擬程式,它由 client 和 server 兩部分組成, client 和 server 之間的通訊基於 TCP 或者UDP協議,要求能夠實現客戶和伺服器端的互動對話。

具體:

1) 伺服器和客戶端有提示;

2) 服務啟動後處於監聽狀態等待客戶機連線,當有客戶連線時給出提示,並   顯示客戶IP地址,並給客戶端傳送問候訊息;

3) 客戶機端要求啟動後主動連線伺服器,也可以通過選單控制連線的時機,   連線成功後給出提出;

4)在通訊連線建立之後,客戶和伺服器雙方可以進行聯絡的訊息傳遞,直至一方傳送quit訊息,斷開連線。

5)要求介面儘量友好,功能儘量完善,可考慮增加功能選單,提高系統的互動性。

6) 對功能進行適當分解,用若干函式完成系統

 

 

四、實驗結果及分析

  1、變數定義:

    (1)需要定義套接字型別變數,因為套接字存在於地址族中,可以將通過套接字通訊的程序的公有特性綜合在一起。套接字通常只與同一區域的套接字交換資料。Windows Sockets只支援AF_INET網路域,使用網際協議族通訊的程序使用該域。因此只有將資料轉換成Socket型別的資料才可以進行傳輸。

 

    (2)定義地址結構體,用於儲存協議族、ip地址以及埠號。其中,在地址結構體sockaddr_in中的sin_family部分指代協議族,也用於存放協議族資訊,這一項在socket程式設計中只能是AF_INET,地址結構體sockaddr_in中的sin_addr部分用於儲存ip地址,而sin_port部分則用於儲存埠號

 

 

    (3)定義雙位元組型數值Socket版本,這裡必須要提及MAKEWORD函式,MAKEWORD函式的作用是將兩個byte型別合併成一個雙位元組型,其中一個在高8位,另一個在低8位。將MAKEWORD函式合併成的雙位元組型值賦給雙位元組型數值sockVersion作為Socket版本。

 

 

    (4)定義WSADATA型別的值,用來儲存返回的Sockets資料。WSADATA是一種資料結構。這個結構被用來儲存被WSAStartup函式呼叫後返回的Windows Sockets資料。

 

 

  2、函式介紹:

    在server程式中:

  1. 服務啟動函式start():
    1. 該函式用於啟動伺服器,若啟動成功返回0,啟動失敗則返回-1。其中應用到了WSAStartup函式,作用是啟動WSA,這個函式的第一個引數為程式請求使用的Socket版本,第二個引數為返回請求的版本資訊,返回值為0時成功。
    2. Socket函式用於根據指定的地址族、資料型別和協議來分配一個套介面的描述字及其所用的資源,3個引數分別為協議族、套接字型別和協議。另外,將對應的值分別儲存到地址結構體中專門存放協議族、ip地址以及埠號的sin_family、sin_addr和sin_port。
    3. 除此之外,start()函式中還用到了庫函式bind(),bind函式的作用是把socket與協議、ip地址、埠號繫結起來,由於bind函式的返回值表示繫結操作是否成功(0表示成功, -1表示不成功),因此可以對bind函式用if語句判斷。bind函式中的第一個引數是待繫結的套接字,第二個引數是標識繫結在哪個“地方”,第三個引數則是這個“地方”的佔地大小                                                                                                                                                                 
    4. start函式中還用到了listen(),listen函式使用主動連線套介面變為被連線套介面,使得一個程序可以接受其它程序的請求,從而成為一個伺服器程序。在TCP伺服器程式設計中listen函式把程序變為一個伺服器,並指定相應的套接字變為被動連線。listen函式的第一個引數表示被listen函式作用的套接字,第二個引數表示佇列核心的上限。另外,listen函式返回值表示偵聽是否成功(0表示成功, -1表示不成功),因此也可以對listen函式用if語句判斷。

 

 

 

 

  1. 服務停止函式stop():                                                                                                                                                                                           該函式用於停止伺服器,首先對startOK的值進行判斷,若startOK的值已經被賦為0(伺服器已經啟動),則開始關閉伺服器。               其中涉及到了closesocket函式,closesocket函式的作用和socket函式的作用相反,釋放為套接字分配的資源。                                         而另一個用到的函式WSACleanup()則和WSAStartup函式的作用相反,終止對WSA的使用。

 

 

 

  1. 接收客戶端連線函式acceptClient():
    1. 該函式用於接收客戶端連線,其中涉及到的accept函式則用於接收客戶端的請求,accept函式第一個引數是待連線的套接字,第二個引數是待連線地址結構體的“位置”,第三個引數則是地址指向“位置”的長度。
    2. 另外,inet_ntoa()為IP地址轉換函式,用於把網路位元組序IP轉化點分十進位制IP。而send()函式則用於傳送資料,應用程式使用send函式向TCP連線的另一端傳送資料,其中尤其需要注意的是send()函式的第四個引數,第四個引數為flags,一般置0。
    3. kbhit()函式是一個系統自帶的庫函式,用於判斷鍵盤是否有按下,若鍵盤有按下則返回1,若鍵盤沒有按下則返回0。
    4. acceptClient()函式中使用到的setsockopt()函式則用於套介面設定選項值,其中第一個引數是待設定的套接字,第二個引數表示選項定義的層次,第三個引數表示需設定的選項,其中SO_RCVTIMEO指超時時間,第四個引數表示指向存放選項值的緩衝區的指標,第五個引數則表示緩衝區長度,也就是int型別的長度。
    5. recv函式用於接收客戶端的資料,其中需要注意的是它的第三個引數表示緩衝區長度,也就是最長能接收的緩衝資料量,第四個引數send()函式相同,意思也是為flags,一般也置0 。

 

 

 

 

 

 

  1. 選單函式menu():                                                                                                                                                                                                     僅僅用於輸出選單。
  2. 主函式main():                                                                                                                                                                                                           使用while(1)來執行無限迴圈,並輸出選單。根據輸入的值不斷呼叫之前的那幾個函式,當輸入5時,執行exit(0)退出。

在client程式中:

  1. 連線伺服器函式connectServer():
    1. 該函式用於連線伺服器,若啟動成功返回0,啟動失敗則返回-1。其中應用到了WSAStartup函式,作用是啟動WSA,這個函式的第一個引數為程式請求使用的Socket版本,第二個引數為返回請求的版本資訊,返回值為0時成功。
    2. Socket函式用於根據指定的地址族、資料型別和協議來分配一個套介面的描述字及其所用的資源,3個引數分別為協議族、套接字型別和協議。另外,將對應的值分別儲存到地址結構體中專門存放協議族、ip地址以及埠號的sin_family、sin_addr和sin_port。
    3. 除此之外,connectServer()函式中還用到了庫函式connect(),connect函式用於連線伺服器,其中第一個引數是客戶端的套接字,第二個引數是服務端的套接字所在的“地方”,第三個引數是該“地方”的大小,如果請求連線成功,則返回0,否則返回錯誤碼。                                              
    4. connectServer函式中還用到了inet_ntoa函式,inet_ntoa()為IP地址轉換函式,用於把網路位元組序IP轉化點分十進位制IP。

 

 

 

 

 

  1. 伺服器對話函式ChatWithServer():
    1. ChatWithServer函式中用到了kbhit函式,kbhit()函式是一個系統自帶的庫函式,用於判斷鍵盤是否有按下,若鍵盤有按下則返回1,若鍵盤沒有按下則返回0。
    2. 其中通過判斷connectOK的值來判斷伺服器是否已經連線,若connectOK的值為0則表示已經與伺服器連線,可以進行接下來的對話步驟。
    3. buf緩衝區變數存放著要傳送的資料,用gets函式來讀字串。首先用系統自帶函式kbhit(),來判斷鍵盤是否有按下,與之前相同,若鍵盤有按下,則讀取緩衝區中要傳送的資料,並呼叫send()函式。應用程式使用send函式向TCP連線的另一端傳送資料。
    4. 對輸入的資料進行判斷,若輸入的資料為"bye"、"再見"或者是"quit",則呼叫清屏函式,並輸出選單和停止函式。
    5. 設定recv的超時時間,超時則返回,不等待。這需要用到setsockopt函式,setsockopt()函式用於套介面設定選項值,它的第一個引數是待設定的套接字,第二個引數表示選項定義的層次,第三個引數表示需設定的選項,其中SO_RCVTIMEO指超時時間,第四個引數表示指向存放選項值的緩衝區的指標,第五個引數則表示緩衝區長度,也就是int型別的長度。
    6. 另外,還用到了recv(),recv函式用於接收客戶端的資料,其中需要注意的是它的第三個引數表示緩衝區長度,也就是最長能接收的緩衝資料量,第四個引數send()函式相同,意思也是為flags,一般也置0 。
    7. 最後,用if進行判斷,如果接收到的資料長度>0,則輸出recvBuf[]中的資料並顯示。對接收到的資料進行判斷,若接收到的資料為"bye"、"再見"或者是"quit",則呼叫清屏函式,並輸出選單和停止函式。

 

 

 

 

 

  1. 客戶端停止函式stop():
    1. 該函式用於停止客戶端,首先對sockClient的值進行判斷,若sockClient的值為1(客戶端已經啟動),則開始關閉客戶端。其中涉及到了closesocket函式,closesocket函式的作用和socket函式的作用相反,釋放為套接字分配的資源。
    2. 而另一個用到的函式WSACleanup()則和WSAStartup函式的作用相反,終止對WSA的使用。

 

 

 

  1. 選單函式menu():                                                                                                                                                                                       僅僅用於輸出選單。
  2. 主函式main():                                                                                                                                                                                           使用while(1)來執行無限迴圈,並輸出選單。根據輸入的值不斷呼叫之前的那幾個函式,當輸入5時,執行exit(0)退出。