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

Posted nmsl123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-2019-1 《信息安全系统设计基础》实验三:并发程序相关的知识,希望对你有一定的参考价值。

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


任务一
  • 要求:

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

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

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

  • wc命令参数:
-c:统计字节数
-l:统计行数
-m:统计字符数。这个标志不能与 -c 标志一起使用。
-w:统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串
-L:打印最长行的长度
-help:显示帮助信息
--version:显示版本信息
  • 技术分享图片

    网上找的代码:
  • 这是之前做简单对话时找的代码

server:

#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 8000 
#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, "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; 
}

client:

#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 8000 
#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); 
  } 
   
  // 打开文件,准备写入 
  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); 
  close(fp); 
  close(client_socket_fd); 
  return 0; 
}
  • 根据要求改成了读取文件:
 printf("%s
", file_name);  


    FILE *fp = fopen(file_name, "w");  
  • 以及读取字数:
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);
修改后实验代码:

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 155323 
#define LENGTH_OF_LISTEN_QUEUE 20  
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512  
#define BEGIN 1; 

int main(void)  
{  

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);  

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));  

if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))  
{  
    perror("Server Bind Failed:");  
    exit(1);  
}  
    
if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))  
{  
    perror("Server Listen Failed:");  
    exit(1);  
}  

while(1)  
{  
    struct sockaddr_in client_addr;  
    socklen_t client_addr_length = sizeof(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;  
    }  


    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;  
    }  


    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(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);  
    }  

    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);

char sendbuf[50];
sprintf(sendbuf,"%d",words);

send(new_server_socket_fd,sendbuf,50,0);

    close(new_server_socket_fd);  
}  

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 155323  
#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;  
}
  • 结果截图:

  • 技术分享图片

思考题
  • 对比单线程的版本的性能,并分析原因。

原因:

  • 多线程技术使程序的响应速度更快,因为用户界面可以在进行其它工作的同时一直处于活动状态;

  • 当前没有进行处理的任务时可以将处理器时间让给其它任务;

  • 占用大量处理时间的任务可以定期将处理器时间让给其它任务;

  • 可以随时停止任务;

  • 可以分别设置各个任务的优先级以优化性能。

  • 是否需要创建多个线程取决于各种因素。在以下情况下,最适合采用多线程处理:
  • 耗时或大量占用处理器的任务阻塞用户界面操作;

  • 各个任务必须等待外部资源 (如远程文件或 Internet连接)。

以上是关于2018-2019-1 《信息安全系统设计基础》实验三:并发程序的主要内容,如果未能解决你的问题,请参考以下文章

2018-2019-1 20165236 《信息安全系统设计基础》第4周学习总结

2018-2019-1 20165312 《信息安全系统设计基础》第一周学习总结

2018-2019-1 20165316 《信息安全系统设计基础》第1周学习总结

2018-2019-1 20165236 《信息安全系统设计基础》第七周学习总结

2018-2019-1 20165226 《信息安全系统设计基础》第8周学习总结

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