2019-2020-1 20175209王梓鸿 实验三 并发程序
Posted wangzihong0213
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019-2020-1 20175209王梓鸿 实验三 并发程序相关的知识,希望对你有一定的参考价值。
实验三 并发程序
实验三-并发程序-1
实验内容:
1.学习使用Linux命令wc(1)。
2.基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端。
客户端传一个文本文件给服务器。
服务器返加文本文件中的单词数。
实验步骤:
学习使用Linux命令wc
首先,我们使用man -k wc查看wc命令的系统调用:
接下来用man 1 wc 查看wc指令:
wc指令功能:统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
wc指令格式:wc [选项] 文件...
wc指令描述:其中word字长是由空格分隔的非零长度序列。
- wc命令参数:
-c 统计字节数。
-l 统计行数。
-m 统计字符数。这个标志不能与 -c 标志一起使用。
-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L 打印最长行的长度。
可以使用
wc -w
命令统计字数,但是字的定义是“空白、跳格或换行字符分隔的字符串”,和单词数不完全相同
。
服务器端与客户端实现代码
- 服务器端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define MYPORT 175209
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("accept client %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);
}
- 客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define MYPORT 175209
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];
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);
}
- 运行结果:
实验三-并发程序-2
实验内容:
使用多线程实现wc服务器并使用同步互斥机制保证计数正确。
对比单线程版本的性能,并分析原因。
实验步骤:
在开始前,需要了解一下同步和互斥的区别:
1.互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
2.同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
3.同步其实已经实现了互斥,所以同步是一种更为复杂的互斥。
4.互斥是一种特殊的同步。
所以服务器代码需要增加两个功能:
增加多线程。
使用同步互斥。
服务器端与客户端实现代码
- 服务器端
#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 175209
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("accept client %s
", inet_ntoa(remote_addr.sin_addr));
pthread_create(&t, NULL, &wc, NULL);
pthread_join(&t, NULL);
}
close(serverfd);
}
- 客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define MYPORT 175209
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];
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);
}
- 运行结果
需要注意的是:
因为pthread
库不是Linux系统默认的库,连接时需要使用库libpthread.a
,所以在使用pthread_create
创建线程时,在编译中要加-lpthread
参数:gcc server.c -lpthread -o server
加上这个以后编译成功!单线程与多线程的区别:
单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)。
多线程程序:有多个线程,线程间独立运行,能有效地避免代码阻塞,并且提高程序的运行性能。
单线程与多线程的优缺点分析:
多线程优缺点:同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。
单线程优缺点:单线程的也就是程序执行时,所跑的程序路径(处理的东西)是连续顺序下来的,必须前面的处理好,后面的才会执行到。
实验三-并发程序-3
实验内容:
交叉编译多线程版本服务器并部署到实验箱中。
PC机作客户端测试wc服务器。
提交测试截图。
实验步骤:
- 运行截图
学习到的知识点:
- 了解了多线程的优点:多线程技术使程序的响应速度更快 ,因为用户界面可以在进行其它工作的同时一直处于活动状态。有多个线程,线程间独立运行,能有效地避免代码阻塞,并且提高程序的运行性能。
以上是关于2019-2020-1 20175209王梓鸿 实验三 并发程序的主要内容,如果未能解决你的问题,请参考以下文章
2019-2020-1 20175209 《信息安全系统设计基础》第三周学习总结
20175209 《MySort》和《IO-myhead》选做
20175209 实验二《Java面向对象程序设计》实验报告
2019-2020-2 网络对抗技术 20175209 Exp7 网络欺诈防范