zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155217《信息安全系统设计基础》实验三

    2017-2018-1 20155217《信息安全系统设计基础》实验三

    任务一

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

    有关wc命令

    使用man wc查看wc命令的基本用法

    1. wc命令功能统计指定文件中的字节数、字数、行数,并将统计结果显示输出。该命令统计指定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所指定文件的总统计数。
    
    2. wc命令格式:wc [选项]文件
    
    3. wc命令参数:
    (1)-c:统计字节数。
    (2)-l:统计行数。
    (3)-m:统计字符数。这个标志不能与 -c 标志一起使用。
    (4)-w:统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
    (5)-L:打印最长行的长度。
    (6)-help:显示帮助信息
    (7)--version:显示版本信息
    
    实例一:查看文件的字节数、字数、行数

    实例二:用wc命令怎么做到只打印统计数字不打印文件名

    实例三:用来统计当前目录下的文件数

    实例四:统计某文件中出现过某个特定单词(字母)的行数
    • 命令grep (单词/字母) 文件名 | wc -l

    实例五:统计某文件中出现过某个特定单词(字母)的个数
    • 命令grep -o (单词/字母) 文件名 | wc -l

    • 因此,wc命令c语言主代码如下:
    int main(int argc, char *argv[])
    {
        int characters, lines, words, state;
        char c;
        state = characters = lines = words = 0;
        while((c = getchar()) != '0') {
            characters++;
            if(c == '
    ') {
                lines++;
                state = 0;
                continue;
            } else if(c == ' ') {
                state = 0;
                continue;
            } else if(c == '	') {
                state = 0;
                continue;
            } else {
                if(state == 0) {
                    state = BEGIN;
                    words++;
                }
                continue;
            }
        }
        printf("%d characters. %d words. %d lines.
    ", characters, words, lines);
    }
    

    实现传送文本文件的服务器和客户端

    • 服务器端程序的编译:gcc -o file_server file_server.c
    • 客户端程序的编译:gcc -o file_client file_client.c
    • 服务器端程序的运行,在一个计算机的终端执行
      ./file_server
    • 客户端程序的运行,在另一个计算机的终端中执行./file_client,运行服务器程序的计算机的IP地址
    • 根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上
    • 在实际编程和测试中,可以用2个终端代替2个计算机,任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1
    服务器主代码:
    int main(int argc, char **argv)
    {
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htons(INADDR_ANY);
        server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    
        //创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
        int server_socket = socket(PF_INET,SOCK_STREAM,0);
        if( server_socket < 0)
        {
            printf("Create Socket Failed!");
            exit(1);
        }
        
        //把socket和socket地址结构联系起来
        if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
        {
            printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); 
            exit(1);
        }
        
        //server_socket用于监听
        if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
        {
            printf("Server Listen Failed!"); 
            exit(1);
        }
        while (1) //服务器端要一直运行
        {
            struct sockaddr_in client_addr;
            socklen_t length = sizeof(client_addr);
    
            //接受一个到server_socket代表的socket的一个连接
            //如果没有连接请求,就等待到有连接请求--这是accept函数的特性
            //accept函数返回一个新的socket,这个socket(new_server_socket)用于同连接到的客户的通信
            //new_server_socket代表了服务器和客户端之间的一个通信通道
            //accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
            int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
            if ( new_server_socket < 0)
            {
                printf("Server Accept Failed!
    ");
                break;
            }
            
            char buffer[BUFFER_SIZE];
            bzero(buffer, BUFFER_SIZE);
            length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
            if (length < 0)
            {
                printf("Server Recieve Data Failed!
    ");
                break;
            }
            char file_name[FILE_NAME_MAX_SIZE+1];
            bzero(file_name, FILE_NAME_MAX_SIZE+1);
            strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
            FILE * fp = fopen(file_name,"r");
            if(NULL == fp )
            {
                printf("File:	%s Not Found
    ", file_name);
            }
            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
    ",file_block_length);
                    //发送buffer中的字符串到new_server_socket,实际是给客户端
                    if(send(new_server_socket,buffer,file_block_length,0)<0)
                    {
                        printf("Send File:	%s Failed
    ", file_name);
                        break;
                    }
                    bzero(buffer, BUFFER_SIZE);
                }
                fclose(fp);
                printf("File:	%s Transfer Finished
    ",file_name);
            }
            //关闭与客户端的连接
            close(new_server_socket);
        }
        //关闭监听用的socket
        close(server_socket);
        return 0;
    }
    
    
    客户端主代码:
    int main(int argc, char **argv)
    {
        if (argc != 2)
        {
            printf("Usage: ./%s ServerIPAddress
    ",argv[0]);
            exit(1);
        }
    
        int client_socket = socket(AF_INET,SOCK_STREAM,0);
        if( client_socket < 0)
        {
            printf("Create Socket Failed!
    ");
            exit(1);
        }
        
        //把客户机的socket和客户机的socket地址结构联系起来
        if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
        {
            printf("Client Bind Port Failed!
    "); 
            exit(1);
        }
    
        //设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
        struct sockaddr_in server_addr;
        bzero(&server_addr,sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        if(inet_aton(argv[1],&server_addr.sin_addr) == 0)
        
        //服务器的IP地址来自程序的参数
        {
            printf("Server IP Address Error!
    ");
            exit(1);
        }
        server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
        socklen_t server_addr_length = sizeof(server_addr);
        
        //向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
        if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)
        {
            printf("Can Not Connect To %s!
    ",argv[1]);
            exit(1);
        }
    
        char file_name[FILE_NAME_MAX_SIZE+1];
        bzero(file_name, FILE_NAME_MAX_SIZE+1);
        printf("Please Input File Name On Server:	");
        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));
        
        //向服务器发送buffer中的数据
        send(client_socket,buffer,BUFFER_SIZE,0);
        FILE * fp = fopen(file_name,"w");
        if(NULL == fp )
        {
            printf("File:	%s Can Not Open To Write
    ", file_name);
            exit(1);
        }
        
        //从服务器接收数据到buffer中
        bzero(buffer,BUFFER_SIZE);
        int length = 0;
        while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
        {
            if(length < 0)
            {
                printf("Recieve Data From Server %s Failed!
    ", argv[1]);
                break;
            }
    
            int write_length = fwrite(buffer,sizeof(char),length,fp);
            if (write_length<length)
            {
                printf("File:	%s Write Failed
    ", file_name);
                break;
            }
            bzero(buffer,BUFFER_SIZE);    
        }
        printf("Recieve File:	 %s From Server[%s] Finished
    ",file_name, argv[1]);
        
        fclose(fp);
        //关闭socket
        close(client_socket);
        return 0;
    }
    
    代码运行结果如下:

    任务二

    • 使用多线程实现wc服务器并使用同步互斥机制保证计数正确
    • 通过man -k命令查看与创建进程相关的函数,找到pthread_create()函数,使用man 3 pthread_create命令可以得知其用法:

    • 因此,服务器需要循环检测是否有新的连接。如果有,则调用pthread_create()函数创建新的进程,并执行相关代码。相关代码如下:
    while(1){
            //接受客户端连接
            socklen_t addrlen = sizeof(struct sockaddr);
            struct sockaddr_in client_addr; //客户端地址结构
            int client_sock = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
            if(client_sock < 0){
                printf("accept error
    ");
            }
            printf("accept success
    ");
    
            pthread_t pid;
            if(pthread_create(&pid, NULL, process_client, &client_sock) < 0){
                printf("pthread_create error
    ");
            }
        }
    
    • 运行结果如下:

    任务三(未完成)

    • 交叉编译多线程版本服务器并部署到实验箱中
      PC机作客户端测试wc服务器

    实验体会

    这次实验使我更加深刻地意识到知识之间的关联性是有多么的密切,比如这次的pthread库。它不是Linux系统默认的库,连接时需要使用静态库libpthread.a,所以在线程函数在编译时,需要使用“-lpthread”链接库函数。不经常巩固以往的知识点,它对你依旧只是陌生人。

  • 相关阅读:
    iOS,Layer
    iOS 手势冲突
    ECharts
    手动安装Package Control
    webstorm配置svn详解
    js 对象 类型转换
    google 跨域解决办法
    关于内层DIV设置margin-top不起作用的解决方案
    图片与文字在div里实现垂直水平都居中
    css3之3D翻牌效果
  • 原文地址:https://www.cnblogs.com/yangdi0420/p/7850937.html
Copyright © 2011-2022 走看看