• 2018-2019-1 20165315 实验三 实时系统


    2018-2019-1 20165315 实验三 实时系统

    任务一 学习使用Linux命令wc(1)

    基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端,客户端传一个文本文件给服务器,服务器返加文本文件中的单词数

    实验步骤

    • 使用man wc命令查看wc(1)

    wc命令详解:

    • 语法:wc [选项] 文件

    • 选项含义

      • -c:统计字节数
      • -l:统计行数
      • -w:统计字数
    • wc代码实现

    void my_wc(socket_counter *my_counter){
        pthread_mutex_lock( &counter_mutex );
        int len, i;
        long wordscount=0;
        int flag=1;
        while(1)
        {
            if((len=recv(my_counter->send_socket, my_counter->buffer, 1024, 0))>0)
            {
                for(i=0; i<len; i++)
                {
                    if(flag==0)
                    {
                        switch(my_counter->buffer[i])
                        {
                            case ' ':
                                wordscount++;
                                break;
                            case '
    ':
                                wordscount++;
                                break;
                            case '
    ':
                                wordscount++;
                                break;
                            default:
                                break;
                        }
                    }
                    if(my_counter->buffer[i]== ' ' || my_counter->buffer[i]=='
    ' || my_counter->buffer[i]=='
    ')
                        flag=1;
                    else
                        flag=0;
                }
            }
            if(len<1024) break;
        }
        send(my_counter->send_socket, &wordscount, sizeof(long), 0);
        close(my_counter->send_socket);
        pthread_mutex_unlock( &counter_mutex );
    }
    
    • 实现文件传输功能

    结合我们在网络安全编程基础中学习的内容,我们知道客户端和服务器的通信过程如下:

    • 完善代码

    服务器端:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define MYPORT 165315
    
    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
    ", 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 '
    ':
    wordscount++;
    break;
    case '
    ':
    wordscount++;
    break;
    default:
    break;
    }
    }
    if(buffer[i]== ' ' || buffer[i]=='
    ' || buffer[i]=='
    ') flag=1;
    else flag=0;
    }
    }
    if(len<1024) break;
    }
    send(clientfd, &wordscount, sizeof(long), 0);
    close(clientfd);
    }
    close(serverfd);
    }
    

    客户端:

    #include <stdio.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <string.h>
    
    #define MYPORT 165315
    
    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
    ", wordscount);
    close(clientfd);
    }
    

    运行结果

    客户端:

    服务器端:

    任务二 多线程实现wc功能

    使用多线程实现wc服务器并使用同步互斥机制保证计数正确,对比单线程版本的性能,并分析原因

    实验步骤

    • 客户端代码不需要改变,只需要改变服务器代码
    • 服务器代码需要增加两个功能
      • 增加多线程
      • 使用同步互斥
    • 代码实现

    服务器端:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <pthread.h>
    #pragma comment(lib,"ws2_32.lib")
    pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    #define MY_PORT 165315
    
    typedef struct socket_counter
    {
        SOCKET send_socket;
        char buffer[1024];
    }socket_counter;
    
    void my_wc(socket_counter *my_counter);
    int main()
    {
        SOCKET listen_socket;//声明Socket接口变量
        struct sockaddr_in my_addr;//声明Socket地址变量
        int dummy,rev_length;
        //char buffer[1024];
        char file_name[100];
        pthread_t t;
        socket_counter *my_counter;
    
        WSADATA wsaDate;
    
        WSAStartup(MAKEWORD(1,1),&wsaDate);//启动版本
    
        listen_socket=socket(AF_INET,SOCK_STREAM,0);//声明为IPV4的TCP
    
        my_addr.sin_family=AF_INET;//IPV4
        my_addr.sin_port=htons(MY_PORT);//端口
        my_addr.sin_addr.s_addr=htonl(INADDR_ANY);//可以连接任一电脑
    
        dummy = sizeof(SOCKADDR);
        memset(file_name,0,sizeof(file_name));
    
        if( bind(listen_socket,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))<0)//绑定本地IP与Socket
        {
           printf("Server Bind error!
    ");
        }
    
        if(listen(listen_socket,5)<0)//等待序列,默认队列最多为5个请求
        {
            printf("Server Listen error!
    ");
        }
    
        while(1)
        {
            my_counter->send_socket=accept(listen_socket,NULL,&dummy);//listen函数创建等待队列后,accept函数处理客户端发来的连接请求
            if(my_counter->send_socket==-1)
            {
                printf("Server Accept failed!
    ");
                break;
            }
            printf("Accept success!
    ");
            pthread_create(&t, NULL, &my_wc,my_counter);
            pthread_join(&t, NULL);
        }
        closesocket(listen_socket);//依次关闭连接
        WSACleanup();//清除
        return 0;
    }
    void my_wc(socket_counter *my_counter){
        pthread_mutex_lock( &counter_mutex );
        int len, i;
        long wordscount=0;
        int flag=1;
        while(1)
        {
            if((len=recv(my_counter->send_socket, my_counter->buffer, 1024, 0))>0)
            {
                for(i=0; i<len; i++)
                {
                    if(flag==0)
                    {
                        switch(my_counter->buffer[i])
                        {
                            case ' ':
                                wordscount++;
                                break;
                            case '
    ':
                                wordscount++;
                                break;
                            case '
    ':
                                wordscount++;
                                break;
                            default:
                                break;
                        }
                    }
                    if(my_counter->buffer[i]== ' ' || my_counter->buffer[i]=='
    ' || my_counter->buffer[i]=='
    ')
                        flag=1;
                    else
                        flag=0;
                }
            }
            if(len<1024) break;
        }
        send(my_counter->send_socket, &wordscount, sizeof(long), 0);
        close(my_counter->send_socket);
        pthread_mutex_unlock( &counter_mutex );
    }
    

    客户端:

    #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>
    #pragma comment(lib,"ws2_32.lib")
    
    #define MY_PORT 165315
    #define DEST_IP "127.0.0.1"
    int main()
    {
        SOCKET con_socket;
        struct sockaddr_in remote_addr;
        char buffer[1024];
        char file_name[100];
        char readch;
        int i;
    
        WSADATA wsaDate;
    
        WSAStartup(MAKEWORD(1,1),&wsaDate);
    
        memset(file_name,0,sizeof(file_name));
        memset(buffer,0,sizeof(buffer));
    
        remote_addr.sin_family=AF_INET;
        remote_addr.sin_port=htons(MY_PORT);
        remote_addr.sin_addr.s_addr=inet_addr(DEST_IP);
    
        con_socket=socket(AF_INET,SOCK_STREAM,0);
        if(con_socket==-1)
        {
            printf("Client socket failed!");
            exit(0);
        }
    
        printf("Please Input File Name:
    ");
        scanf("%s", file_name);
    
        if(connect(con_socket,(struct sockaddr*)&remote_addr,sizeof(struct sockaddr))==-1)
        {
            printf("Client connet failed!");
        }
        else
        {
            FILE *fp=fopen(file_name,"r");
            if(fp==NULL)
            {
                printf("%s File not Found!
    ",file_name);
            }
            else
            {
                while((readch=fgetc(fp))!=EOF)
                {
                    if(i<1024)
                    {
                        buffer[i]=readch;
                        i++;
                    }
                    else
                    {
                        i=0;
                        int n=send(con_socket, buffer, 1024, 0);
                        if(n==-1)
                        {
                            printf("Send File Error!
    ");
                        }
                    }
                }
                fclose(fp);
                printf("File:%s Transfer Finished!
    ", file_name);
            }
            fclose(fp);
            long wordscount;
            recv(con_socket, &wordscount, sizeof(long), 0);
            printf("%ld
    ", wordscount);
        }
        closesocket(con_socket);
    
        WSACleanup();
        return 0;
    }
    

    实验分析

    相比单线程,多线程运行时可以同时多个客户端一起给服务器传文件效率更高

    实验结果

    实验中出现的问题

    • 客户端始终无法与服务器端连接上

    解决过程:
    经过反复调试代码排查,发现竟然是客户端和服务器端的端口号设置的不同导致的(客户端设置的是165315,服务器端设置的是5315),这样的小错误耗费了大半个小时的时间,实在是非常不值得...

    • 编译过程没有问题,但是在在运行过程中出现段错误(Segmentation Fault)

    解决过程:
    经过上网查询,在一篇博客中找到了错误的原因:指针使用错误

    实验感想

    本次实验重点在实现Linux下wc指令的功能,即统计文本单词的数量,并分别用单线程和多线程、客户端和服务器端之间的传输实现,有一定难度,结合了网络安全编程基础的知识,这让我更加感受到了这学期课程之间的融会贯通。在同组同学的相互帮助之下,借鉴了网路安全编程基础的代码,终于成功实现,也是有一定成就感的。
    但是在实验过程中,也犯了大大小小很多错误,导致差点想放弃,但是在同组同学的鼓励下,我们还是坚持到了最后,坚持就是胜利!

  • 相关阅读:
    强弱类型 静态语言 动态语言 || 脚本语言
    mysql版本升级问题处理
    word
    IntelliJ IDEA 插件
    dubbo
    spring源码构建
    zookeeper 本地多线程模拟分布式事务控制及配置中心
    一次性关闭所有的Activity
    可能以后用得到得东西
    Thread.sleep还是TimeUnit.SECONDS.sleep
  • 原文地址:https://www.cnblogs.com/yh666/p/9976044.html
Copyright © 2020-2023  润新知