zoukankan      html  css  js  c++  java
  • 2018-2019-1 20165205 实验三 实时系统

    2018-2019-1 20165205 实验三 并发进程

    任务一:

    • 学习使用Linux命令wc(1)

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

    客户端代码如下:

    #include<netinet/in.h>   // sockaddr_in  
    #include<sys/types.h>    // socket  
    #include<sys/socket.h>   // socket  
    #include<stdio.h>        // printf  
    #include<stdlib.h>       // exit  
    #include<string.h>       // bzero  
    
    #define SERVER_PORT 165205  
    #define BUFFER_SIZE 1024  
    #define FILE_NAME_MAX_SIZE 512  
    #define BEGIN 1;
    
    int main()  
    {  	
    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_fd = socket(AF_INET, SOCK_STREAM, 0);  
    if(client_socket_fd < 0)  
    {  
        perror("Create Socket Failed:");  
        exit(1);  
    }  
    
    if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))  
    {  
        perror("Client Bind Failed:");  
        exit(1);  
    }  
    
    struct sockaddr_in server_addr;  
    bzero(&server_addr, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;  
    if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)  
    {  
        perror("Server IP Address Error:");  
        exit(1);  
    }  
    server_addr.sin_port = htons(SERVER_PORT);  
    socklen_t server_addr_length = sizeof(server_addr);  
    
    if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)  
    {  
        perror("Can Not Connect To Server IP:");  
        exit(0);  
    }  
    
    char file_name[FILE_NAME_MAX_SIZE+1];  
    bzero(file_name, FILE_NAME_MAX_SIZE+1);  
    
    printf("Please Input File Name On Client:	");
    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));  
    
    if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)  
    {  
        perror("Send File Name Failed:");  
        exit(1);  
    }  
    
        FILE *fp = fopen(file_name, "r");  
        if(NULL == fp)  
    {  
        printf("File:%s Not Found
    ", file_name);  
    }  
    else  
    {  
        bzero(buffer, BUFFER_SIZE);  
        int length = 0;  
        while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)  
        {  
            if(send(client_socket_fd, buffer, length, 0) < 0)  
            {  
                printf("Send File:%s Failed./n", file_name);  
                break;  
            }  
            bzero(buffer, BUFFER_SIZE);  
        }  
    
        fclose(fp);  
        printf("File:%s Transfer Successful!
    ", file_name);  
    }  
    
    char s[50];
    scanf("%s",s);
    send(client_socket_fd,"OK",50,0);
    
    char recvdata[sizeof(int)+1];
    recv(client_socket_fd,recvdata,sizeof(int),0);
    recvdata[sizeof(int)]='';
    int words=atoi(recvdata);
    close(client_socket_fd);  
    return 0;  
    }
    

    服务器端代码如下:

    #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(PF_INET, SOCK_STREAM, 0)) == -1){ 
        perror("socket"); 
        exit(errno); 
    }else 
        printf("socket create success!
    "); 
    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 = htonl(INADDR_ANY); 
    
    /*把地址和端口帮定到套接字上*/ 
    if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){ 
        perror("bind error"); 
        exit(errno); 
    }else 
        printf("bind success!
    "); 
    /*侦听本地端口*/ 
    if(listen(sockfd,5) == -1){ 
        perror("listen error"); 
        exit(errno); 
    }else 
        printf("the server is listening!
    "); 
    while(1){ 
        printf("*****************聊天开始***************
    "); 
        len = sizeof(struct sockaddr); 
        if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){ 
            perror("accept"); 
            exit(errno); 
        }else 
            printf("正在与您聊天的客户端是:%s: %d
    ",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出错,与该客户端连接的程序将退出
    ");  
                break; 
            }else if(retval == 0){ 
                printf("waiting...
    "); 
                continue; 
            }else{ 
                /*服务器输入信息*/ 
                if(FD_ISSET(0, &rfds)){ 
            
                    /******发送消息*******/ 
                    memset(buf,0,sizeof(buf)); 
                    
                    fgets(buf,BUFLEN,stdin); 
                    
                    //fputs(buf,stdout); 
                    if(!strncasecmp(buf,"quit",4)){ 
                        printf("server 请求终止聊天!
    "); 
                        break; 
                    } 
                        len = send(newfd,buf,strlen(buf),0); 
                    if(len > 0) 
                        printf("	消息发送成功:%s
    ",buf); 
                    else{ 
                        printf("消息发送失败!
    "); 
                        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
    ",buf); 
                    else{ 
                        if(len < 0 ) 
                            printf("接受消息失败!
    "); 
                        else 
                            printf("客户端退出了,聊天终止!
    "); 
                        break; 
                    } 
                } 
            } 
        } 
        /*关闭聊天的套接字*/ 
        close(newfd); 
        /*是否退出服务器*/ 
        printf("服务器是否退出程序:y->是;n->否? "); 
        bzero(buf, BUFLEN); 
        fgets(buf,BUFLEN, stdin); 
        if(!strncasecmp(buf,"y",1)){ 
            printf("server 退出!
    "); 
            break; 
        } 
    } 
    /*关闭服务器的套接字*/ 
    close(sockfd); 
    return 0; 
    }
    
    • 实验截图

    任务二:

    • 使用多线程实现wc服务器并使用同步互斥机制保证计数

    在实验之前,我学习了关于多线程函数pthread的一些知识

    1.pthread_creat函数

    它的作用是创建一个新线程,使用方法如下:

    #include <pthread.h>
    int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); 
    

    第一个参数是指向pthread_t类型的指针。线程被创建时 这个指针指向的变量将被写入一个标识符(线程ID)我们用该标识符来引用新线程。

    第二个参数用于设置线程的属性,一般不需要特殊的属性,所以只需要设置该参数为NULL。

    最后两个参数,分别告诉新线程将要启动执行的函数和传递给该函数的参数。

    pthread_create函数在成功调用时返回0,如果失败则返回失败码

    2.pthread_exit函数

    线程通过调用pthread_exit函数终止执行。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针

    #include <pthread.h>
    void pthread_exit(void *retval);
    

    3.pthread_join函数

    pthread_join函数的作用是等待某个线程的结束。其第一个参数指定了需要等待的线程ID,第二个参数是一个二级指针,它指向另一个指针,而后者指向线程的返回值。

    #include <pthread.h>
    int pthread_join(pthread_t th, void **thread_return);
    

    4.pthread_self函数

    每个线程都有一个在所属进程内标识自己的ID。线程ID由phtread_create返回,而且我们已经看到pthread_join也使用了线程ID来指定等待哪个线程。pthread_self的作用是返回自身的线程ID.

    #include <pthread.h>
    pthread_t pthread_self(void);
    

    5.pthread_detach函数

    一个线程或者是可汇合(joinable),或者是脱离的(detached)。当一个可汇合的线程终止时,它的线程ID和退出状态将留存到另一个线程对它调用pthread_join的返回值中。脱离的线程终止时,所有相关资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一个线程什么时候终止,那就最好保持第二个线程的可汇合状态。

    pthread_detach函数把指定的线程转变为脱离的状态。

    #include <pthread.h>
    int pthread_detach(pthread_t th);
    
    • 多线程客户端代码:

        #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; 
        
        if(argc != 2)
        {
            perror("Usage:./client <ipaddress>.");
            exit(errno);
        }
      
      
        /*建立socket*/
        if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(errno);
        }else
            printf("socket create success!
      ");
      
      
        /*设置服务器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!
      ");
      
        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出错,客户端程序退出
      ");
                break;
            }else if(retval == 0){
            printf("waiting...
      ");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sockfd,&rfds)){
                /******接收消息*******/
                bzero(buf,BUFLEN);
                len = recv(sockfd,buf,BUFLEN,0);
                if(len > 0)
                    printf("服务器发来的消息是:%s
      ",buf);
                else{
                    if(len < 0 )
                        printf("接受消息失败!
      ");
                    else
                        printf("服务器退出了,聊天终止!
      ");
                break; 
                }
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0, &rfds)){ 
                /******发送消息*******/ 
                bzero(buf,BUFLEN);
                fgets(buf,BUFLEN,stdin);
               
                if(!strncasecmp(buf,"quit",4)){
                    printf("client 请求终止聊天!
      ");
                    break;
                }
                    len = send(sockfd,buf,strlen(buf),0);
                if(len > 0)
                    printf("	消息发送成功:%s
      ",buf); 
                else{
                    printf("消息发送失败!
      ");
                    break; 
                } 
            }
        }
      
        }
        /*关闭连接*/
        close(sockfd);
      
        return 0;
        }	
      
    • 多线程服务器代码:

        #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(PF_INET, SOCK_STREAM, 0)) == -1){ 
            perror("socket"); 
            exit(errno); 
        }else 
            printf("socket create success!
      "); 
        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 = htonl(INADDR_ANY); 
      
        /*把地址和端口帮定到套接字上*/ 
        if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){ 
            perror("bind error"); 
            exit(errno); 
        }else 
            printf("bind success!
      "); 
        /*侦听本地端口*/ 
        if(listen(sockfd,5) == -1){ 
            perror("listen error"); 
            exit(errno); 
        }else 
            printf("the server is listening!
      "); 
        while(1){ 
            printf("*****************聊天开始***************
      "); 
            len = sizeof(struct sockaddr); 
            if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){ 
                perror("accept"); 
                exit(errno); 
        }else 
            printf("正在与您聊天的客户端是:%s: %d
      ",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出错,与该客户端连接的程序将退出
      ");  
                break; 
            }else if(retval == 0){ 
                printf("waiting...
      "); 
                continue; 
            }else{ 
                /*服务器输入信息*/ 
                if(FD_ISSET(0, &rfds)){ 
            
                    /******发送消息*******/ 
                    memset(buf,0,sizeof(buf)); 
                    
                    fgets(buf,BUFLEN,stdin); 
                    
                    //fputs(buf,stdout); 
                    if(!strncasecmp(buf,"quit",4)){ 
                        printf("server 请求终止聊天!
      "); 
                        break; 
                    } 
                        len = send(newfd,buf,strlen(buf),0); 
                    if(len > 0) 
                        printf("	消息发送成功:%s
      ",buf); 
                    else{ 
                        printf("消息发送失败!
      "); 
                        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
      ",buf); 
                    else{ 
                        if(len < 0 ) 
                            printf("接受消息失败!
      "); 
                        else 
                            printf("客户端退出了,聊天终止!
      "); 
                        break; 
                    } 
                } 
            } 
        } 
        /*关闭聊天的套接字*/ 
        close(newfd); 
        /*是否退出服务器*/ 
        printf("服务器是否退出程序:y->是;n->否? "); 
        bzero(buf, BUFLEN); 
        fgets(buf,BUFLEN, stdin); 
        if(!strncasecmp(buf,"y",1)){ 
            printf("server 退出!
      "); 
            break; 
        } 
        } 
        /*关闭服务器的套接字*/ 
        close(sockfd); 
        return 0; 
        }
      
    • 实验截图

    遇到的问题及解决方法

    • 问题:在编译多线程的代码时使用普通的gcc server.c -o server没有编译成功。
    • 解决方法:由于多线程使用到了pthread的函数库,需要手动加入,将编译命令改为gcc server.c -o server -lpthread则可以 解决这个问题。
  • 相关阅读:
    编写高质量Python代码的59个有效方法
    排序NB三人组(快速排序/堆排序/归并排序)
    排序之插入排序
    编写高质量代码 改善Python程序的91个建议——笔记(三)
    ImportHelper 导出帮助类
    使用Layer弹出一个页面
    MongoDB使用手册
    MVC4设置@Html.BeginForm的ID
    LayerManage
    Layer弹窗返回数据回调
  • 原文地址:https://www.cnblogs.com/mushroomissmart/p/9959064.html
Copyright © 2011-2022 走看看