2019-2020-1 20175204 20175202 20175216 《信息安全系统设计基础》实验三 并发程序

2019-2020-1 20175204 20175202 20175216 《信息安全系统设计基础》实验三 并发程序

组员 20175204 张湲祯 20175202 葛旭阳 20175216 张雪原

任务一【并发程序-1】

一、实验任务:
1.学习使用Linux命令wc(1)
2.基于Linux套接字程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
3.客户端传一个文本文件给服务器
4.服务器返回加文本文件中的单词数个以上

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

二、实验步骤:
1.学习使用man wc命令;

wc指令功能:统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
wc指令格式:wc [选项] 文件...
wc指令描述:其中word字长是由空格分隔的非零长度序列。
wc命令参数:
-c 统计字节数。
-l 统计行数。
-m 统计字符数。这个标志不能与 -c 标志一起使用。(字的定义是“空白、跳格或换行字符分隔的字符串”,和单词数不完全相同)
-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L 打印最长行的长度。
2.wc命令的使用:

3.服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define MYPORT 175204

void main(){
   int serverfd, clientfd;
   struct sockaddr_in my_addr;
   struct sockaddr_in remote_addr;

   char buffer[BUFSIZ];
   memset(&my_addr, 0, sizeof(my_addr));
   my_addr.sin_family=AF_INET;
   my_addr.sin_addr.s_addr=INADDR_ANY;
   my_addr.sin_port=htons(MYPORT);

   if((serverfd=socket(PF_INET, SOCK_STREAM, 0))==-1){
       perror("socket");
   }
   
   if(bind(serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))<0){
       perror("bind");
   }
   listen(serverfd, 5);
   int addrlen=sizeof(struct sockaddr_in);
   while(1){
       if((clientfd=accept(serverfd, (struct sockaddr *)&remote_addr, &addrlen))<0){
           perror("accept");
   }
   printf("接收到客户端 %s
", inet_ntoa(remote_addr.sin_addr));
   int len, i;
   long wordscount=0;
   int flag=1;
   while(1){
       if((len=recv(clientfd, buffer, 1024, 0))>0){
           for(i=0; i<len; i++){
               if(flag==0){
                   switch(buffer[i]){
                       case ' ':
                           wordscount++;
                           break;
                       case '
':
                           wordscount++;
                           break;
                       case '
':
                           wordscount++;
                           break;
                       default:
                           break;
                   }
               }
           if(buffer[i]== ' ' || buffer[i]=='
' || buffer[i]=='
') flag=1;
           else flag=0;
           }
       }
       if(len<1024) break;
   }
   send(clientfd, &wordscount, sizeof(long), 0);
   close(clientfd);
   }
   close(serverfd);

4.客户端代码:

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <string.h>

#define MYPORT 175204

void main(){
   int clientfd;
   struct sockaddr_in remote_addr;
   char buffer[BUFSIZ];
   memset(&remote_addr, 0 , sizeof(remote_addr));
   remote_addr.sin_family=AF_INET;
   remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
   remote_addr.sin_port=htons(MYPORT);

   if((clientfd=socket(PF_INET,SOCK_STREAM,0))<0){  
       perror("socket");  
   }

   if(connect(clientfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr))<0){
       perror("connect");
   }

   int len;
   FILE *fp;
   char path[20];
printf("请输入需要测试的文件名");
   gets(path);

   fp=fopen(path, "r");
   char readch;
   int i=0;
   while((readch=fgetc(fp))!=EOF){
       if(i<1024){
           buffer[i]=readch;
           i++;
       }
       else{
           i=0;
           int n=send(clientfd, buffer, 1024, 0);
       }
   }
   fclose(fp);
   if(i!=0)
       send(clientfd, buffer, i, 0);
   long wordscount;
   recv(clientfd, &wordscount, sizeof(long), 0);
   printf("%ld
", wordscount);
   close(clientfd);
}

5.分别打开两个终端,对服务器代码sever.c和客户端代码client.c分别编译;后在两个终端分别运行;先运行服务器在运行客户端,后根据要求输入需要测试的文件名,进行测试。

任务二 【并发程序-2】

一、实验任务:
1.使用多线程实现wc服务器并使用同步互斥机制保证计数正确
2.上方提交代码
3.下方提交测试
4.对比单线程版本的性能,并分析原因
二、实验步骤:
1.重新编写并编译运行服务器代码;
2.服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>

#define MYPORT 175204
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
int serverfd, clientfd;
char buffer[BUFSIZ];

void *wc(void *m){
   pthread_mutex_lock( &counter_mutex );
   int len, i;
   long wordscount=0;
   int flag=1;
   while(1){
       if((len=recv(clientfd, buffer, 1024, 0))>0){
           for(i=0; i<len; i++){
               if(flag==0){
                   switch(buffer[i]){
                       case ' ':
                           wordscount++;
                           break;
                       case '
':
                           wordscount++;
                           break;
                       case '
':
                           wordscount++;
                           break;
                       default:
                           break;
                   }
               }
               if(buffer[i]== ' ' || buffer[i]=='
' || buffer[i]=='
')
                   flag=1;
               else
                   flag=0;
           }
       }
       if(len<1024)
           break;
   }
   send(clientfd, &wordscount, sizeof(long), 0);
   close(clientfd);
   pthread_mutex_unlock( &counter_mutex );
   return NULL;
}
void main(){
   pthread_t t;
   char arg[30];

   struct sockaddr_in my_addr;
   struct sockaddr_in remote_addr;

   memset(&my_addr, 0, sizeof(my_addr));
   my_addr.sin_family=AF_INET;
   my_addr.sin_addr.s_addr=INADDR_ANY;
   my_addr.sin_port=htons(MYPORT);

   if((serverfd=socket(PF_INET, SOCK_STREAM, 0))==-1){
       perror("socket");
   }

   if(bind(serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))<0){
       perror("bind");
   }
   listen(serverfd, 5);
   int addrlen=sizeof(struct sockaddr_in);
   while(1){
       if((clientfd=accept(serverfd, (struct sockaddr *)&remote_addr, &addrlen))<0){
           perror("accept");
       }
       printf("接收到客户端 %s
", inet_ntoa(remote_addr.sin_addr));
       pthread_create(&t, NULL, &wc, NULL);
       pthread_join(&t, NULL);
   }
   close(serverfd);
}

3.客户端代码:

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <string.h>

#define MYPORT 175204

void main(){
   int clientfd;
   struct sockaddr_in remote_addr;
   char buffer[BUFSIZ];
   memset(&remote_addr, 0 , sizeof(remote_addr));
   remote_addr.sin_family=AF_INET;
   remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
   remote_addr.sin_port=htons(MYPORT);

   if((clientfd=socket(PF_INET,SOCK_STREAM,0))<0){  
       perror("socket");  
   }

   if(connect(clientfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr))<0){
       perror("connect");
   }

   int len;
   FILE *fp;
   char path[20];
printf("请输入需要测试的文件名:");
   gets(path);
   fp=fopen(path, "r");
   char readch;
   int i=0;
   while((readch=fgetc(fp))!=EOF){
       if(i<1024){
           buffer[i]=readch;
           i++;
       }
       else{
           i=0;
           int n=send(clientfd, buffer, 1024, 0);
       }
   }
   fclose(fp);
   if(i!=0)
       send(clientfd, buffer, i, 0);
   long wordscount;
   recv(clientfd, &wordscount, sizeof(long), 0);
   printf("%ld
", wordscount);
   close(clientfd);
}

4.分别打开多个终端,一个终端运行服务器,其余终端运行客户端;
运行多个客户端后,服务端会收到多个请求。


5.对比单线程的版本的性能,并分析原因。
单线程容易实现,但是一次只允许一个客户端连接。
多线程更复杂,但是一次允许多个客户端,工作效率更高。
单线程保证单用户的安全性,但多线程保证任务的高效性。

任务三 【并发程序-3】

一、实验任务:
1.交叉编译多线程版本服务器并部署到实验箱中
2.PC机作客户端测试wc服务器
3.提交测试截图

二、实验步骤:
1.参考实验1在Ubuntu中对服务器代码交叉编译。
2.将实验箱与电脑连接好,配置好网络模式并能ping通;
3.打开虚拟机命令行终端,配置/etc/exports;
sudo vim /etc/exports
NFS允许挂载的目录及权限在文件/etc/exports中进行了定义。需要把/home/linux/175204zyz/sy3目录共享出来,那么我们只需要在/etc/exports文件末添加如下一行:
/home/linux/175204zyz/sy3 *(rw,sync,no_root_squash,no_subtree_check)
保存并推出,随后重启服务:
sudo /etc/init.d/nfs-kernel-server restart
4.在超级终端中mount -t nfs -o nolock 192.168.0.230(宿主机IP):/home/linux/175204zyz/sy3
5.然后运行程序。

实验总结

本次实验我们小组首先遇到了很多问题:
问题1:在任务二中编译服务器代码时出现致命错误。

解决方案:通过参考对pthread_create未定义的引用,因为pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时,命令使用gcc server.c -lpthread -o createThread.
问题2:运行多线程时,打开多个客户端输入直接卡死。
解决方案:由于在分配给Ubuntu虚拟机时只分配一个单核处理器,改为多个处理器多核就可以正常运行。

在本次实验中也回顾了第一次实验对实验箱的运用操作,还对socket编程有了进一步的理解与学习,对单线程和多线程运行有了更直观的认识与了解,感觉自己还需要努力学习。

原文地址:https://www.cnblogs.com/zyzgl/p/11882321.html