1. 程式人生 > >2017-2018-1 20155208 20155212 實驗三 實時系統

2017-2018-1 20155208 20155212 實驗三 實時系統

stream tex logs 實驗 reat error ges 字節數 return

2017-2018-1 20155212 實驗三 實時系統

1 學習使用Linux命令wc(1)

題目

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

步驟

  • 使用man wc命令查看wc技術分享圖片
  • wc命令詳解
    • 語法:wc [選項] 文件
    • 選項含義
      • c:統計字節數
      • l:統計行數
      • w:統計字數
  • 使用示例技術分享圖片
  • 實現難點:
    • 如何統計單詞數?
      • 使用od -tc命令查看文本中單詞之間如何間隔技術分享圖片
      • 單詞間通過‘ ‘、‘\r‘、‘\n‘間隔開
    • 統計結果與實際出現較大誤差
      • 字符間可能有多個間隔符,因此連續的間隔符只能算一個

最終代碼

  • 服務器

    /*server*/
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define MYPORT 155212
    
    void main(){
        int serverfd, clientfd;
        struct sockaddr_in my_addr;
        struct sockaddr_in remote_addr;
    
        char buffer[BUFSIZ];
        memset(&my_addr, 0, sizeof(my_addr));
        my_addr.sin_family=AF_INET;
        my_addr.sin_addr.s_addr=INADDR_ANY;
        my_addr.sin_port=htons(MYPORT);
    
        if((serverfd=socket(PF_INET, SOCK_STREAM, 0))==-1){
            perror("socket");
        }
    
        if(bind(serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))<0){
            perror("bind");
        }
        listen(serverfd, 5);
        int addrlen=sizeof(struct sockaddr_in); 
        while(1){
            if((clientfd=accept(serverfd, (struct sockaddr *)&remote_addr, &addrlen))<0){
                perror("accept");
            }
            printf("accept client %s\n", inet_ntoa(remote_addr.sin_addr));
            int len, i;
            long wordscount=0;
            int flag=1;
            while(1){
                if((len=recv(clientfd, buffer, 1024, 0))>0){
                    for(i=0; i<len; i++){
                        if(flag==0){
                            switch(buffer[i]){
                                case ‘ ‘:
                                    wordscount++;
                                    break;
                                case ‘\n‘:
                                    wordscount++;
                                    break;
                                case ‘\r‘:
                                    wordscount++;
                                    break;
                                default:
                                    break;
                            }
                        }
                        if(buffer[i]== ‘ ‘ || buffer[i]==‘\n‘ || buffer[i]==‘\r‘) flag=1;
                        else flag=0;
                    }
                }
                if(len<1024) break;
            }
            send(clientfd, &wordscount, sizeof(long), 0);
            close(clientfd);
        }
        close(serverfd);
    }
  • 客戶端

    /*client*/
    #include <stdio.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <string.h>
    
    #define MYPORT 155212
    
    void main(){
        int clientfd;
        struct sockaddr_in remote_addr;
        char buffer[BUFSIZ];
        memset(&remote_addr, 0 , sizeof(remote_addr));
        remote_addr.sin_family=AF_INET;
        remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
        remote_addr.sin_port=htons(MYPORT);
    
        if((clientfd=socket(PF_INET,SOCK_STREAM,0))<0){  
            perror("socket");  
        }
    
        if(connect(clientfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr))<0){
            perror("connect");
        }
    
        int len;
        FILE *fp;
        char path[20];
        gets(path);
        fp=fopen(path, "r");
        char readch;
        int i=0;
        while((readch=fgetc(fp))!=EOF){
            if(i<1024){
                buffer[i]=readch;
                i++;
            }
            else{
                i=0;
                int n=send(clientfd, buffer, 1024, 0);
            }
        }
        fclose(fp);
        if(i!=0) send(clientfd, buffer, i, 0);
        long wordscount;
        recv(clientfd, &wordscount, sizeof(long), 0);
        printf("%ld\n", wordscount);
        close(clientfd);
    }
  • 運行結果截圖技術分享圖片

2 使用多線程實現wc服務器並使用同步互斥機制保證計數正確

分析

  • 1中的客戶端代碼不需要改變,只需要改變服務器代碼即可。
  • 服務器代碼需要增加兩個功能
    • 增加多線程
    • 使用同步互斥

代碼

  • 服務器
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>

#define MYPORT 155212
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

char buffer[BUFSIZ];
void *wc(void *m){
    pthread_mutex_lock( &counter_mutex );
    int len, i;
    long wordscount=0;
    int flag=1;
    while(1){
        if((len=recv(clientfd, buffer, 1024, 0))>0){
            for(i=0; i<len; i++){
                if(flag==0){
                    switch(buffer[i]){
                        case ‘ ‘:
                            wordscount++;
                            break;
                        case ‘\n‘:
                            wordscount++;
                            break;
                        case ‘\r‘:
                            wordscount++;
                            break;
                        default:
                            break;
                    }
                }
                if(buffer[i]== ‘ ‘ || buffer[i]==‘\n‘ || buffer[i]==‘\r‘) flag=1;
                else flag=0;
            }
        }
        if(len<1024) break;
    }
    send(clientfd, &wordscount, sizeof(long), 0);
    close(clientfd);
    pthread_mutex_unlock( &counter_mutex );
    return NULL;
}
void main(){
    pthread_t t;    
    char arg[30];
    int serverfd, clientfd;
    struct sockaddr_in my_addr;
    struct sockaddr_in remote_addr;

    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family=AF_INET;
    my_addr.sin_addr.s_add#include  <pthread.h>r=INADDR_ANY;
    my_addr.sin_port=htons(MYPORT);

    if((serverfd=socket(PF_INET, SOCK_STREAM, 0))==-1){
        perror("socket");
    }

    if(bind(serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))<0){
        perror("bind");
    }
    listen(serverfd, 5);
    int addrlen=sizeof(struct sockaddr_in); 
    while(1){
        if((clientfd=accept(serverfd, (struct sockaddr *)&remote_addr, &addrlen))<0){
            perror("accept");
        }
        printf("accept client %s\n", inet_ntoa(remote_addr.sin_addr));
        pthread_create(&t, NULL, &wc, NULL);
        pthread_join(&t, NULL);
    }
    close(serverfd);
}

運行結果

技術分享圖片

實驗總結

  • 在本次實驗中,實驗進展比較慢,主要原因在於對socket編程不夠熟悉,有一些錯誤一直沒調出來,而且由於比較急,任務二的截圖提交錯了。在今後的實驗中,需要更加提前準備實驗,同時在提交截圖時需要仔細確認。
  • 希望老師能多提前幾天將其他實驗的任務給我們,以便我們能充分準備好實驗

2017-2018-1 20155208 20155212 實驗三 實時系統