2017-2018-1 20155212 实验三 实时系统

2017-2018-1 20155212 实验三 实时系统

1 学习使用Linux命令wc(1)

题目

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

步骤

  • 使用man wc命令查看wc
  • wc命令详解
    • 语法:wc [选项] 文件
    • 选项含义
      • c:统计字节数
      • l:统计行数
      • w:统计字数
  • 使用示例
  • 实现难点:
    • 如何统计单词数?
      • 使用od -tc命令查看文本中单词之间如何间隔
      • 单词间通过' '、' '、' '间隔开
    • 统计结果与实际出现较大误差
      • 字符间可能有多个间隔符,因此连续的间隔符只能算一个

最终代码

  • 服务器

    /*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
    ", 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);
    }
    
  • 客户端

    /*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
    ", 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 '
':
							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];
	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
", inet_ntoa(remote_addr.sin_addr));
		pthread_create(&t, NULL, &wc, NULL);
		pthread_join(&t, NULL);
	}
	close(serverfd);
}

运行结果

实验总结

  • 在本次实验中,实验进展比较慢,主要原因在于对socket编程不够熟悉,有一些错误一直没调出来,而且由于比较急,任务二的截图提交错了。在今后的实验中,需要更加提前准备实验,同时在提交截图时需要仔细确认。
  • 希望老师能多提前几天将其他实验的任务给我们,以便我们能充分准备好实验
原文地址:https://www.cnblogs.com/dky20155212/p/7859380.html