2017-2018-1 20155318 实验三 实时系统报告

2017-2018-1 20155318 实验三 实时系统报告

任务一:

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

  • 使用wc查看测试文档的单词数

  • test1和test2单词数

  • 分析wc功能,编写mywc,代码如下:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
  int count,start;
  FILE *fp;
  char c;
  if(argc!=2)
    {
    printf("Usage:./a.out Filename
");
        exit(1);
    }
  fp=fopen(argv[1],"r");
  if(fp==NULL)
  {
    printf("Open Failed!
");
    exit(1);
  }
  fseek(fp,0,SEEK_SET);
  start=1;  //0-单词开始  1-不是开头
  count=0;
  while(feof(fp)==0)
  {
    fread(&c,1,1,fp);
    if(c==' ' && start==1)
    {
      start=1;
    }
    else if(c!=' ' && start==1)
    {
      start=0;
      count++;
    }
    else if(c==' ' && start==0)
    {
      start=1;
    }
  }
  printf("单词数为%d
",count);
  return 1;
}
  • 客户端代码如下:
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HELLO_WORLD_SERVER_PORT    6666 
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("Usage: ./%s ServerIPAddress
",argv[0]);
        exit(1);
    }

    struct sockaddr_in client_addr;
    bzero(&client_addr,sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = htons(INADDR_ANY);
    client_addr.sin_port = htons(0);
    int client_socket = socket(AF_INET,SOCK_STREAM,0);
    if( client_socket < 0)
    {
        printf("Create Socket Failed!
");
        exit(1);
    }
    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
    {
        printf("Client Bind Port Failed!
"); 
        exit(1);
    }
    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) 
    {
        printf("Server IP Address Error!
");
        exit(1);
    }
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    socklen_t server_addr_length = sizeof(server_addr);
    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));
    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);
    }
    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);
    close(client_socket);
    return 0;
}
  • 服务器代码
#include <netinet/in.h>    // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>    // for socket
#include <stdio.h>        // for printf
#include <stdlib.h>        // for exit
#include <string.h>        // for bzero
#define HELLO_WORLD_SERVER_PORT    6666 
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr)); 
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    int server_socket = socket(PF_INET,SOCK_STREAM,0);
    if( server_socket < 0)
    {
        printf("Create Socket Failed!");
        exit(1);
    }
    
    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
    {
        printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); 
        exit(1);
    }
    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);
        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);
                if(send(new_server_socket,buffer,file_block_length,0)<0)
                {
                    printf("Send File:	%s Failed
", file_name);
                    break;
                }
                bzero(buffer, BUFFER_SIZE);
            }
//            close(fp);
            fclose(fp);
            printf("File:	%s Transfer Finished
",file_name);
        }
        close(new_server_socket);
    }
    close(server_socket);
    return 0;
}

运行结果如下:

任务二

  1. 使用多线程实现wc服务器并使用同步互斥机制保证计数正确
  2. 上方提交代码
  3. 下方提交测试
  4. 对比单线程版本的性能,并分析原因
  • 多线程实现的关键在于互斥的计数,即为当某一个线程计数时,另一个线程就不能计数
  • 服务器
#include <stdio.h>
#include <stdlib.h>
#include<pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <dirent.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#define LEN 4096  
#define MAXLINE 40
#define BUFFERSIZE 4096
#define PORT 13321
#define BUFFER_LENGTH 1024
#define MAX_CONN_LIMIT 512     //MAX connection limit
ssize_t writen(int fd, const void * vptr, size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char * ptr;

    ptr = vptr;
    nleft = n;
    while ( nleft > 0)
     {
        if ((nwritten = write(fd, ptr, nleft)) <= 0)
        {
            if (nwritten < 0 && errno == EINTR) 
            {
                nwritten = 0;
            }
            else
            {
                return -1;
            }
        }

        nleft -= nwritten;
        ptr += nwritten; 
    }
    return n;
}

ssize_t readline(int fd, void * vptr, size_t maxlen)
{
    ssize_t    n, rc;
    char    c, *ptr;
    ptr = vptr;
    for (n = 1; n < maxlen; n++)
    {
        again:
        if ((rc = read(fd, &c, 1)) == 1)
        {
            *ptr++ = c;
            if (c == '
')
            {
                break;
            }
        }
        else if (rc == 0)
        {   
            *ptr = 0;
            return (n - 1);
        }
        else
        {
            if (errno == EINTR)
            {
                goto again;
            }
            return (-1);
        }
    }
    *ptr = 0;
    return (n);
}

int Socket(int domain, int type, int protocol)
{
    int sockfd;
    if ((sockfd = socket(domain, type, protocol)) < 0)
    {
        fprintf(stderr, "socket error
");
        exit(1);
    }
    return sockfd;
}

int Accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen)
{
    int ret;
    if ((ret = accept(sockfd, addr, addrlen)) < 0)
    {
        fprintf(stderr, "accept error
");
        exit(1);
    }
    return ret;
}

int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
    int ret;
    if ((ret = bind(sockfd, addr, addrlen)) < 0)
    {
        fprintf(stderr, "bind error
");
        exit(1);
    }
    return ret;
}

int Listen(int sockfd, int backlog)
{
    int ret;
    if ((ret = listen(sockfd, backlog)) < 0)
    {
        fprintf(stderr, "listen error
");
        exit(1);
    }
    return ret;
}

int Close(int fd)
{
    int ret;
    if ((ret = close(fd)) < 0)
    {
        fprintf(stderr, "close error
");
        exit(1);
    }
    return ret;
}


static void Data_handle(void * sock_fd)
{
     int fd = *((int *)sock_fd);
     int i_recvBytes;
     char data_recv[BUFFER_LENGTH];
     const char * data_send = "Server has received your request!
";
     pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
     while(1)
     {
        pthread_mutex_lock( &counter_mutex );
        int totalNum[1] = {0};
        FILE *fp;  // 指向文件的指针
        char buffer[1003];  //缓冲区,存储读取到的每行的内容
        int bufferLen;  // 缓冲区中实际存储的内容的长度
        int i;  // 当前读到缓冲区的第i个字符
        char c;  // 读取到的字符
        int isLastBlank = 0;  // 上个字符是否是空格
        int charNum = 0;  // 当前行的字符数
        int wordNum = 0; // 当前行的单词数
        if( (fp=fopen("/home/rafel/shiyan3/2/save", "rb")) == NULL ){
            perror(filename);
            exit(1);
        }
    
    while(fgets(buffer, 1003, fp) != NULL){
        bufferLen = strlen(buffer);
        // 遍历缓冲区的内容
        for(i=0; i<bufferLen; i++){
            c = buffer[i];
            if( c==' ' || c=='	'){  // 遇到空格
                !isLastBlank && wordNum++;  // 如果上个字符不是空格,那么单词数加1
                isLastBlank = 1;
            }else if(c!='
'&&c!='
'){  // 忽略换行符
                charNum++;  // 如果既不是换行符也不是空格,字符数加1
                isLastBlank = 0;
            }
        }
        !isLastBlank && wordNum++;  // 如果最后一个字符不是空格,那么单词数加1
        isLastBlank = 1;  // 每次换行重置为1
        // 一行结束,计算总单词数
        totalNum[0] += wordNum;  // 总单词数
        // 置零,重新统计下一行
        charNum = 0;
        wordNum = 0;
    pthread_mutex_unlock( &counter_mutex );
    }
    printf("Total: %d words
", totalNum[0]);
}
     printf("terminating current client_connection...
");
     close(fd);            //close a file descriptor.
     pthread_exit(NULL);   //terminate calling thread!
 }

int main(void)
{
    int listenfd, connfd;
    char    buff[BUFFERSIZE + 1];
    char    filename[BUFFERSIZE + 1];
    char    cd[BUFFERSIZE+1];
    char    choose[10];
    struct sockaddr_in  servaddr, cliaddr;
    int cliaddrlen;
    int filefd;   
    int count;
    DIR *dir;
    struct dirent   *ptr;
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    Listen(listenfd, 5);

    while(1)
    {
        printf("开始监听
");

        cliaddrlen = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);

        if (readline(connfd, buff, BUFFERSIZE) < 0)
        {
            fprintf(stderr, "readline error
");
            exit(1);
        }
        buff[strlen(buff) - 1] = 0;    /* change '
' to NUL */
        memcpy(filename, buff, BUFFERSIZE + 1);
        printf("统计的文件名: %s
", buff);
        
        printf("Input the direct you want to store %s:
", buff);
        scanf("%s", cd);
        if(chdir(cd) < 0)
        {
            fprintf(stderr, "direct error
");
            exit(1);
        }

        dir = opendir(cd);
        while((ptr = readdir(dir)) != NULL)
        {
            if(strcmp(buff, ptr->d_name) == 0)
            {
                printf("已存在文件:%s
", buff);
                printf("若想重命名请输入yes,否则请输入no
");    
                scanf("%s", choose);
                if(strcmp(choose, "yes") == 0)
                {           
                    printf("重命名为:	");
                    scanf("%s", buff);
                }
            }
        }

        filefd = open(buff, O_WRONLY | O_CREAT);
        if (filefd < 0)
        {
            fprintf(stderr, "can't open the file: %s
", buff);
            exit(1);
        }

        while(count = read(connfd, buff, BUFFERSIZE))
        {
            if (count < 0)
            {
                fprintf(stderr, "connfd read error
");
                exit(1);
            }
            if (writen(filefd, buff, count) < 0) 
            {
                fprintf(stderr, "writing to filefd error
");
                exit(1);
            }
        }
        
    int sockfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);
    //sockfd = accept(sockfd_server,(struct sockaddr*)(&s_addr_client),(socklen_t *)(&client_length));

    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
         {
             fprintf(stderr,"pthread_create error!
");
             break;                                  //break while loop
         }


        if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
         {
             fprintf(stderr,"pthread_create error!
");
             break;                                  //break while loop
         }
        closedir(dir);
        Close(filefd);
        Close(connfd);
        printf("file %s received!
", filename);
}
}

客户端代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#define MAXLINE 40
#define BUFFERSIZE 4096
#define PORT 13321
ssize_t writen(int fd, const void * vptr, size_t n)
{
    size_t    nleft;
    ssize_t    nwritten;
    const char *    ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) 
    {
        if ((nwritten = write(fd, ptr, nleft)) <= 0) 
        {
            if (nwritten < 0 && errno == EINTR) 
            {
                nwritten = 0;
            }
            else 
            {
                return -1;
            }
        }

        nleft -= nwritten;
        ptr += nwritten;
    }

    return n;
}

int Socket(int domain, int type, int protocol)
{
    int sockfd;
    if ((sockfd = socket(domain, type, protocol)) < 0) 
    {
        fprintf(stderr, "socket error
");
        exit(1);
    }

    return sockfd;
}

int Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
    int ret;
    if ((ret = connect(sockfd, addr, addrlen)) < 0) 
    {
        fprintf(stderr, "connect error
");
        exit(1);
    }

    return ret;
}


int Close(int fd)
{
    int ret;
    if ((ret = close(fd)) < 0) 
    {
        fprintf(stderr, "close error
");
        exit(1);
    }

    return ret;
}


int main(int argc, char *argv[])
{
    if (argc != 3) 
    {
        fprintf(stderr, "Usage: ./fileclient <file> <serverIP>
");
        exit(1);
    }

    int sockfd;
    char buff[BUFFERSIZE + 1];
    char filenameheader[BUFFERSIZE + 1];
    struct sockaddr_in servaddr;
    int filefd;    /* file descriptor */
    int count;

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=INADDR_ANY;
    servaddr.sin_port = htons(PORT);
    
    
    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("已连接服务器
");

    printf("需统计的文件名为: %s........
", argv[1]);
    memcpy(filenameheader, argv[1], strlen(argv[1]));
    filenameheader[strlen(argv[1])] = '
';
    filenameheader[strlen(argv[1]) + 1] = 0;
    writen(sockfd, filenameheader, strlen(filenameheader));

    printf("正上传文件%s至服务器
", argv[1]);

    filefd = open(argv[1], O_RDONLY);
    if (filefd < 0) 
    {
        fprintf(stderr, "can't open the file: %s
", argv[1]);
        exit(1);
    }

    while(count = read(filefd, buff, BUFFERSIZE)) 
    {
        if (count < 0) 
        {
            fprintf(stderr, "filefd read error
");
            exit(1);
        }
        if (writen(sockfd, buff, count) < 0) 
        {
            fprintf(stderr, "writing to sockfd error
");
            exit(1);
        }
    }   
    Close(filefd);
    Close(sockfd);
    printf("文件%s已上传至服务器!
", argv[1]);
    return 0;
}

实验结果如下:

新学到的知识

  • 服务器-客户端模型
  • 多线程编程
  • 使用函数pthread_create创建一个新的线程
  • 使用函数pthread_join等待某进程结束
原文地址:https://www.cnblogs.com/lxy1997/p/7860815.html