2019-2020-1 20175325石淦铭《信息安全系统设计基础》实验三 《并发程序》

2019-2020-1 20175325石淦铭《信息安全系统设计基础》实验三 《并发程序》

任务一:

  • 学习使用Linux命令wc(1)
  • 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
  • 客户端传一个文本文件给服务器
  • 服务器返加文本文件中的单词数
  • 上方提交代码
  • 附件提交测试截图,至少要测试附件中的两个文件

步骤:

  • wc指令功能:统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
  • wc指令格式:wc [选项] 文件
  • wc命令参数:
    • c 统计字节数。
    • l 统计行数。
    • m 统计字符数,不能与 -c 标志一起使用。
    • w 统计字数。
    • L 打印最长行的长度。
    • -help:显示帮助信息
    • --version:显示版本信息
  • 实现伪代码:
    fd = fopen()//打开文件;
    fscanf()//对文件的内容以字符串的形式进行读取
    if..count++//设置条件,当满足字符串条件时计数;
  • wc -w'\n''\t''\r'作为分隔符进行实现。
  • 服务器代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define MYPORT 175325

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);
}
  • 客户端代码:
#include <stdio.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <string.h>

#define MYPORT 175325

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);
}
  • 实验截图:



任务二:

  • 使用多线程实现wc服务器并使用同步互斥机制保证计数正确
  • 上方提交代码
  • 下方提交测试
  • 对比单线程版本的性能,并分析原因

步骤:

  • 对比单线程版本的性能,分析原因如下:

单线程比较稳定易于实现,运行稳定。而采用多线程可能不会提高程序的执行速度,反而会降低速度,同时,同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,其效率通常比多线程应用程序低

  • 重新编写支持多线程的服务器程序,然后编译,执行同上步
  • 实验截图:

任务三:

  • 交叉编译多线程版本服务器并部署到实验箱中
  • PC机作客户端测试wc服务器
  • 提交测试截图
  • 关键代码:
HANDLE CreateThread(  
LPSECURITY_ATTRIBUTES lpThreadAttributes,
 //指向结构体SECURITY_ATTRIBUTES的指针,表示指定新建线程的安全属性
DWORD dwStackSize,
 //指定线程初始化时地址空间的大小
LPTHREAD_START_ROUTINE lpStartAddress,
//指定该线程的线程函数的地址   
LPVOID lpParameter,
//将要传递给新建线程的命令行参数                
DWORD dwCreationFlags, 
//指定新建线程创建后是否立即执行                
LPDWORD lpThreadId   ); 
//表示新建线程的ID号
  • 执行:
    通过命令行即可实现交叉编译:
    • /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

猜你喜欢

转载自www.cnblogs.com/sgm5/p/11887349.html