2017-2018-1 20155306 实验三 实时系统
2017-2018-1 20155306 实验三 实时系统
实验内容:
任务一
学习使用Linux命令wc(1)
基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
客户端传一个文本文件给服务器
服务器返加文本文件中的单词数
上方提交代码
附件提交测试截图,至少要测试附件中的两个文件
通过man命令得知:
- 命令格式:
wc [选项]文件... - 命令功能:
统计指定文件中的字节数、字数、行数,并将统计结果显示输出。该命令统计指定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所指定文件的总统计数。 - 命令参数:
-c 统计字节数。
-l 统计行数。
-m 统计字符数。这个标志不能与 -c 标志一起使用。
-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L 打印最长行的长度。
-help 显示帮助信息
--version 显示版本信息
SERVER :
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 155306
#define BACKLOG 1
#define MAXRECVLEN 1024
int main(int argc, char *argv[])
{
char buf[MAXRECVLEN];
int listenfd, connectfd; /* socket descriptors */
struct sockaddr_in server; /* server's address information */
struct sockaddr_in client; /* client's address information */
socklen_t addrlen;
/* Create TCP socket */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* handle exception */
perror("socket() error. Failed to initiate a socket");
exit(1);
}
/* set socket option */
int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
/* handle exception */
perror("Bind() error.");
exit(1);
}
if(listen(listenfd, BACKLOG) == -1)
{
perror("listen() error. \n");
exit(1);
}
addrlen = sizeof(client);
while(1){
if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1)
{
perror("accept() error. \n");
exit(1);
}
FILE *stream;
struct timeval tv;
gettimeofday(&tv, NULL);
printf(" Client ip : %s \n",inet_ntoa(client.sin_addr));
printf(" Port id : %d \n ",htons(client.sin_port));
printf("Time is %ld.%ld\n",tv.tv_sec,tv.tv_usec);
int iret=-1;
char d[1024];
iret = recv(connectfd, buf, MAXRECVLEN, 0);
if(iret>0)
{
strcpy(d,buf);
stream = fopen(buf,"r");
bzero(buf, sizeof(buf));
//strcat(buf,"Word number:");
strcat(buf,"Word number:");
char s[21];
long int count = 0;
while(fscanf(stream,"%s",s)!=EOF)
count++;
char str[10];
sprintf(str, " %ld\n", count);
int n = sizeof(str);
str[n] = '\0';
strcat(buf,"\n");
//strcat(buf,"\t");strcat(buf,str);
printf("\n");
strcat(buf,"\n");
}else
{
close(connectfd);
break;
}
/* print client's ip and port */
send(connectfd, buf, iret, 0); /* send to the client welcome message */
}
close(listenfd); /* close listenfd */
return 0;
}
CLIENT:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /* netdb is necessary for struct hostent */
#define PORT 155306 /* server port */
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int sockfd, num; /* files descriptors */
char buf[MAXDATASIZE]; /* buf will store received text */
struct hostent *he; /* structure that will get information about remote host */
struct sockaddr_in server;
if (argc != 3)
{
printf("Usage: %s <IP Address><Filename>\n",argv[0]);
exit(1);
}
if((he=gethostbyname(argv[1]))==NULL)
{
printf("gethostbyname() error\n");
exit(1);
}
if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1)
{
printf("socket() error\n");
exit(1);
}
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *((struct in_addr *)he->h_addr);
if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1)
{
printf("connect() error\n");
exit(1);
}
char str[MAXDATASIZE] ;
strcpy(str,argv[2]);
if((num=send(sockfd,str,sizeof(str),0))==-1){
printf("send() error\n");
exit(1);
}
if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
{
printf("recv() error\n");
exit(1);
}
buf[num-1]='\0';
printf(" Successful! \n %s\n",buf);
close(sockfd);
return 0;
}
运行截图如下:
任务二
使用多线程实现wc服务器并使用同步互斥机制保证计数正确
上方提交代码
下方提交测试
对比单线程版本的性能,并分析原因
进程同步
进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。
比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图1所示。
进程互斥
进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图2所示。
运行截图如下: