1. 程式人生 > >2017-2018-1 20155214 《信息安全系統設計基礎》實驗三 並發程序

2017-2018-1 20155214 《信息安全系統設計基礎》實驗三 並發程序

沒有 .com 顯示 res 空間 緩存 char 參數 分隔

2017-2018-1 20155214 《信息安全系統設計基礎》

實驗三 並發程序

實驗要求

任務一
學習使用Linux命令wc(1)
基於Linux Socket程序設計實現wc(1)服務器(端口號是你學號的後6位)和客戶端
客戶端傳一個文本文件給服務器
服務器返加文本文件中的單詞數

任務二
使用多線程實現wc服務器並使用同步互斥機制保證計數正確
上方提交代碼
下方提交測試
對比單線程版本的性能,並分析原因

任務三
交叉編譯多線程版本服務器並部署到實驗箱中
PC機作客戶端測試wc服務器

實驗背景

技術分享圖片

  • wc
    統計指定文件中的字節數、字數、行數,並將統計結果顯示輸出。該命令統計指定文件中的字節數、字數、行數。如果沒有給出文件名,則從標準輸入讀取。wc同時也給出所指定文件的總統計數。

-w統計字數。一個字被定義為由空白、跳格或換行字符分隔的字符串。

偽代碼

//客戶端
......
打開文件
while(文件不為空){
將文件讀入緩存區
將緩沖區內容發送至服務器
}

接收服務器返回的字數
......

//服務器
......
打開文件
while(當客戶端傳輸字節不為0){
調用wc函數計算接收緩存區中的字數
將緩存區裏的內容寫入文件
}

將統計的文件字數返回給客戶端
......
  • 碼雲鏈接
    https://gitee.com/besti155214/BESTI.IS.ISSDB.20155214/tree/exp0/exp0/src/Wc

  • 運行截圖

技術分享圖片

多線程實現

  • 線程創建函數CreateThread(),屬於API函數;
HANDLE CreateThread(  
  LPSECURITY_ATTRIBUTES lpThreadAttributes, //指向結構體SECURITY_ATTRIBUTES的指針,表示指定新建線程的安全屬性
  DWORD dwStackSize, //指定線程初始化時地址空間的大小
  LPTHREAD_START_ROUTINE lpStartAddress,//指定該線程的線程函數的地址   
  LPVOID lpParameter,//將要傳遞給新建線程的命令行參數                
  DWORD dwCreationFlags, //指定新建線程創建後是否立即執行                
  LPDWORD lpThreadId   ); 表示新建線程的ID號
  • pthread_create調用成功以後,新線程和老線程誰先執行,誰後執行用戶是不知道的,這一塊取決與操作系統對線程的調度,如果我們需要等待指定線程結束,需要使用pthread_join函數,這個函數實際上類似與多進程編程中的waitpid。

  • gcc編譯時需要加上-lpthread,要不然會報錯

多線程的同步互斥

  • 通過信號量控制。信號量本質上是一個非負數的整數計數器,它也被用來控制對公共資源的訪問。當公共資源增加的時候,調用信號量增加函數sem_post()對其進行增加,當公共資源減少的時候,調用函數sem_wait()來減少信號量。

  • 關鍵代碼

void *thread(void *vargp){
    
    time_t lt;
    tm *local;
    char sbuf[MAXLINE];
    int count = 0;
    char *fp = fopen("test.txt","wb");
    char rbuf[MAXLINE];
    int connfd = *((int*)vargp);

    free(vargp);

    pthread_detach(pthread_self());

    /*lt = time(NULL); 
    local = localtime(&lt);
    strftime(sbuf,64,"%Y-%m-%d %H:%M:%S",local);
    send(connfd,sbuf,MAXLINE,0);
    */
while(recv(connfd,rbuf,MAXLINE,0)){

        //printf("%d\n",recv(connfd,rbuf,MAXLINE,0));   
        fputs(rbuf,fp);
     
        count += wc(rbuf);

        bzero(rbuf,sizeof(rbuf));
        }


        //printf("傳輸成功!,該文件單詞數共%d\n!",count);

        fclose(fp);

        itoa(count,sbuf);

        //send(connfd,sbuf,MAXLINE,0);
       
        printf("該文件單詞數為%s!\n",sbuf);

    close(connfd);
    
    return NULL;
}

多線程編程的目的,就是"最大限度地利用CPU資源",當某一線程的處理不需要占用CPU而只和I/O,OEMBIOS等資源打交道時,讓需要占用CPU資源的其它線程有機會獲得CPU資源。每個程序執行時都會產生一個進程,而每一個進程至少要有一個主線程。這個線程其實是進程執行的一條線索,除了主線程外你還可以給進程增加其它的線程,也即增加其它的執行線索,由此在某種程度上可以看成是給一個應用程序增加了多任務功能。當程序運行後,您可以根據各種條件掛起或運行這些線程,尤其在多CPU的環境中,這些線程是並發運行的。多線程就是在一個進程內有多個線程。從而使一個應用程序有了多任務的功能。

  • 通過命令行/usr/local/toolchain/toolchain4.3.2/bin/arm-none-linux-gnuenbi-gcc -c dateserveri.c/usr/local/toolchain/toolchain4.3.2/bin/arm-none-linux-gnuenbi-gcc -static -o dateserveri dateserveri.o csapp.a -lpthread即可實現交叉編譯。

2017-2018-1 20155214 《信息安全系統設計基礎》實驗三 並發程序