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

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

    并发程序-1

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

    • 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端

    • 客户端传一个文本文件给服务器

    • 服务器返加文本文件中的单词数

    • 上方提交代码

    • 附件提交测试截图,至少要测试附件中的两个文件

    首先先学习一下命令wc使用

    • 利用man命令查看wc命令使用

    实例为:

    1. 统计行数
    $wc –l file
    
    1. 统计单词数
    $wc –w file
    
    1. 统计字符数
    $wc –c file
    
    1. 统计流中的字符数
    $echo –n 1234 | wc –c
    

    实验过程

    实验代码

    Server.c
    #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
    #include<unistd.h>
    #define SERVER_PORT 155316
    #define LENGTH_OF_LISTEN_QUEUE 20
    #define BUFFER_SIZE 1024
    #define FILE_NAME_MAX_SIZE 512
    int CountWordsOfEuropeanTxtFile(char *szFileName);
    int CountWordsInOneLine(const char *szLine);
    int main(void)
    {
        // 声明并初始化一个服务器端的socket地址结构
        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(SERVER_PORT);
       // 创建socket,若成功,返回socket描述符
        int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
        if(server_socket_fd < 0)
        {
            perror("Create Socket Failed:");
            exit(1);
        }
        int opt = 1;
        setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
     // 绑定socket和socket地址结构
        if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
        {
            perror("Server Bind Failed:");
            exit(1);
        }
         // socket监听
        if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
        {
            perror("Server Listen Failed:");
            exit(1);
        }
    while(1)
        {
            // 定义客户端的socket地址结构
            struct sockaddr_in client_addr;
            socklen_t client_addr_length = sizeof(client_addr);
     // 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信
            // accept函数会把连接到的客户端信息写到client_addr中
            int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
            if(new_server_socket_fd < 0)
            {
                perror("Server Accept Failed:");
                break;
            }
            // recv函数接收数据到缓冲区buffer中
            char buffer[BUFFER_SIZE];
            bzero(buffer, BUFFER_SIZE);
            if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
            {
                perror("Server Recieve Data Failed:");
                break;
            }
            // 然后从buffer(缓冲区)拷贝到file_name中
            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));
            printf("5316:%s
    ", file_name);
    	int count=0;
    	bzero(buffer, BUFFER_SIZE);
    	count = CountWordsOfEuropeanTxtFile(file_name);
    	sprintf(buffer,"%d", count);
            if(send(new_server_socket_fd, buffer, sizeof(buffer), 0) < 0)
            {
                   printf("Send File:%s Failed./n", file_name);
            }
    	bzero(buffer, BUFFER_SIZE);	
            /*/ 打开文件并读取文件数据
            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(new_server_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);
            }*/
            // 关闭与客户端的连接
            close(new_server_socket_fd);
        }
        // 关闭监听用的socket
        close(server_socket_fd);
        return 0;
    }
    int CountWordsOfEuropeanTxtFile(char *szFileName)
    {
    	int nWords = 0;//词计数变量,初始值为0
    	FILE *fp; //文件指针
    	char carrBuffer[1024];//每行字符缓冲,每行最多1024个字符
    	//打开文件
    	if ((fp = fopen(szFileName,  "r")) == NULL)
    	{
    		return -1;	//文件打开不成功是返回-1
    	}
    	while (!feof(fp))//如果没有读到文件末尾 
    	{
    		//从文件中读一行
    		if (fgets(carrBuffer, sizeof(carrBuffer),fp) != NULL)
    			//统计每行词数
    			nWords += CountWordsInOneLine(carrBuffer);
    	}
    	//关闭文件
    	fclose(fp);
    	return nWords;
    }
    int CountWordsInOneLine(const char *szLine)
    {
    	int nWords = 0;
    	int i=0;
    	for (;i<strlen(szLine);i++)
    	{
    		if (*(szLine+i)!=' ')
    		{
    			nWords++;
    			while ((*(szLine+i)!=' ')&&(*(szLine+i)!=''))
    			{
    				i++;
    			}
    		}
    
    	}
    			//printf("%d	",nWords);
    	
    	return nWords;
    }
    
    Client.c
    #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
    #include<unistd.h>
    #include<stdlib.h>
    #define SERVER_PORT 155316
    #define BUFFER_SIZE 1024
    #define FILE_NAME_MAX_SIZE 512
    int main()
    {
        // 声明并初始化一个客户端的socket地址结构
        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);
        // 创建socket,若成功,返回socket描述符
        int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(client_socket_fd < 0)
        {
            perror("Create Socket Failed:");
            exit(1);
        }
        // 绑定客户端的socket和客户端的socket地址结构 非必需
        if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
        {
            perror("Client Bind Failed:");
            exit(1);
        }
        // 声明一个服务器端的socket地址结构,并用服务器那边的IP地址及端口对其进行初始化,用于后面的连接
        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);
        // 向服务器发起连接,连接成功后client_socket_fd代表了客户端和服务器的一个socket连接
        if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
        {
            perror("Can Not Connect To Server IP:");
            exit(0);
        }
        // 输入文件名 并放到缓冲区buffer中等待发送
        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中的数据
        if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
        {
            perror("Send File Name Failed:");
            exit(1);
        }	
        //int count=0;
        int length=0;
        bzero(buffer, BUFFER_SIZE);
        length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0);
        buffer[length] = '';
        printf("count=%s
    ", buffer);
        bzero(buffer, BUFFER_SIZE);   
        /* / 打开文件,准备写入
         / 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_fd, buffer, BUFFER_SIZE, 0)) > 0)
        {
            if(fwrite(buffer, sizeof(char), length, fp) < length)
            {
                printf("File:	%s Write Failed
    ", file_name);
                break;
            }
            bzero(buffer, BUFFER_SIZE);
        }
        / 接收成功后,关闭文件,关闭socket
        printf("Receive File:	%s From Server IP Successful!
    ", file_name);
        fclose(fp);
        */
        close(client_socket_fd);
        return 0;
    }
    

    实验操作

    • 查阅相关资料,了解wc是可以对一个文件内的单词数进行一个统计
    • 对程序初步设计分为两块,一块是C/S程序,一块是对传入文件进行单词统计
    • 具体程序见CS_tfile

    实验问题及解答

    出现的问题

    • 编译client server程序时出现如下警告(因为当时没有截图,以下截图为实景还原)
    • 说是宏定义的常量过大,以及没有inet_pton函数
    • 这两个都是警告
    • 实际运行时还是可以正常运行,这说明我们可以暂时不管这两个警告

    并发程序-2

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

    实验过程

    实验代码

    thread_server.c
    #include<stdlib.h>
    #include<pthread.h>
    #include<sys/socket.h>
    #include<sys/types.h>       //pthread_t , pthread_attr_t and so on.
    #include<stdio.h>
    #include<netinet/in.h>      //structure sockaddr_in
    #include<arpa/inet.h>       //Func : htonl; htons; ntohl; ntohs
    #include<assert.h>          //Func :assert
    #include<string.h>          //Func :memset bzero
    #include<unistd.h>          //Func :close,write,read
    #define SOCK_PORT 9988
    #define BUFFER_LENGTH 1024
    #define MAX_CONN_LIMIT 512     //MAX connection limit
    static void Data_handle(void * sock_fd);   //Only can be seen in the file
    int CountWordsOfEuropeanTxtFile(char *szFileName);
    int CountWordsInOneLine(const char *szLine);
    int main()
    {
        int sockfd_server;
        int sockfd;
        int fd_temp;
        struct sockaddr_in s_addr_in;
        struct sockaddr_in s_addr_client;
        int client_length;
        sockfd_server = socket(AF_INET,SOCK_STREAM,0);  //ipv4,TCP
        assert(sockfd_server != -1);
        //before bind(), set the attr of structure sockaddr.
        memset(&s_addr_in,0,sizeof(s_addr_in));
        s_addr_in.sin_family = AF_INET;
        s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);  //trans addr from uint32_t host byte order to network byte order.
        s_addr_in.sin_port = htons(SOCK_PORT);          //trans port from uint16_t host byte order to network byte order.
        fd_temp = bind(sockfd_server,(const struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
        if(fd_temp == -1)
        {
            fprintf(stderr,"bind error!
    ");
            exit(1);
        }
        fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
        if(fd_temp == -1)
        {
            fprintf(stderr,"listen error!
    ");
            exit(1);
        }
        while(1)
        {
            printf("waiting for new connection...
    ");
            pthread_t thread_id;
            client_length = sizeof(s_addr_client);
            //Block here. Until server accpets a new connection.
            sockfd = accept(sockfd_server,(struct sockaddr * restrict)(&s_addr_client),(socklen_t *)(&client_length));
            if(sockfd == -1)
            {
                fprintf(stderr,"Accept error!
    ");
                continue;                               //ignore current socket ,continue while loop.
            }
            printf("A new connection occurs!
    ");
            if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
            {
                fprintf(stderr,"pthread_create error!
    ");
                break;                                  //break while loop
            }
        }
        //Clear
        int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection.
        assert(ret != -1);
        printf("Server shuts down
    ");
        return 0;
    }
    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!
    ";
        while(1)
        {
            printf("waiting for file_name...
    ");
            //Reset data.
            memset(data_recv,0,BUFFER_LENGTH);
            i_recvBytes = read(fd,data_recv,BUFFER_LENGTH);
            if(i_recvBytes == 0)
            {
                printf("Maybe the client has closed
    ");
                break;
            }
            if(i_recvBytes == -1)
            {
                fprintf(stderr,"read error!
    ");
                break;
            }
            if(strcmp(data_recv,"quit")==0)
            {
                printf("Quit command!
    ");
                break;                           //Break the while loop.
            }
            printf("read from client : %s
    ",data_recv);
    		
    	char buffer[BUFFER_LENGTH];
    	int count=0;
    	bzero(buffer, BUFFER_LENGTH);
    	count = CountWordsOfEuropeanTxtFile(data_recv);
    	sprintf(buffer,"%d", count);
            send(fd, buffer, sizeof(buffer), 0);
            if(write(fd,data_send,strlen(data_send)) == -1)
            {
                break;
            }
        }
        //Clear
        printf("terminating current client_connection...
    ");
        close(fd);            //close a file descriptor.
        pthread_exit(NULL);   //terminate calling thread!
    }
    int CountWordsOfEuropeanTxtFile(char *szFileName)
    {
    	int nWords = 0;//词计数变量,初始值为0
    	FILE *fp; //文件指针
    	char carrBuffer[1024];//每行字符缓冲,每行最多1024个字符
    	//打开文件
    	if ((fp = fopen(szFileName,  "r")) == NULL)
    	{
    		return -1;	//文件打开不成功是返回-1
    	}
    	while (!feof(fp))//如果没有读到文件末尾 
    	{
    		//从文件中读一行
    		if (fgets(carrBuffer, sizeof(carrBuffer),fp) != NULL)
    			//统计每行词数
    			nWords += CountWordsInOneLine(carrBuffer);
    	}
    
    	//关闭文件
    	fclose(fp);
    	return nWords;
    }
    int CountWordsInOneLine(const char *szLine)
    {
    	int nWords = 0;
    	int i=0;
    	for (;i<strlen(szLine);i++)
    	{
    		if (*(szLine+i)!=' ')
    		{
    			nWords++;
    			while ((*(szLine+i)!=' ')&&(*(szLine+i)!=''))
    			{
    				i++;
    			}
    		}
    
    	}
    			//printf("%d	",nWords);
    	
    	return nWords;
    }
    
    
    thread_client.c
    #include<stdlib.h>
    #include<sys/socket.h>
    #include<sys/types.h>       //pthread_t , pthread_attr_t and so on.
    #include<stdio.h>
    #include<netinet/in.h>      //structure sockaddr_in
    #include<arpa/inet.h>       //Func : htonl; htons; ntohl; ntohs
    #include<assert.h>          //Func :assert
    #include<string.h>          //Func :memset bzero
    #include<unistd.h>          //Func :close,write,read
    #define SOCK_PORT 9988
    #define BUFFER_LENGTH 1024
    int main()
    {
        int sockfd;
        int tempfd;
        struct sockaddr_in s_addr_in;
        char data_send[BUFFER_LENGTH];
        char data_recv[BUFFER_LENGTH];
        memset(data_send,0,BUFFER_LENGTH);
        memset(data_recv,0,BUFFER_LENGTH);
        sockfd = socket(AF_INET,SOCK_STREAM,0);       //ipv4,TCP
        if(sockfd == -1)
        {
            fprintf(stderr,"socket error!
    ");
            exit(1);
        }
        //before func connect, set the attr of structure sockaddr.
        memset(&s_addr_in,0,sizeof(s_addr_in));
        s_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");      //trans char * to in_addr_t
        s_addr_in.sin_family = AF_INET;
        s_addr_in.sin_port = htons(SOCK_PORT);
        tempfd = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
        if(tempfd == -1)
        {
            fprintf(stderr,"Connect error! 
    ");
            exit(1);
        }
        while(1)
        {
        	printf("Please Input File Name On Server(input "quit" to quit):	");
    	scanf("%s", data_send);        
    	//gets(data_send);
            //scanf("%[^
    ]",data_send);         //or you can also use this
            tempfd = write(sockfd,data_send,BUFFER_LENGTH);
            if(tempfd == -1)
            {
                fprintf(stderr,"write error
    ");
                exit(0);
            }
    
            if(strcmp(data_send,"quit") == 0)  //quit,write the quit request and shutdown client
            {
                break;
            }
            else
            {
                tempfd = read(sockfd,data_recv,BUFFER_LENGTH);
                assert(tempfd != -1);
                printf("%s
    ",data_recv);
                memset(data_send,0,BUFFER_LENGTH);
                memset(data_recv,0,BUFFER_LENGTH);
            }
    	char buffer[BUFFER_LENGTH];
    	int length=0;
       	bzero(buffer, BUFFER_LENGTH);
        	length = recv(sockfd, buffer, BUFFER_LENGTH, 0);
        	buffer[length] = '';
        	printf("count=%s
    ", buffer);
        	bzero(buffer, BUFFER_LENGTH);
        }
        int ret = shutdown(sockfd,SHUT_WR);       //or you can use func close()--<unistd.h> to close the fd
        assert(ret != -1);
        return 0;
    }
    

    实验操作

    • 性能比较:多线程一定程度上提高响应速度,在多核的情况下更能充分利用CPU资源

    • 以下为实践内容

    • 代码

    并发程序-3

    此次试验三因为时间原因,没有进行成功,我们先学习了一些知识。

    如何调用进程?

    1. 首先man -k thread|grep create查看
    2. 找到函数,用man 3 pthread_create命令得到详细信息。

    根据这个网址
    http://blog.csdn.net/youbang321/article/details/7815707
    了解到

    功能:创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数。
    
    说明:thread:线程标识符;
    
              attr:线程属性设置;
    
              start_routine:线程函数的起始地址;
    
              arg:传递给start_routine的参数;
    
              返回值:成功,返回0;出错,返回-1。
    

    感想

    本次实验是基于网络编程基础的一次实验,与Windows环境下有很大的不同,并且加了很多其他的功能。实验过程中总体来说还是比较艰难的,因为时间和自己预习不充分的原因,使得部分没有完整做出来。

    这个实验充分利用了我们网络编程中的知识,将课堂上讲的东西应用于实践中,使得我们对于客户端与服务器之间的通信有了比较好的认识,也对我们今后的学习有了实践的基础。

  • 相关阅读:
    mysql BETWEEN操作符 语法
    mysql IN操作符 语法
    mysql LIKE通配符 语法
    mysql TOP语句 语法
    mysql DELETE语句 语法
    mysql Update语句 语法
    mysql INSERT语句 语法
    mysql ORDER BY语句 语法
    mysql OR运算符 语法
    mysql AND运算符 语法
  • 原文地址:https://www.cnblogs.com/JIUSHA/p/7861301.html
Copyright © 2011-2022 走看看