2017-2018-1 《信息安全系统设计基础》实验三报告
2017-2018-1 《信息安全系統(tǒng)設(shè)計(jì)基礎(chǔ)》實(shí)驗(yàn)三報(bào)告
本小組成員:20155303、20155213
————————CONTENTS————————
- 任務(wù)一 C語(yǔ)言模擬wc命令
- 任務(wù)二 實(shí)現(xiàn)傳送文本文件的服務(wù)器和客戶端
- 任務(wù)三 多線程實(shí)現(xiàn)傳送文本文件的服務(wù)器和客戶端
- 任務(wù)四 使用PC機(jī)和實(shí)驗(yàn)箱模擬客戶端服務(wù)器并測(cè)試
- 實(shí)驗(yàn)感想與體會(huì)
- 參考資料
任務(wù)一 C語(yǔ)言模擬wc命令
使用man wc命令查看wc命令的基本用法:
可知wc命令的功能為:統(tǒng)計(jì)指定文件中的字節(jié)數(shù)、字?jǐn)?shù)、行數(shù)等,并將統(tǒng)計(jì)結(jié)果顯示輸出。常用的參數(shù)為:
- -c:統(tǒng)計(jì)字節(jié)數(shù)
- -l:統(tǒng)計(jì)行數(shù)
- -m:統(tǒng)計(jì)字符數(shù),且不能與-c參數(shù)一起使用
- -w:統(tǒng)計(jì)字?jǐn)?shù),一個(gè)字被定義為由空白、跳格或換行字符分割的字符串
- -L:打印最長(zhǎng)行的長(zhǎng)度
- ......
但是,如果我們想統(tǒng)計(jì)某文件中出現(xiàn)過(guò)某個(gè)特定單詞的行數(shù),只用wc命令是無(wú)法完成的。我們可以借助管道將wc命令與其他命令(如grep)串聯(lián)起來(lái):
grep and test.txt | wc -l
上面命令實(shí)現(xiàn)了查找test.txt中所有出現(xiàn)過(guò)“and”這個(gè)單詞的行,并統(tǒng)計(jì)行數(shù)。
再進(jìn)一步,如果想精確到個(gè)數(shù)(比如一行出現(xiàn)兩次,算作2),可以加上參數(shù)-o選項(xiàng)(only),表示只選中那些匹配的地方,結(jié)果為:
基于以上分析,代碼如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> void wc_func(char *file,int ism,int isw,int isl); int main(int argc ,char *argv[]){int ism,isw,isl,opt;ism = isw = isl = 0;int count = 0;while((opt=getopt(argc,argv,"mwl"))!=-1){count++;switch(opt){case 'm':ism=1;break;case 'w':isw=1;break;case 'l':isl=1;break;case '?':printf("請(qǐng)查看該指令說(shuō)明文檔 %c\n",optopt);exit(0);}} if(count==0){ism=isw=isl=1;}if(optind==argc){printf("wc error: have no file!\n");}for(;optind<argc;optind++){wc_func(argv[optind],ism,isw,isl);} } void wc_func(char *file,int ism,int isw,int isl) {int t,m,w,l;int state = 0;FILE *in;if((in = fopen(file,"r"))==NULL){printf("wc %s:no this file or dir\n",file);return;}w=m=l=0;while((t=fgetc(in))!=EOF){/*if(t=='\t'||t==' '){ w++;}else if(t=='\n'){l++;}*/if(t == '\n') {l++;state = 0;continue;} else if(t == ' ') {state = 0;continue;} else if(t == '\r') {state = 0;continue;} else {if(state == 0) {state = 1;w++;}continue;}m++; }if(isl)printf("%-5d",l);if(isw)printf("%-5d",w);if(ism)printf("%-5d",m);printf("%-10s\n",file); }運(yùn)行結(jié)果如下:
返回目錄
任務(wù)二 實(shí)現(xiàn)傳送文本文件的服務(wù)器和客戶端
雖然在網(wǎng)絡(luò)安全編程基礎(chǔ)課程上學(xué)習(xí)過(guò)網(wǎng)絡(luò)編程的相關(guān)知識(shí),但基于的是Windows。將其移植到Linux下時(shí)需要注意以下幾個(gè)方面:
- 頭文件
Windows下winsock.h或winsock2.h;
Linux下netinet/in.h(包括大部分),unistd.h(包括close函數(shù)),sys/socket.h。
- 初始化
windows下需要用WSAStartup啟動(dòng)Ws2_32.lib;
linux下不需要。
- 關(guān)閉socket
windows下使用closesocket();
linux下使用close()。
- 類型
windows下SOCKET;
linux下int。
- 多線程(下一個(gè)任務(wù)會(huì)用到)
windows下包含process.h,使用_beginthread和_endthread;
linux下包含pthread.h,使用pthread_create和pthread_exit。
- ......
以上是我在移植過(guò)程中遇到的問(wèn)題,需格外注意。更多情況可參考Socket程序從windows移植到linux的注意事項(xiàng)等相關(guān)文章。
基于客戶端與服務(wù)器的通信流程,可分別寫(xiě)出創(chuàng)建服務(wù)器和客戶端,以及客戶端和服務(wù)器連接的代碼:
/*創(chuàng)建服務(wù)器:*/ int start_server(int port, int type){//建立服務(wù)器套接字int ss = socket(AF_INET, type, 0);if(ss < 0){printf("create socket error\n");return -1;}//設(shè)置服務(wù)器地址struct sockaddr_in server_addr; //服務(wù)器地址結(jié)構(gòu)bzero(&server_addr, sizeof(struct sockaddr_in)); //清零server_addr.sin_family = AF_INET; //協(xié)議族server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //ip地址server_addr.sin_port = htons(port); //端口//綁定地址結(jié)構(gòu)到套接字描述符if(bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){printf("bind error\n");return -1;}//TCPif(SOCK_STREAM == type){//設(shè)置偵聽(tīng)if(listen(ss, LISTEN_SIZE) < 0){printf("listen error\n");return -1;}printf("tcp server start\n");}elseprintf("udp server start\n");return ss; }int create_tcp_server(int port){start_server(port, SOCK_STREAM); }int create_udp_server(int port){start_server(port, SOCK_DGRAM); } /*接受客戶端連接:*/ socklen_t addrlen = sizeof(struct sockaddr); struct sockaddr_in client_addr; //客戶端地址結(jié)構(gòu) client_sock = accept(ss, (struct sockaddr*)&client_addr, &addrlen); if(client_sock < 0){printf("accept error\n"); }printf("accept success\n"); /*客戶端:*/ int connectsock(char* server_ip, int server_port, int type){int sock_fd = socket(AF_INET, type, 0);if(-1 == sock_fd){printf("create socket error\n");return -1;}struct sockaddr_in server_addr;//設(shè)置服務(wù)器地址bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(server_port);inet_pton(AF_INET, server_ip, &server_addr.sin_addr);//連接服務(wù)器if(-1 == connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in))){printf("connect server error\n");return -1;}printf("connect server success\n");return sock_fd; } int connect_tcp(char* server_ip, int server_port){return connectsock(server_ip, server_port, SOCK_STREAM); } int connect_udp(char* server_ip, int server_port){return connectsock(server_ip, server_port, SOCK_DGRAM); }搭建好客戶端和服務(wù)器,接下來(lái)考慮如何傳輸文件。
傳輸數(shù)據(jù)需要用到緩沖區(qū)。客戶端首先輸入文件名,并判斷該文件是否存在。若不存在,則返回錯(cuò)誤提示;存在,則發(fā)送至服務(wù)器。服務(wù)器接收到數(shù)據(jù)后,創(chuàng)建一個(gè)同樣名稱的文件。至此,完成了最基礎(chǔ)的一步。
傳輸文件內(nèi)容的思路上面類似,但需注意:文件名稱一般很短,但文件內(nèi)容大小并不確定。所以不要奢望一次性傳輸完所有的數(shù)據(jù),而應(yīng)設(shè)置循環(huán),以固定大小傳輸數(shù)據(jù),一直到傳輸結(jié)束。
傳輸數(shù)據(jù)部分的代碼如下:
/*客戶端:*/ char file_name[FILE_NAME_MAX_SIZE+1];bzero(file_name, FILE_NAME_MAX_SIZE+1);printf("Please Input File Name On Server:\t");scanf("%s", file_name);char buffer[BUFFER_SIZE];bzero(buffer,BUFFER_SIZE);strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));//向服務(wù)器發(fā)送buffer中的數(shù)據(jù)send(client_socket,buffer,BUFFER_SIZE,0);FILE * fp = fopen(file_name,"r");if(NULL == fp ){printf("File:\t%s Not Found\n", file_name);exit(1);}else{bzero(buffer, BUFFER_SIZE);int file_block_length = 0;while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE, fp))>0){//printf("file_block_length = %d\n",file_block_length);//發(fā)送buffer中的字符串到服務(wù)器if(send(client_socket,buffer,file_block_length,0)<0){printf("Send File:\t%s Failed\n", file_name);break;}bzero(buffer, BUFFER_SIZE);}}printf("Send File:\t %s To Server[%s] Finished\n",file_name, argv[1]);printf("The File has %d words.\n", wc_func(file_name));fclose(fp); /*服務(wù)器:*/char file_name[FILE_NAME_MAX_SIZE+1];bzero(file_name, FILE_NAME_MAX_SIZE+1);char buffer[BUFFER_SIZE];bzero(buffer,BUFFER_SIZE);recv(new_server_socket,file_name,BUFFER_SIZE,0);FILE * fp = fopen(file_name,"w");if(NULL == fp ){printf("File:\t%s Can Not Open To Write\n", file_name);exit(1);}//從客戶端接收數(shù)據(jù)到buffer中bzero(buffer,BUFFER_SIZE);int len = 0;while( len = recv(new_server_socket,buffer,BUFFER_SIZE,0)){if(len < 0){printf("Recieve Data From Client %s Failed!\n", argv[1]);break;}int write_length = fwrite(buffer,sizeof(char),len,fp);if (write_length<len){printf("File:\t%s Write Failed\n", file_name);break;}bzero(buffer,BUFFER_SIZE); }printf("File:\t%s Transfer Finished!\n",file_name);fclose(fp);按照要求,在服務(wù)器端調(diào)用計(jì)算單詞數(shù)的函數(shù),并返回給客戶端即可。
【注:完成代碼已上傳至碼云】
返回目錄
任務(wù)三 多線程實(shí)現(xiàn)傳送文本文件的服務(wù)器和客戶端
通過(guò)man -k命令查看與創(chuàng)建進(jìn)程相關(guān)的函數(shù):
我們可以找到“pthread_create()”函數(shù),使用man 3 pthread_create命令可以得知其用法:
說(shuō)明:
- thread:線程標(biāo)識(shí)符;
- attr:線程屬性設(shè)置;
- start_routine:線程函數(shù)的起始地址;
- arg:傳遞給start_routine的參數(shù);
- 返回值:成功,返回0;出錯(cuò),返回-1。
- 注意:pthread庫(kù)不是Linux系統(tǒng)默認(rèn)的庫(kù),連接時(shí)需要使用靜態(tài)庫(kù)libpthread.a,所以在線程函數(shù)在編譯時(shí),需要使用“-lpthread”鏈接庫(kù)函數(shù)。
因此,服務(wù)器需要循環(huán)檢測(cè)是否有新的連接。如果有,則調(diào)用pthread_create()函數(shù)創(chuàng)建新的進(jìn)程,并執(zhí)行相關(guān)代碼。這部分的代碼如下:
while(1){//接受客戶端連接socklen_t addrlen = sizeof(struct sockaddr);struct sockaddr_in client_addr; //客戶端地址結(jié)構(gòu)int client_sock = accept(ss, (struct sockaddr*)&client_addr, &addrlen);if(client_sock < 0){printf("accept error\n");}printf("accept success\n");pthread_t pid;if(pthread_create(&pid, NULL, process_client, &client_sock) < 0){printf("pthread_create error\n");}}創(chuàng)建了新的線程,接下來(lái)就可以傳送文件了。過(guò)程與任務(wù)二類似。
【注:完成代碼已上傳至碼云】
返回目錄
任務(wù)四 使用PC機(jī)和實(shí)驗(yàn)箱模擬客戶端服務(wù)器并測(cè)試(未完成)
返回目錄
實(shí)驗(yàn)感想與體會(huì)
- 此次實(shí)驗(yàn)首先在Linux下實(shí)現(xiàn)了客戶端與服務(wù)器傳送文本文件,并模擬wc命令統(tǒng)計(jì)文本文件中的單詞數(shù)。但一次只能為一個(gè)客戶端提供服務(wù)的迭代網(wǎng)絡(luò)是不現(xiàn)實(shí)的,因此,在任務(wù)二中創(chuàng)建了一個(gè)并發(fā)服務(wù)器,它為每一個(gè)客戶端創(chuàng)建一個(gè)單獨(dú)的邏輯流。這就允許服務(wù)器同時(shí)為多個(gè)客戶端服務(wù),提高了其使用價(jià)值。
- 在完成任務(wù)三的過(guò)程中遇到了重重困難。本打算在自己筆記本上完成,也方便后續(xù)學(xué)習(xí),但參考指導(dǎo)書(shū)《實(shí)驗(yàn)開(kāi)發(fā)環(huán)境使用說(shuō)明-12.04》中“解決上網(wǎng)與本地網(wǎng)絡(luò)調(diào)試沖突”的相關(guān)講解完成配置后,實(shí)驗(yàn)箱與主機(jī)仍然無(wú)法ping通。想到之前實(shí)驗(yàn)一在實(shí)驗(yàn)室的PC機(jī)上完成得比較順利,于是改用實(shí)驗(yàn)室的PC機(jī),但找不到正確的端口,更換了PC機(jī)和實(shí)驗(yàn)箱后仍然解決不了,只能作罷。
- 近期學(xué)習(xí)效率低下,每周一章的任務(wù)常常不能按時(shí)完成,總需要后期抽時(shí)間補(bǔ)充。回想上學(xué)期學(xué)習(xí)Java時(shí),雖然也是一周學(xué)習(xí)一章,但并沒(méi)有覺(jué)得如此吃力,花十幾個(gè)小時(shí)就能完成當(dāng)周的任務(wù)。尤其這次實(shí)驗(yàn)結(jié)束,花費(fèi)大量時(shí)間也沒(méi)有解決問(wèn)題,心情失落的同時(shí),不禁懷疑自己的自學(xué)能力。且不說(shuō)與老師的要求相差甚遠(yuǎn),這種學(xué)習(xí)效率與狀態(tài)連自己都不能接受。課本內(nèi)容較上學(xué)期更難更深是一方面,但更多的是自身的問(wèn)題。比如沒(méi)有合理分配時(shí)間,做到門(mén)門(mén)課程兼顧;比如將精力浪費(fèi)在一些無(wú)關(guān)緊要的事情上,等等。
- 課下了解到,不少同學(xué)也遇到了類似的問(wèn)題。能及時(shí)趕上老師的進(jìn)度還好,一旦某一陣略有松懈沒(méi)跟上節(jié)奏,就容易產(chǎn)生惡性循環(huán),落下越來(lái)越多的內(nèi)容。老師一直以來(lái)采取的都是自學(xué)為主,教學(xué)為輔的方式,這一點(diǎn)無(wú)可厚非,我認(rèn)為自學(xué)能力可以讓人終生受益。不怕自學(xué)的過(guò)程中遇到困難,怕就怕在總是遇到無(wú)法解決的困難而逐漸放棄。
- 前幾天不慎扭傷了腳,不能在寢室、主樓和圖書(shū)館之間隨意跑的日子還真不適應(yīng),只能躺著休息,因此對(duì)好多任務(wù)都心有余而力不足...多虧朋友們悉心的照顧還有及時(shí)涂藥,腳在一天天康復(fù),落下的事情也要一點(diǎn)點(diǎn)補(bǔ)回來(lái)。那么,就先從努力按時(shí)完成本周學(xué)習(xí)任務(wù)開(kāi)始吧:)
返回目錄
參考資料
- Linux C TCP Socket實(shí)現(xiàn)客戶與服務(wù)器簡(jiǎn)單通信
- Linux C TCPSocket 傳輸文件簡(jiǎn)單實(shí)例-多線程實(shí)現(xiàn)
- wc:統(tǒng)計(jì)一個(gè)文件里出現(xiàn)某個(gè)單詞出現(xiàn)的次數(shù)
- Socket程序從Windows移植到Linux下的一些注意事項(xiàng)
- Linux下getopt()函數(shù)的簡(jiǎn)單使用
- linux網(wǎng)絡(luò)編程:用C語(yǔ)言實(shí)現(xiàn)的聊天程序(同步通信)
- Linux下C編寫(xiě)基本的多線程socket服務(wù)器
返回目錄
轉(zhuǎn)載于:https://www.cnblogs.com/Vivian517/p/7832469.html
總結(jié)
以上是生活随笔為你收集整理的2017-2018-1 《信息安全系统设计基础》实验三报告的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: css hover图片hover效果兼容
- 下一篇: Python Selenium + ph