網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)4單播通信實(shí)驗(yàn).doc_第1頁
網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)4單播通信實(shí)驗(yàn).doc_第2頁
網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)4單播通信實(shí)驗(yàn).doc_第3頁
網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)4單播通信實(shí)驗(yàn).doc_第4頁
網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)4單播通信實(shí)驗(yàn).doc_第5頁
已閱讀5頁,還剩9頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

網(wǎng)絡(luò)程序設(shè)計(jì)實(shí)驗(yàn)報(bào)告 實(shí)驗(yàn)名稱:單播通信實(shí)驗(yàn) 實(shí)驗(yàn)類型:設(shè)計(jì)型 指導(dǎo)教師: 專業(yè)班級(jí): 姓 名: 學(xué) 號(hào): 電子郵件: 實(shí)驗(yàn)地點(diǎn): 實(shí) 驗(yàn) 日 期: 年 月 日實(shí)驗(yàn)成績:_ 一、實(shí)驗(yàn)?zāi)康膌 掌握TCP服務(wù)器程序和客戶程序的編程流程; 熟悉面向連接的C/S程序使用的winsock API。二、實(shí)驗(yàn)設(shè)計(jì)實(shí)驗(yàn)內(nèi)容:1、編寫一個(gè)TCP回顯服務(wù)器,將收到的客戶端信息發(fā)送給客戶端,同時(shí)能在同客戶端建立連接后顯示客戶端地址信息和當(dāng)前連接數(shù)。2、編寫一個(gè)TCP客戶端程序能連接到你編寫的服務(wù)器,接收服務(wù)器信息。主函數(shù)使用int main(int argc,char* argv)形式傳入服務(wù)器IP地址和端口。3、測試你編寫的程序,將測試數(shù)據(jù)、測試結(jié)果和結(jié)果分析寫入實(shí)驗(yàn)報(bào)告。實(shí)驗(yàn)步驟:1) 創(chuàng)建套接字函數(shù)socketSOCKET socket(int af,int type,int protocol);/由于采用流套接字進(jìn)行數(shù)據(jù)傳輸,因此type參數(shù)必須設(shè)置為SOCK_STREAM,protocol參數(shù)必須設(shè)置為IPPROTO_TCP。2) 綁定本地地址到所創(chuàng)建的套接字函數(shù)bindint bind(SOCKET s,const struct sockaddr* name,int namelen);3) 監(jiān)聽網(wǎng)絡(luò)連接請(qǐng)求函數(shù)listenint listen(SOCKET s,int backlog);4) 連接請(qǐng)求函數(shù)connectint connect(SOCKET s,const struct sockaddr FAR* name,int namelen);5) 接受請(qǐng)求函數(shù)acceptSOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);6) 發(fā)送數(shù)據(jù)函數(shù)sendint send(SOCKET s,const char* buf,int len,int flags);7) 接收數(shù)據(jù)函數(shù)recvint recv(SOCKET s,char* buf,int len,int flags);8) 關(guān)閉套接字函數(shù)closesocketint closesocket(SOCKET s);3、 實(shí)驗(yàn)過程(包含實(shí)驗(yàn)結(jié)果)1) 服務(wù)端通過socket()函數(shù)建立的套接字sListen與在accept函數(shù)返回后得到的新套接字sClient是兩個(gè)不同的套接字,區(qū)別在于:前者用于服務(wù)端監(jiān)聽連接,在服務(wù)端主進(jìn)程中只創(chuàng)建一次,并且綁定一個(gè)固定的端口號(hào),以便客戶端根據(jù)該端口號(hào)進(jìn)行連接;后者用于與具體某個(gè)發(fā)起連接請(qǐng)求的客戶端進(jìn)行數(shù)據(jù)的交換。它們之間的聯(lián)系在于:套接字sListen在監(jiān)聽到連接后,會(huì)將該連接的相關(guān)請(qǐng)求放到一個(gè)緩沖區(qū)中,套接字sClient在處理完上一個(gè)連接后,會(huì)查詢?cè)摼彌_區(qū)的狀態(tài),并據(jù)此決定是否需要開始一次新的通信過程。請(qǐng)對(duì)照?qǐng)D3-3認(rèn)真領(lǐng)會(huì)服務(wù)端兩類套接字的作用。2) 每個(gè)客戶在建立連接后,可與服務(wù)端負(fù)責(zé)數(shù)據(jù)通信的套接字sClient進(jìn)行多次數(shù)據(jù)交換,只有在所有數(shù)據(jù)交換完成后,由任一方執(zhí)行closesocket(),雙方才會(huì)關(guān)閉該次連接,并釋放對(duì)應(yīng)的套接字。 流程圖: ServerClientSocket()bind()Recvfrom()阻塞,等待客戶連接請(qǐng)求處理服務(wù)請(qǐng)求Sendto()Closesocket()Socket()bind()Sendto()Recvfrom()Closesocket()服務(wù)請(qǐng)求服務(wù)應(yīng)答socket(),建立流式套接字,返回套接字句柄sListen。bind(),關(guān)聯(lián)一個(gè)本地地址到套接字sListen。listen(),設(shè)置backlog值,進(jìn)入監(jiān)聽狀態(tài)。accept(),等待接受客戶連接請(qǐng)求。建立連接,accept函數(shù)返回,得到新的套接字,如sClient。recv()/send(),在套接字sClient上收發(fā)數(shù)據(jù),直到完成交換。closesocket(),關(guān)閉套接字sClient。closesocket(),關(guān)閉監(jiān)聽套接字sListen,服務(wù)結(jié)束。服務(wù)端socket(),建立流式套接字s。connect(),將套接字s與服務(wù)器連接。recv()/send(),在套接字s上收發(fā)數(shù)據(jù),直到數(shù)據(jù)完成交換。closesocket(),關(guān)閉套接字s,結(jié)束TCP對(duì)話??蛻舳诉\(yùn)行結(jié)果截圖: 4、 討論與分析1、 accept()函數(shù),connect( )函數(shù)會(huì)阻塞嗎?如果阻塞,說明在什么情況下阻塞。 請(qǐng)給出在VC環(huán)境下的驗(yàn)證方法。答:accept()函數(shù):請(qǐng)求隊(duì)列為空就阻塞;不為空就不會(huì)阻塞。 connect()函數(shù):不會(huì)阻塞,如果沒服務(wù)器處理,過一會(huì)兒其就會(huì)自動(dòng)返回,連接失敗,不會(huì)堅(jiān)持到底。2、 connect()函數(shù)調(diào)用觸發(fā)什么過程?答:觸發(fā)三次握手過程。3、 你在服務(wù)端和客戶端分別使用了哪些Winsock API函數(shù),起什么作用?答:服務(wù)端:recv()接收數(shù)據(jù)函數(shù); bind()綁定本地地址到所創(chuàng)建的套接字函數(shù);listen()進(jìn)入監(jiān)聽狀態(tài); accept()等待接受客戶連接請(qǐng)求;send()發(fā)送數(shù)據(jù)函數(shù)客戶端:bind() 可以使用來綁定,也可以不用。connect()將套接字與服務(wù)器連接。 recv()/send()在套接字上收發(fā)數(shù)據(jù),直到數(shù)據(jù)完成交換。 5、 實(shí)驗(yàn)者自評(píng)(從實(shí)驗(yàn)設(shè)計(jì)、實(shí)驗(yàn)過程、對(duì)實(shí)驗(yàn)知識(shí)點(diǎn)的理解上給出客觀公正的自我評(píng)價(jià)) 通過此次實(shí)驗(yàn)我對(duì)tcp協(xié)議有了更深的理解。六、附錄:關(guān)鍵代碼(給出適當(dāng)注釋,可讀性高) Client/ TcpClient.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。/#include stdafx.h#include stdafx.h#include #include #include using namespace std; #pragma comment(lib,WS2_32.lib) #define BUF_SIZE 64 / 緩沖區(qū)大小 int main(int argc, CHAR* argv)WSADATA wsd;/ 用于初始化Windows Socket SOCKET sHost;/ 與服務(wù)器進(jìn)行通信的套接字 SOCKADDR_IN servAddr;/ 服務(wù)器地址 char bufBUF_SIZE;/ 用于接受數(shù)據(jù)緩沖區(qū) int retVal;/ 調(diào)用各種Socket函數(shù)的返回值 / 初始化Windows Socket if(WSAStartup(MAKEWORD(2,2),&wsd) != 0) printf(WSAStartup failed !n); return 1; / 創(chuàng)建套接字 sHost = socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(INVALID_SOCKET = sHost) printf(socket failed !n); WSACleanup(); return -1; / 設(shè)置套接字為非阻塞模式int iMode = 1;retVal = ioctlsocket(sHost, FIONBIO, (u_long FAR*) &iMode);if(retVal = SOCKET_ERROR)printf(ioctlsocket failed !n);WSACleanup();return -1; / 設(shè)置服務(wù)器地址 servAddr.sin_family = AF_INET; servAddr.sin_addr.S_un.S_addr = inet_addr(/*127.0.0.1*/argv1);/ 用戶需要根據(jù)實(shí)際情況修改 servAddr.sin_port = htons(/*9990*/atoi(argv2);/ 在實(shí)際應(yīng)用中,建議將服務(wù)器的IP地址和端口號(hào)保存在配置文件中 int sServerAddlen = sizeof(servAddr);/ 計(jì)算地址的長度 / 循環(huán)等待while(true)/ 連接服務(wù)器 Sleep( 200 );retVal = connect(sHost,(SOCKADDR*)&servAddr,sizeof(servAddr); Sleep( 200 );if(SOCKET_ERROR = retVal) int err = WSAGetLastError();if(err = WSAEWOULDBLOCK | err = WSAEINVAL)/ 無法立即完成非阻塞套接字上的操作/Sleep(500);continue;else if(err = WSAEISCONN)/ 已建立連接break;elsecontinue;/printf(connect failed !n); /closesocket(sHost); /WSACleanup(); /return -1; / 循環(huán)向服務(wù)器發(fā)送字符串,并顯示反饋信息。/ 發(fā)送quit將使服務(wù)器程序退出,同時(shí)客戶端程序自身也將退出while(true)/ 向服務(wù)器發(fā)送數(shù)據(jù) printf(Please input a string to send:n );/ 接收輸入的數(shù)據(jù)std:string str;cinstr;/ 將用戶輸入的數(shù)據(jù)復(fù)制到buf中ZeroMemory(buf,BUF_SIZE); strcpy(buf,str.c_str(); / 循環(huán)等待while(true)/ 向服務(wù)器發(fā)送數(shù)據(jù)retVal = send(sHost,buf,strlen(buf),0); if(SOCKET_ERROR = retVal) int err = WSAGetLastError();if(err = WSAEWOULDBLOCK)/ 無法立即完成非阻塞套接字上的操作Sleep(500);continue;elseprintf(send failed !n); closesocket(sHost); WSACleanup(); return -1; break; while(true)ZeroMemory(buf,BUF_SIZE);/ 清空接收數(shù)據(jù)的緩沖區(qū)retVal = recv(sHost,buf,sizeof(buf),0); / 接收服務(wù)器回傳的數(shù)據(jù) if(SOCKET_ERROR = retVal) int err = WSAGetLastError();/ 獲取錯(cuò)誤編碼if(err = WSAEWOULDBLOCK)/ 接收數(shù)據(jù)緩沖區(qū)暫無數(shù)據(jù)Sleep(100);/printf(waiting back msg !n);continue;else if(err = WSAETIMEDOUT | err = WSAENETDOWN)printf(recv failed !n); closesocket(sHost); WSACleanup(); return -1;break; break;/ZeroMemory(buf,BUF_SIZE);/ 清空接收數(shù)據(jù)的緩沖區(qū)/retVal = recv(sHost,buf,sizeof(buf)+1,0); / 接收服務(wù)器回傳的數(shù)據(jù) printf(Recv From Server: %sn,buf); / 如果收到quit,則退出if(strcmp(buf, quit) = 0)printf(quit!n);break; / 釋放資源 closesocket(sHost); WSACleanup(); / 暫停,按任意鍵繼續(xù)system(pause); return 0; Sever/ TcpServer.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。/#include stdafx.h #include #include #include using namespace std;#pragma comment(lib,WS2_32.lib) #define BUF_SIZE 64 / 緩沖區(qū)大小int num = 0;sockaddr_in addrClient;/ 客戶端地址DWORD WINAPI AnswerThread(LPVOID lparam) char bufBUF_SIZE;/ 用于接受客戶端數(shù)據(jù)的緩沖區(qū) int retVal;/ 調(diào)用各種Socket函數(shù)的返回值 SOCKET sClient=(SOCKET)(LPVOID)lparam; / 循環(huán)接收客戶端的數(shù)據(jù),直接客戶端發(fā)送quit命令后退出。 while(true)ZeroMemory(buf,BUF_SIZE);/ 清空接收數(shù)據(jù)的緩沖區(qū)retVal = recv(sClient,buf,BUFSIZ,0);/ 接收來自客戶端的數(shù)據(jù),因?yàn)槭欠亲枞J?,所以即使沒有數(shù)據(jù)也會(huì)繼續(xù)if(SOCKET_ERROR = retVal) int err = WSAGetLastError();/ 獲取錯(cuò)誤編碼if(err = WSAEWOULDBLOCK)/ 接收數(shù)據(jù)緩沖區(qū)暫無數(shù)據(jù)Sleep(100);continue;else if(err = WSAETIMEDOUT | err = WSAENETDOWN)printf(recv failed !n); closesocket(sClient); WSACleanup(); return -1; / 獲取當(dāng)前系統(tǒng)時(shí)間SYSTEMTIME st;GetLocalTime(&st);char sDateTime30;sprintf(sDateTime, %4d-%2d-%2d %2d:%2d:%2d,st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);/ 打印輸出的信息printf(%s, Recv From Client %s:%d :%sn, sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf); /*if (buf0 = q&buf1 = u&buf2 = i&buf3 = t)num-;cout 當(dāng)前連接數(shù): num endl;*/ 如果客戶端發(fā)送quit字符串,則服務(wù)器退出if(strcmp(buf, quit) = 0)num-;cout 當(dāng)前連接數(shù): num endl;retVal = send(sClient,quit,strlen(quit),0); break;else/ 否則向客戶端發(fā)送回顯字符串char msgBUF_SIZE; sprintf(msg, Message received - %s, buf); while(true)/ 向服務(wù)器發(fā)送數(shù)據(jù)retVal = send(sClient, msg, strlen(msg),0); if(SOCKET_ERROR = retVal) int err = WSAGetLastError();if(err = WSAEWOULDBLOCK)/ 無法立即完成非阻塞套接字上的操作Sleep(500);continue;elseprintf(send failed !n); closesocket(sClient); WSACleanup(); return -1; break; / 關(guān)閉套接字 closesocket(sClient); return 0;int _tmain(int argc, _TCHAR* argv)WSADATA wsd;/ WSADATA變量,用于初始化Windows Socket SOCKET sServer;/ 服務(wù)器套接字,用于監(jiān)聽客戶端請(qǐng)求 SOCKET sClient;/ 客戶端套接字,用于實(shí)現(xiàn)與客戶端的通信 int retVal;/ 調(diào)用各種Socket函數(shù)的返回值 / 初始化套接字動(dòng)態(tài)庫 if(WSAStartup(MAKEWORD(2,2),&wsd) != 0) printf(WSAStartup failed !n); return 1; / 創(chuàng)建用于監(jiān)聽的套接字 sServer = socket(AF_INET,SOCK_STREAM, IPPROTO_IP); if(INVALID_SOCKET = sServer) printf(socket failed !n); WSACleanup(); return -1; / 設(shè)置套接字為非阻塞模式int iMode = 1;retVal = ioctlsocket(sServer, FIONBIO, (u_long FAR*) &iMode);if(retVal = SOCKET_ERROR)printf(ioctlsocket failed !n);WSACleanup();return -1; / 設(shè)置服務(wù)器套接字地址 SOCKADDR_IN addrServ; addrServ.sin_family = AF_INET; addrServ.sin_port = htons(9990);/ 監(jiān)聽端口為9990 addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); / 綁定套接字sServer到本地地址,端口9990 retVal = bind(sServer,(const struct sockaddr*)&addr

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論