zoukankan      html  css  js  c++  java
  • 2019-2020信息安全系统设计基础 20175306 20175309 20175322 实验三 并发程序

    实验目的及步骤

    并发程序-1

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

     上方提交代码
     附件提交测试截图,至少要测试附件中的两个文件
    

    (1)学习使用Linux命令wc(1)
    首先使用“找男人”命令学习wc命令,即man wc命令查看wc命令

    可以晓得wc命令是用来统计指定文件中的字节数、字数、行数并将统计结果直接输出
    直接使用wc+文件名.txt命令就可以了。

    (2)基于Socket程序设计实现wc服务端和客户端的文件传输
    原理:

    客户端代码:

    #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 165235  
    #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 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));  
    
        // 向服务器发送buffer中的数据  
        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",BUFFER_SIZE,0);
            recv(client_socket_fd,buffer,BUFFER_SIZE,0);    
            printf("%d words.
    ",atoi(buffer));
        }  
    
        close(client_socket_fd);  
        return 0;  
    } 
    

    服务器端

    #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 165235  
    #define LENGTH_OF_LISTEN_QUEUE 20  
    #define BUFFER_SIZE 1024
    #define FILE_NAME_MAX_SIZE 512  
    
    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("%s
    ", file_name);  
    
        // 打开文件,准备写入  
            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(new_server_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)  
            {  
            if(strcmp(buffer,"OK")==0) break;
                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 Client IP Successful!
    ", file_name);  
            fclose(fp);
    
    
        // 统计文件单词个数,并发送给客户端
        int words=0;
        char s[100];
        FILE *fp2;
        if((fp2=fopen(file_name,"r"))==NULL){
            printf("ERROR!
    ");
            exit(0);
        }
        while(fscanf(fp2,"%s",s)!=EOF)
            words++;
        fclose(fp2);
        //printf("%d words.
    ",words);
    
    
        sprintf(buffer,"%d",words);
    
        send(new_server_socket_fd,buffer,BUFFER_SIZE,0);
    
        //send(new_server_socket_fd,&words,sizeof(words),0);
        close(new_server_socket_fd);  
    
    
    
            // 关闭与客户端的连接  
    
        }  
        // 关闭监听用的socket  
        close(server_socket_fd);  
        return 0;  
    } 
    

    测试截图

    并发程序-2

    要求:使用多线程实现wc服务器并使用同步互斥机制保证计数正确
    上方提交代码
    下方提交测试
    对比单线程版本的性能,并分析原因。
    基本步骤:
    服务端创建ServerSocket绑定端口号,循环调用accept()方法。
    客户端创建一个socket并请求和服务器端连接。
    服务器端接受客户端请求,创建socket与该客户建立连接。
    两个socket在一个单独的线程上通话。
    服务器端继续等待新的连接,当有一个新的客户端与服务端连接,就创建一个新的socket并在这个线程里面通信。
    而且编译的时候要添加-lpthread选项声明需要链接线程库,就创建一个新的socket并在这个线程里面通信。

    新增一个头文件head.h

    #ifndef HEAD_H
    #define HEAD_H
    int wcfunc(char *file_name);
    #endif
    

    客户端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include "head.h"
    #define BUFFER_SIZE 1024  
    #define FILE_NAME_MAX_SIZE 512 
    
    static void usage(const char* proc)
    {
        printf("%s[server_ip][server_port]
    ", proc);
    }
    
    //./client server_ip, server_port
    int main(int argc, char* argv[])
    {
        if(argc != 3)
        {
            usage(argv[0]);
            return 1;
        }
        //1.创建sock
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
            perror("socket");
            return 2;
        }
        //2.connect
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(atoi(argv[2]));
        //将点分十进制的字符串转换成能在网络上传输的网络号
        server.sin_addr.s_addr = inet_addr(argv[1]);
        //调用connect,第一个参数是客户端的socket套接字,第二个参数是服务器端套接字
        if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
        {
            perror("connect");
            return 2;
        }
        /*//先写后读
        char buf[1024];
        while(1)
        {
            printf("Please enter# ");
            fflush(stdout);
            //读取标准输入键盘中的数据
            ssize_t s = read(0, buf, sizeof(buf) - 1);
            if(s > 0)
            {
                buf[s - 1] = 0;
                //将buf中的内容写到套接字中
                write(sock, buf, strlen(buf));
                //读取服务器的响应
                ssize_t _s = read(sock, buf, sizeof(buf)-1);
                if(_s > 0)
                {
                    buf[_s] = 0;
                    printf("server ech0# %s
    ", buf);
                }
            }
        }*/
        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(sock, 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(sock, buffer, length, 0) < 0)  
                {  
                 	printf("Send File: %s Failed!/n", file_name);  
                    break;  
                }  
                bzero(buffer, BUFFER_SIZE);  
            }  
    	printf("Send File: %s Successful!
    ", file_name);
    	printf("The File has %d words.
    ",wcfunc(file_name));	  
        }
        fclose(fp);
        close(sock);
        return 0;
    }
    
    int wcfunc(char *file_name)
    {
    	int t;
    	int w = 0;
    	int state = 0;
    	FILE *in;
    	if((in = fopen(file_name,"r"))==NULL)
    	{
    		printf("wc %s:no this file or dir
    ",file_name);
    		return 0;
    	}
    	while((t=fgetc(in))!=EOF)
    	{
    		
    		if(t=='
    '||t==' '||t=='
    ') {
                		state = 0;
                		continue;
            	} else {
                		if(state == 0) {
                    	state = 1;
                    	w++;
               		}
                		continue;
            	}
    	}
    	return w;
    }
    
    

    服务器端

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #define BUFFER_SIZE 1024
    #define FILE_NAME_MAX_SIZE 512
    static void Usage(char* proc)
    {
        printf("%s[local_ip], [local_port]
    ", proc);
    }
    int startup(char* _ip, int _port)
    {
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
            perror("socket");
            return 1;
        }
        struct sockaddr_in local;//初始化协议地址
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip);
        //将套接字和tcp服务绑定(服务端ip地址)
        if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            perror("bind");
            exit(3);
        }
        //监听这个套接字,监听指定端口,第二个参数表示可以排队连接的最大个数
        if(listen(sock, 5) < 0)
        {
            perror("listen");
        }
        return sock;
    }
    void* handle(void* argc)
    {
        int newsock = (int)argc;
        char buf[1024];
        while(1)
        {
            int s = read(newsock, buf, sizeof(buf) - 1);
            if(s > 0)
            {
                buf[s] = 0;
                printf("client# %s
    ", buf);
                write(newsock, buf, strlen(buf));//服务器回显
            }
            else if(s == 0)
            {
                printf("client quit
    ");
            }
            else
            {
                break;
            }
        }
        close(newsock);
    }
    //argv[]指针数组,指向各个参数
    int main(int argc, char* argv[])
    {
        if(argc != 3)
        {
            Usage(argv[0]);
            return 2;
        }
        int listen_sock = startup(argv[1], atoi(argv[2]));
        //printf("sock:%d
    ", listen_sock);
        //需要让子进程的子进程去提供服务
        //父进程继续监听
        char buf[1024];
        while(1)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int newsock = accept(listen_sock, (struct sockaddr*)&client, &len);
            if(newsock < 0)
            {
                perror("accept");
                continue;
            }
            //将网络中的数据转换为主机用户可以看懂的数据
            printf("get a new client %s:%d
    ", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
            //创建一个新的线程去服务
            //主线程只负责监听工作
            pthread_t tid;
            //pthread_create(&tid, NULL, handle, (void*)newsock);
            pthread_detach(tid);
    
    	/*char buffer[BUFFER_SIZE]; 
    	bzero(buffer, BUFFER_SIZE); 
    	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("%s
    ", file_name);  
        	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(newsock, buffer, BUFFER_SIZE, 0)) > 0)  
        	{  
    	    if(strcmp(buffer,"OK")==0) 
    		break;
    	    if(fwrite(buffer, sizeof(char), length, fp) < length)  
    	    {  
    	  	printf("File: %s Write Failed!
    ", file_name);  
    	    	break;  
    	    }  
                bzero(buffer, BUFFER_SIZE);  
    	}  
        	printf("Receive File: %s From Client Successful!
    ", file_name);  
        	fclose(fp);
    
    	int words=0;
    	char s[100];
    	FILE *fp2;
    	if((fp2=fopen(file_name,"r"))==NULL)
    	{
    	    printf("ERROR!
    ");
    	    exit(0);
    	}
    	while(fscanf(fp2,"%s",s)!=EOF)
      	words++;
    	fclose(fp2);
    	printf("%d words.
    ",words);
    	char sendbuf[50];
    	sprintf(sendbuf,"%d",words);
    	send(newsock,sendbuf,50,0);
        	close(newsock);*/
        }
        close(listen_sock);
        return 0;
    }
    

    实验结果截图:

    对比单线程版本,多线程响应时间比单线程短,速度更快,可以更好的利用CPU。因为单线程必须按顺序一个一个执行,前面线程的没有执行完是无法执行下一个的;而多线程可以分析CPU是否有空余,判断是否可以同时执行多个线程,这样既缩短了时间,又更好的利用了CPU。

    并发程序-3

    要求:交叉编译多线程版本服务器并部署到实验箱中
    PC机作客户端测试wc服务器
    提交测试截图

    前面两个实验完成的很顺利,没想到最后一个出现了问题,就是实验箱和主机ping不通,大概调试了半个多小时也无果,最后不得不抱憾而去。我们也很疑惑,因为第一次实验的时候我们只用了一次就搞定了,完成的非常顺利,这一次就不奏效了,换箱子、换网线都无法得以解决,我们也十分苦恼这件事情。

    实验感想

    本次实验是并发程序,分三个步骤进行,第一个让我们用命令wc查看文件中的单词数,和我们最近正在学习的sockets编程有很多相似的地方,都是客服端与服务器共同进行。第二个是在第一个的基础上实现多进程,前面两个都不算困难,只要代码正确就可以在自己电脑上完成。而第三部分是在实验箱上完成,我们遇到了很大的困难,经过一步一步的排除,仍未完成,实验箱与电脑一直处于ping不通的状态。通过这次实验,我们学会了使用Linux命令wc,在这次实验中遇到的问题,我们也会总结反思,在下次实验中会仔细研究并找到电脑和实验箱不能连接的原因。

  • 相关阅读:
    Anagram
    HDU 1205 吃糖果(鸽巢原理)
    Codeforces 1243D 0-1 MST(补图的连通图数量)
    Codeforces 1243C Tile Painting(素数)
    Codeforces 1243B2 Character Swap (Hard Version)
    Codeforces 1243B1 Character Swap (Easy Version)
    Codeforces 1243A Maximum Square
    Codeforces 1272E Nearest Opposite Parity(BFS)
    Codeforces 1272D Remove One Element
    Codeforces 1272C Yet Another Broken Keyboard
  • 原文地址:https://www.cnblogs.com/20175309lyh/p/11918799.html
Copyright © 2011-2022 走看看