|
網(wǎng)絡(luò)程序設(shè)計實驗報告 一、實驗目的
1.熟悉UDP下socket編程,掌握socket編程的具體實現(xiàn)步驟
2.熟悉進程間通信方式,掌握常用IPC編程方法
3.熟悉并發(fā)服務器模型,掌握一種編程方法
二、實驗內(nèi)容
1.用UDP套接字實現(xiàn)流式通信
2.用管道,套接字,共享內(nèi)存實現(xiàn)一個大文件的傳輸并比較他們的速率
3.創(chuàng)建一個TCP并發(fā)服務,并可支持斷點續(xù)傳。
三、實驗步驟
1.用UDP套接字實現(xiàn)流式通信
基于UDP套接字的編程模型如下:
0.png (19.67 KB, 下載次數(shù): 107)
下載附件
2016-3-14 15:33 上傳
其中,在服務器端,服務器創(chuàng)建socket描述符,并將該描述符邦定到本服務器地址上,接著調(diào)用接收函數(shù)recvfrom,如果此時客戶端沒有發(fā)來UDP請求,服務器一直阻塞在recvfrom函數(shù)。當服務器接收到客戶端發(fā)來的UDP請求后,服務器端繼續(xù)執(zhí)行recvfrom函數(shù)之后的代碼,處理客戶端請求,處理完成后再通過sendto函數(shù)無阻塞地將處理結(jié)果返回到客戶端,之后服務器端循環(huán)又回到recvfrom函數(shù),等待客戶端的UDP請求。
在客戶端,用戶創(chuàng)建socket描述符,并將該描述符邦定到指定的服務器地址上,接著調(diào)用發(fā)送函數(shù)sendto將客戶端的請求通過UDP無阻塞地發(fā)送到服務器,接著執(zhí)行到接收函數(shù)recvfrom,如果服務器還沒有UDP請求發(fā)送到客戶端,客戶端一直阻塞在該函數(shù)。當服務器執(zhí)行完客戶端的請求,并把結(jié)果通過UDP發(fā)送到客戶端后,客戶端接收結(jié)果,最后客戶端關(guān)閉socket端口,客戶端與服務器的一次對話結(jié)束。
2.用管道,套接字,文件共享實現(xiàn)一個大文件的傳輸
(1)管道可以用于具有親緣關(guān)系的進程間通信,命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān)系的進程之間通信。當進程創(chuàng)建一個管道的時候,系統(tǒng)內(nèi)核同時為該進程設(shè)立了一對文件句柄,一個用來從管道獲取數(shù)據(jù),另一個用來向管道輸出數(shù)據(jù),如圖2-1。在主進程中利用fork()函數(shù)創(chuàng)建一個子進程,該子進程繼承了父進程打開的文件句柄,利用繼承的句柄,就可以實現(xiàn)父子進程之間的通信,如圖2-2。
現(xiàn)在,父子兩個進程同時擁有對同一個管道的讀寫句柄,因為管道必須是單向的,所以還需要決定數(shù)據(jù)的流動方向是從父進程到子進程還是從子進程到父進程,然后在每個進程中關(guān)閉不需要的句柄。假設(shè)需要利用管道完成從父進程向子進程傳送數(shù)據(jù),關(guān)閉了相應句柄后的管道如圖2-3所示。
1.png (13.08 KB, 下載次數(shù): 100)
下載附件
2016-3-14 15:33 上傳
通過以上操作后,建立好像完整的管道數(shù)據(jù)通路,就可以利用標準的讀寫函數(shù)read()、write()對管道進行讀寫操作了。
在具體的C程序中,使用pipe()函數(shù)來建立管道。它只有一個參數(shù):一個有兩個成員的整形數(shù)組,用于存放pipe()函數(shù)新建立的管道句柄。
(2)套接字是兩個通信通道上得端點。套接字函數(shù)可以用來產(chǎn)生通信信道,通過信道兩個應用程序間可以傳送數(shù)據(jù)。由于需要傳輸?shù)氖俏募赃x擇安全機制較高的TCP套接字。基于TCP套接字的編程模型如下:
0.png (15.5 KB, 下載次數(shù): 127)
下載附件
2016-3-14 15:34 上傳
在服務器端,服務器創(chuàng)建socket描述符,將該描述符邦定到自己的IP地址上,再設(shè)置最大連接請隊列長度,接著用accept接收請求函數(shù)等待客戶端的請求,如果沒有收到客戶端的請求,服務器就阻塞在此。收到客戶端請求后,服務器讀取該請求,經(jīng)過處理,最后將處理結(jié)果通過write寫函數(shù)返回到客戶端。
在客戶端,用戶程序創(chuàng)建socket描述符,并用connet連接函數(shù)將該描述符連接到服務器的地址上,連接上后客戶端通過write寫函數(shù)將請求發(fā)送到服務器,服務器經(jīng)過處理將結(jié)果返回客戶端,客戶端通過read函數(shù)讀取處理結(jié)果,當服務器沒有結(jié)果返回時,客戶端將一直阻塞在read函數(shù)。
(3)共享內(nèi)存實現(xiàn)進程間通信,系統(tǒng)在內(nèi)存中指定一個區(qū)域作為共享存儲區(qū)域,建立一張表進行管理,各進程可以申請其中的一個存儲段,并在申請時提供關(guān)鍵字。若申請的存儲區(qū)已經(jīng)被其他進程所有,則系統(tǒng)向申請進程返回關(guān)鍵字,該存儲區(qū)就連接了進程的邏輯地址空間,此后進程就可以直接存取共享存儲區(qū)中的數(shù)據(jù)了;若申請的存儲段尚未分配,則系統(tǒng)會按照申請者的要求分配存儲段,并在段表中加入該進程的信息。一個進程可以申請多個存儲段,使用共享存儲區(qū)進行通信時進程間的互斥或同步要靠其他的機構(gòu)來解決。
在調(diào)試代碼的時候發(fā)現(xiàn)用共享內(nèi)存的方式傳輸一個5MB左右的文件的時候可以,但是傳輸100多MB的文件時,創(chuàng)建共享內(nèi)存的函數(shù)shmget()返回報錯。在網(wǎng)上搜也沒有搜到合適的解答,后來偶然發(fā)現(xiàn)了shmmax這個參數(shù),在往上搜索這個參數(shù)發(fā)現(xiàn)Linux對共享內(nèi)存的大小有限制。后來找到了解決的辦法,用echo 268435456 > /proc/sys/kernel/shmmax 指令臨時把系統(tǒng)最大共享內(nèi)存限制提高到256MB,之后再調(diào)試程序,發(fā)現(xiàn)大文件可以傳輸,問題解決。但隨后又發(fā)現(xiàn)一個問題,在用共享內(nèi)存方式傳送小文件時速度很快,平均300MB/s左右。但在傳送大文件時,速度比較慢,平均幾十MB/s左右,對于該問題,我也沒弄清是怎么回事。
3.創(chuàng)建一個TCP并發(fā)服務,支持斷點續(xù)傳
原本打算參考一個Linux下的基于命名行的開源Ftp客戶端軟件cmdftp,找的是比較原始的0.7.3版本,代碼不多,不到3000行,但是自己閱讀之后發(fā)下里面的命令解析過于復雜,而且應用層用的Ftp協(xié)議也比較龐大;找了開源的Ftp服務器端軟件,發(fā)現(xiàn)異常龐大,在短時間內(nèi)幾乎不可能完成。所以最后采用了網(wǎng)上的一個基于MFC開發(fā)的Windows下的局域網(wǎng)文件傳輸工具。
四、實驗結(jié)果
以上各個實驗均在Fedora9下,使用Qt Creator開發(fā)環(huán)境調(diào)試通過,各個實驗的結(jié)果截圖如下:
1.用UDP套接字實現(xiàn)流式通信
image001.png (64.58 KB, 下載次數(shù): 113)
下載附件
2016-3-14 15:44 上傳
客戶端程序運行情況
image002.png (93.79 KB, 下載次數(shù): 121)
下載附件
2016-3-14 15:44 上傳
服務器端程序運行情況
image003.png (69.58 KB, 下載次數(shù): 108)
下載附件
2016-3-14 15:44 上傳
QT4開發(fā)環(huán)境 2.用管道,套接字,文件共享實現(xiàn)一個大文件的傳輸
image004.png (105.78 KB, 下載次數(shù): 103)
下載附件
2016-3-14 15:44 上傳
管道傳輸
image005.png (65.49 KB, 下載次數(shù): 101)
下載附件
2016-3-14 15:44 上傳
QT4開發(fā)環(huán)境
image006.png (110.06 KB, 下載次數(shù): 109)
下載附件
2016-3-14 15:44 上傳
套接字傳輸客戶端
image007.png (119.43 KB, 下載次數(shù): 108)
下載附件
2016-3-14 15:44 上傳
套接字傳輸服務器端
image008.png (64.45 KB, 下載次數(shù): 137)
下載附件
2016-3-14 15:44 上傳
QT4開發(fā)環(huán)境
image009.png (102.06 KB, 下載次數(shù): 113)
下載附件
2016-3-14 15:44 上傳
共享內(nèi)存?zhèn)鬏敚ㄐ∥募?/font>
image010.png (103.15 KB, 下載次數(shù): 121)
下載附件
2016-3-14 15:44 上傳
共享內(nèi)存?zhèn)鬏敚ù笪募?/font> 可以看出,除了用共享內(nèi)存?zhèn)鬏敶笪募ㄟ@種情況下為何速度不高沒有弄清楚)這種情況。傳輸速度依次為: 管道:42 MB/s 套接字:47 MB/s 共享內(nèi)存:300 MB/s 無疑,共享內(nèi)存速度最快,按照理論管道應該比套接字速度快,但本實驗中發(fā)現(xiàn)套接字竟然比管道速度快,這個問題也沒有弄清楚。
image011.png (59.51 KB, 下載次數(shù): 125)
下載附件
2016-3-14 15:44 上傳
QT4卡開發(fā)環(huán)境 3.創(chuàng)建一個TCP并發(fā)服務,支持斷點續(xù)傳
image012.jpg (48.73 KB, 下載次數(shù): 112)
下載附件
2016-3-14 15:44 上傳
服務器端傳輸程序界面
image013.jpg (53.56 KB, 下載次數(shù): 114)
下載附件
2016-3-14 15:44 上傳
客戶端接收程序界面 五、實驗總結(jié) 通過本次課程設(shè)計,初步了解了Linux下的網(wǎng)絡(luò)程序設(shè)計的步驟,對基于套接字的編程有了個新的認識。Qt集成開發(fā)環(huán)境使Linux下的C/C++開發(fā)方便了許多,無論是代碼編寫還是調(diào)試運行。雖然沒有獨立完成最后一題,但也通過在嘗試自己編寫,自己閱讀開源的小型Ftp客戶端軟件,對Linux的Shell編程有了新的認識,尤其對如何利用標準C編寫跨平臺程序。總體通過這次作業(yè),收獲到了很多以前不了解或了解不深入的東西,對網(wǎng)絡(luò)程序設(shè)計有了新的認識。
下面是部分源碼,完整代碼請下載51黑的附件: - #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- int main(int argc, char ** argv)
- {
- if(argc != 2)
- {
- printf("usage: udp_client portnum");
- exit(1);
- }
- short port = atoi(argv[1]);
- int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if(sockfd == -1)
- {
- printf("error create socket!");
- exit(1);
- }
- struct sockaddr_in srvaddr;
- srvaddr.sin_family = AF_INET;
- srvaddr.sin_port = htons(port);
- if(inet_aton("127.0.0.1", &srvaddr.sin_addr) == -1)
- {
- printf("error address convert!");
- exit(1);
- }
- char buf[100];
- struct timeval time;
- while(1)
- {
- gettimeofday(&time, NULL);
- sprintf(buf,"this is hello from client! %d",(int)time.tv_sec);
- sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
- sleep(1);
- }
- }
復制代碼 論文和程序下載:
0.png (37.16 KB, 下載次數(shù): 115)
下載附件
2016-3-14 15:43 上傳
網(wǎng)絡(luò)程序設(shè)計報告 源碼.rar
(2.06 MB, 下載次數(shù): 9)
2016-3-14 15:39 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|
|