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