zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155314《信息安全系统设计基础》实验三 并发程序

    2017-2018-1 20155314《信息安全系统设计基础》实验三 并发程序

    并发程序-1

    实验要求

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

    上方提交代码

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

    实验步骤

    • man wc命令学习wc命令的使用
      29cjO.png

    • mywc的编写

      • mywc20155314.c:

        #include <stdio.h>
        #include <stdlib.h>
        int main(int argc, char *argv[]){
            int count=0;
            char s[100];
            FILE *fp;
            if((fp=fopen(argv[1],"r"))==NULL){
                printf("Open the file failure...
        ");
                exit(0);
            }
            while(fscanf(fp,"%s",s)!=EOF)
                count++;
            fclose(fp);
            printf("There is(are) %d word(s) in the text.
        ",count);
            return 0;
        }
        
      • 运行结果:
        2peeJ.png

    本题代码

    • 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  
        
      #define SERVER_PORT 155314  
      #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;  
      } 
      
      
    • 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  
        
      #define SERVER_PORT 155314  
      #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;  
      } 
      
      

    运行结果

    2p5lT.png

    并发程序-2

    实验要求

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

    实验步骤

    • man pthread命令学习pthread相关调用
      294UA.png
      29hEd.png

    本题代码

    • pthread_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  
        
      #define SERVER_PORT 155314  
      #define LENGTH_OF_LISTEN_QUEUE 20  
      #define BUFFER_SIZE 1024
      #define FILE_NAME_MAX_SIZE 512  
      
      pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
      
      void *mywc20155314(void *m) // 统计文件单词个数
      {
      	pthread_mutex_lock(&counter_mutex);
      	// 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);
      
      	sprintf(buffer,"%d",words);
      
      	send(new_server_socket_fd,buffer,BUFFER_SIZE,0);
      	close(new_server_socket_fd);  
      	
      	// 关闭与客户端的连接
      	
      	pthread_mutex_unlock( &counter_mutex );
      	return NULL;   
      
      }
      
      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;  
              }
          	
      		pthread_create(&t, NULL, &wc, NULL);
      		pthread_join(&t, NULL);
              
          }  
          // 关闭监听用的socket  
          close(server_socket_fd);  
          return 0;  
      } 
      
      
    • pthread_client.c同并发程序-1的client.c

    运行结果

    2pAQU.png

    实验中遇到的问题及解决过程

    Ubuntu Linux下exfat挂载问题

    • 问题描述:

      在Ubuntu下,由于版权的原因,默认不支持exFAT格式的U盘:29aB4.png

    • 解决方法:

      sudo apt-get install exfat-utils命令添加对exFAT的支持:
      29dHJ.png
      我的64G exFAT格式的U盘终于能被Ubuntu所读取!
      290E9.png

    参考资料

  • 相关阅读:
    【简●解】[AHOI2009]中国象棋
    【讲●解】KMP算法
    【简●解】POJ 1185,LG P2704【炮兵阵地】
    学习网站整理
    【讲●解】火车进出栈类问题 & 卡特兰数应用
    洛谷4556 [Vani有约会]雨天的尾巴
    BZOJ2212或洛谷3521 [POI2011]ROT-Tree Rotations
    洛谷1119 灾后重建
    洛谷1462(重题1951) 通往奥格瑞玛的道路(收费站_NOI导刊2009提高(2))
    BZOJ2721或洛谷1445 [Violet]樱花
  • 原文地址:https://www.cnblogs.com/crazymosquito/p/7862622.html
Copyright © 2011-2022 走看看