2017-2018-1 20155329 实验三 实时系统

2017-2018-1 20155329 实验三 实时系统

实验目的

第一题

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

上方提交代码
附件提交测试截图,至少要测试附件中的两个文件
wc命令学习
  1. 命令格式:wc [选项]文件...
  2. 命令功能:统计指定文件中的字节数、字数、行数,并将统计结果显示输出。该命令统计指定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所指定文件的总统计数。
  3. 命令参数:

-c 统计字节数。

-l 统计行数。

-m 统计字符数。这个标志不能与 -c 标志一起使用。

-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。

-L 打印最长行的长度。

-help 显示帮助信息

-version 显示版本信息

socket编程

本段代码参考链接

TCP_Service
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/time.h> 
  
#define BUFLEN 1024 
#define PORT 6666
#define LISTNUM 20
  
int main() 
{ 
    int sockfd, newfd; 
    struct sockaddr_in s_addr, c_addr; 
    char buf[BUFLEN]; 
    socklen_t len; 
    unsigned int port, listnum; 
    fd_set rfds; 
    struct timeval tv; 
    int retval,maxfd; 
      
    /*建立socket*/ 
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ 
        perror("socket"); 
        exit(errno); 
    }else 
        printf("socket create success!\n"); 
    memset(&s_addr,0,sizeof(s_addr)); 
    s_addr.sin_family = AF_INET; 
    s_addr.sin_port = htons(PORT); 
    s_addr.sin_addr.s_addr = htons(INADDR_ANY); 
    
    /*把地址和端口帮定到套接字上*/ 
    if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){ 
        perror("bind"); 
        exit(errno); 
    }else 
        printf("bind success!\n"); 
    /*侦听本地端口*/ 
    if(listen(sockfd,listnum) == -1){ 
        perror("listen"); 
        exit(errno); 
    }else 
        printf("the server is listening!\n"); 
    while(1){ 
        printf("*****************聊天开始***************\n"); 
        len = sizeof(struct sockaddr); 
        if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){ 
            perror("accept"); 
            exit(errno); 
        }else 
            printf("正在与您聊天的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); 
        while(1){ 
            FD_ZERO(&rfds); 
            FD_SET(0, &rfds); 
            maxfd = 0; 
            FD_SET(newfd, &rfds); 
            /*找出文件描述符集合中最大的文件描述符*/ 
            if(maxfd < newfd) 
                maxfd = newfd; 
            /*设置超时时间*/ 
            tv.tv_sec = 6; 
            tv.tv_usec = 0; 
            /*等待聊天*/ 
            retval = select(maxfd+1, &rfds, NULL, NULL, &tv); 
            if(retval == -1){ 
                printf("select出错,
:
if(retval == -1){ 
                printf("select出错,与该客户端连接的程序将退出\n"); 
                break; 
            }else if(retval == 0){ 
                printf("waiting...\n"); 
                continue; 
            }else{ 
                /*用户输入信息了*/ 
                if(FD_ISSET(0, &rfds)){ 
            
                    /******发送消息*******/ 
                    memset(buf,0,sizeof(buf)); 
                    /*fgets函数:从流中读取BUFLEN-1个字符*/ 
                    fgets(buf,BUFLEN,stdin); 
                    /*打印发送的消息*/ 
                    //fputs(buf,stdout); 
                    if(!strncasecmp(buf,"quit",4)){ 
                        printf("server 请求终止聊天!\n"); 
                        break; 
                    } 
                        len = send(newfd,buf,strlen(buf),0); 
                    if(len > 0) 
                        printf("\t消息发送成功:%s\n",buf); 
                    else{ 
                        printf("消息发送失败!\n"); 
                        break; 
                    } 
                } 
                /*客户端发来了消息*/ 
                if(FD_ISSET(newfd, &rfds)){ 
                    /******接收消息*******/ 
                    memset(buf,0,sizeof(buf)); 
                    /*fgets函数:从流中读取BUFLEN-1个字符*/ 
                    len = recv(newfd,buf,BUFLEN,0); 
                    if(len > 0) 
                        printf("客户端发来的信息是:%s\n",buf); 
                    else{ 
                        if(len < 0 ) 
                            printf("接受消息失败!\n"); 
                        else 
                            printf("客户端退出了,聊天终止!\n"); 
                        break; 
                    } 
                } 
            } 
        } 
        /*关闭聊天的套接字*/ 
        close(newfd); 
        /*是否退出服务器*/ 
        printf("服务器是否退出程序:y->是;n->否? "); 
        bzero(buf, BUFLEN); 
        fgets(buf,BUFLEN, stdin); 
        if(!strncasecmp(buf,"y",1)){ 
            printf("server 退出!\n"); 
            break; 
        } 
    } 
    /*关闭服务器的套接字*/ 
    close(sockfd); 
    return 0; 
}
TCP_Client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>

#define BUFLEN 1024
#define PORT 6666

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in s_addr;
    socklen_t len;
    unsigned int port;
    char buf[BUFLEN];
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd; 
    
    /*建立socket*/
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(errno);
    }else
        printf("socket create success!\n");

    
    /*设置服务器ip*/
    memset(&s_addr,0,sizeof(s_addr));
    s_addr.sin_family = AF_INET;
     s_addr.sin_port = htons(PORT);
    if (inet_aton(argv[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0) {
        perror(argv[1]);
        exit(errno);
    }
    /*开始连接服务器*/ 
    if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1){
        perror("connect");
        exit(errno);
    }else
        printf("conncet success!\n");
    
    while(1){
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
        maxfd = 0;
        FD_SET(sockfd, &rfds);
        if(maxfd < sockfd)
            maxfd = sockfd;
        tv.tv_sec = 6;
        tv.tv_usec = 0;
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("waiting...\n");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sockfd,&rfds)){
                /******接收消息*******/
                bzero(buf,BUFLEN);
                len = recv(sockfd,buf,BUFLEN,0);
                if(len > 0)
                    printf("服务器发来的消息是:%s\n",buf);
                else{
                    if(len < 0 )
                        printf("接受消息失败!\n");
                    else
                        printf("服务器退出了,聊天终止!\n");
                break; 
                }

else
                        printf("服务器退出了,聊天终止!\n");
                break; 
                }
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){ 
                /******发送消息*******/ 
                bzero(buf,BUFLEN);
                fgets(buf,BUFLEN,stdin);
               
                if(!strncasecmp(buf,"quit",4)){
                    printf("client 请求终止聊天!\n");
                    break;
                }
                    len = send(sockfd,buf,strlen(buf),0);
                if(len > 0)
                    printf("\t消息发送成功:%s\n",buf); 
                else{
                    printf("消息发送失败!\n");
                    break; 
                } 
            }
        }
    
    }
    /*关闭连接*/
    close(sockfd);

    return 0;
}

https://private.cdn.img.oss.mosoteach.cn/mssvc/attachment/2017/11/55208b6fc7744033c8b2c632a5766a43.JPG%40!s200x200?OSSAccessKeyId=95rMSbPQpR5gkRWs&Expires=2147483647&Signature=0WMzSjPPis%2FGZ55DjxbthalOVcw%3D

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

linux 线程创建 同步与互斥 学习

  • 线程同步和互斥的区别:
  1. 互斥锁主要用来保护临界资源,什么是临界资源,就是有可能多个线程都需要访问的数据地址,也有可能是某一段代码,执行这段代码有可能会改变多个线程都需要访问的数据。

  2. 加入同步机制主要是为了在多线程程序中,如果需要对某个共享资源C进行同步访问,什么是同步访问,就是A线程访问过程中,B线程不能访问,必须等A线程访问结束后,B线程才能访问,而互斥锁,如果用来对C进行保护,A访问C资源的过程中,B不能访问,A访问结束后,B可以访问,但不一定访问的到,这取决于系统的调度是否给到B,如果没有,A反而被调度到了,那么A就有可能方法到C。

  3. 反观同步机制,在这种情况下,如果系统没有调度到B,A也是没有可能访问C的,必须等B调度到之后,A才可能重新访问。

单线程
  • 单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)
多线程
  • 使用多线程编程的目的:就是"最大限度地利用CPU资源"
  • 坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
  • 好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。
  • 线程相对于进程的缺点:
  1. 共享资源需要耗费一定的锁资源,同步相对复杂。
  2. 一个线程崩溃可能导致整个进程崩溃,这个当然是自己的应用程序有问题

感想

  • 本次实验将操作系统,web编程中的socket编程都覆盖到了,第二题还将线程加入进来,在做实验的过程中查看了很多相关博客,参考了挺多代码,在参考代码的同是看到了很多大神们的简介,阐述了socket编程,线程,进程的关系优缺点。复习了操作系统课上的同步与互斥,用实例来更深刻的理解,还将刘念老师的实验也给做了。
posted @ 2017-11-19 21:57  20155329胡佩伦  阅读(174)  评论(0编辑  收藏  举报