2017-2018-1 20155212 实验三 实时系统
1 学习使用Linux命令wc(1)
题目
- 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
- 客户端传一个文本文件给服务器
- 服务器返加文本文件中的单词数
步骤
- 使用
man wc
命令查看wc
- wc命令详解
- 语法:wc [选项] 文件
- 选项含义
- c:统计字节数
- l:统计行数
- w:统计字数
- 使用示例
- 实现难点:
- 如何统计单词数?
- 使用
od -tc
命令查看文本中单词之间如何间隔 - 单词间通过\' \'、\'\\r\'、\'\\n\'间隔开
- 使用
- 统计结果与实际出现较大误差
- 字符间可能有多个间隔符,因此连续的间隔符只能算一个
- 如何统计单词数?
最终代码
-
服务器
/*server*/ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #define MYPORT 155212 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\\n", 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 \'\\n\': wordscount++; break; case \'\\r\': wordscount++; break; default: break; } } if(buffer[i]== \' \' || buffer[i]==\'\\n\' || buffer[i]==\'\\r\') flag=1; else flag=0; } } if(len<1024) break; } send(clientfd, &wordscount, sizeof(long), 0); close(clientfd); } close(serverfd); }
-
客户端
/*client*/ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #define MYPORT 155212 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\\n", wordscount); close(clientfd); }
-
运行结果截图
2 使用多线程实现wc服务器并使用同步互斥机制保证计数正确
分析
- 1中的客户端代码不需要改变,只需要改变服务器代码即可。
- 服务器代码需要增加两个功能
- 增加多线程
- 使用同步互斥
代码
- 服务器
#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 155212
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
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 \'\\n\':
wordscount++;
break;
case \'\\r\':
wordscount++;
break;
default:
break;
}
}
if(buffer[i]== \' \' || buffer[i]==\'\\n\' || buffer[i]==\'\\r\') 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];
int serverfd, clientfd;
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_add#include <pthread.h>r=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\\n", inet_ntoa(remote_addr.sin_addr));
pthread_create(&t, NULL, &wc, NULL);
pthread_join(&t, NULL);
}
close(serverfd);
}
运行结果
实验总结
- 在本次实验中,实验进展比较慢,主要原因在于对socket编程不够熟悉,有一些错误一直没调出来,而且由于比较急,任务二的截图提交错了。在今后的实验中,需要更加提前准备实验,同时在提交截图时需要仔细确认。
- 希望老师能多提前几天将其他实验的任务给我们,以便我们能充分准备好实验