实验三
并发程序-1
-
实验目标
- 学习使用Linux命令wc(1)
- 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
- 客户端传一个文本文件给服务器
- 服务器返加文本文件中的单词数
-
运行截图:
-
参考代码:
客户端:
#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>
#define PORT 165320
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int sockfd, num;
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in server;
if (argc != 3)
{
printf("Usage: %s <IP Address><Filename>
",argv[0]);
exit(1);
}
if((he=gethostbyname(argv[1]))==NULL)
{
printf("gethostbyname() error
");
exit(1);
}
if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1)
{
printf("socket() error
");
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
");
exit(1);
}
char str[MAXDATASIZE] ;
strcpy(str,argv[2]);
if((num=send(sockfd,str,sizeof(str),0))==-1){
printf("send() error
");
exit(1);
}
if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
{
printf("recv() error
");
exit(1);
}
buf[num-1]=' ';
printf("server message: %s
",buf);
close(sockfd);
return 0;
}
服务器:
#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 165320
#define BACKLOG 1
#define MAXRECVLEN 1024
int main(int argc, char *argv[])
{
char buf[MAXRECVLEN];
int listenfd, connectfd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addrlen;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket() error. Failed to initiate a socket");
exit(1);
}
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)
{
perror("Bind() error.");
exit(1);
}
if(listen(listenfd, BACKLOG) == -1)
{
perror("listen() error.
");
exit(1);
}
addrlen = sizeof(client);
while(1){
if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1)
{
perror("accept() error.
");
exit(1);
}
FILE *stream;
struct timeval tv;
gettimeofday(&tv, NULL);
printf("You got a connection from client's ip %s, port %d at time %ld.%ld
",inet_ntoa(client.sin_addr),htons(client.sin_port), 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,"单词数:");
char s[21];
long int count = 0;
while(fscanf(stream,"%s",s)!=EOF)
count++;
char str[10];
sprintf(str, "%ld", count);
int n = sizeof(str);
str[n] = ' ';
strcat(buf,"
");
strcat(buf,str);
strcat(buf,"(");
strcat(buf,d);
strcat(buf,"单词数)");strcat(buf,"
");
}else
{
close(connectfd);
break;
}
send(connectfd, buf, iret, 0);
}
close(listenfd);
return 0;
}
并发程序-2
-
实验目标
-
使用多线程实现wc服务器并使用同步互斥机制保证计数正确
-
上方提交代码
-
下方提交测试
-
对比单线程版本的性能,并分析原因
-
运行截图:
-
参考代码:
-
服务器:
#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<sys/types.h> //pthread_t , pthread_attr_t and so on.
#include<stdio.h>
#include<netinet/in.h> //structure sockaddr_in
#include<arpa/inet.h> //Func : htonl; htons; ntohl; ntohs
#include<assert.h> //Func :assert
#include<string.h> //Func :memset bzero
#include<unistd.h> //Func :close,write,read
#define SOCK_PORT 9988
#define BUFFER_LENGTH 1024
#define MAX_CONN_LIMIT 512 //MAX connection limit
static void Data_handle(void * sock_fd); //Only can be seen in the file
int CountWordsOfEuropeanTxtFile(char *szFileName);
int CountWordsInOneLine(const char *szLine);
int main()
{
int sockfd_server;
int sockfd;
int fd_temp;
struct sockaddr_in s_addr_in;
struct sockaddr_in s_addr_client;
int client_length;
sockfd_server = socket(AF_INET,SOCK_STREAM,0); //ipv4,TCP
assert(sockfd_server != -1);
//before bind(), set the attr of structure sockaddr.
memset(&s_addr_in,0,sizeof(s_addr_in));
s_addr_in.sin_family = AF_INET;
s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); //trans addr from uint32_t host byte order to network byte order.
s_addr_in.sin_port = htons(SOCK_PORT); //trans port from uint16_t host byte order to network byte order.
fd_temp = bind(sockfd_server,(const struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
if(fd_temp == -1)
{
fprintf(stderr,"bind error!
");
exit(1);
}
fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
if(fd_temp == -1)
{
fprintf(stderr,"listen error!
");
exit(1);
}
while(1)
{
printf("waiting for new connection...
");
pthread_t thread_id;
client_length = sizeof(s_addr_client);
//Block here. Until server accpets a new connection.
sockfd = accept(sockfd_server,(struct sockaddr * restrict)(&s_addr_client),(socklen_t *)(&client_length));
if(sockfd == -1)
{
fprintf(stderr,"Accept error!
");
continue; //ignore current socket ,continue while loop.
}
printf("A new connection occurs!
");
if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
{
fprintf(stderr,"pthread_create error!
");
break; //break while loop
}
}
//Clear
int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection.
assert(ret != -1);
printf("Server shuts down
");
return 0;
}
static void Data_handle(void * sock_fd)
{
int fd = *((int *)sock_fd);
int i_recvBytes;
char data_recv[BUFFER_LENGTH];
const char * data_send = "Server has received your request!
";
while(1)
{
printf("waiting for file_name...
");
//Reset data.
memset(data_recv,0,BUFFER_LENGTH);
i_recvBytes = read(fd,data_recv,BUFFER_LENGTH);
if(i_recvBytes == 0)
{
printf("Maybe the client has closed
");
break;
}
if(i_recvBytes == -1)
{
fprintf(stderr,"read error!
");
break;
}
if(strcmp(data_recv,"quit")==0)
{
printf("Quit command!
");
break; //Break the while loop.
}
printf("read from client : %s
",data_recv);
char buffer[BUFFER_LENGTH];
int count=0;
bzero(buffer, BUFFER_LENGTH);
count = CountWordsOfEuropeanTxtFile(data_recv);
sprintf(buffer,"%d", count);
send(fd, buffer, sizeof(buffer), 0);
if(write(fd,data_send,strlen(data_send)) == -1)
{
break;
}
}
//Clear
printf("terminating current client_connection...
");
close(fd); //close a file descriptor.
pthread_exit(NULL); //terminate calling thread!
}
int CountWordsOfEuropeanTxtFile(char *szFileName)
{
int nWords = 0;//词计数变量,初始值为0
FILE *fp; //文件指针
char carrBuffer[1024];//每行字符缓冲,每行最多1024个字符
//打开文件
if ((fp = fopen(szFileName, "r")) == NULL)
{
return -1; //文件打开不成功是返回-1
}
while (!feof(fp))//如果没有读到文件末尾
{
//从文件中读一行
if (fgets(carrBuffer, sizeof(carrBuffer),fp) != NULL)
//统计每行词数
nWords += CountWordsInOneLine(carrBuffer);
}
//关闭文件
fclose(fp);
return nWords;
}
int CountWordsInOneLine(const char *szLine)
{
int nWords = 0;
int i=0;
for (;i<strlen(szLine);i++)
{
if (*(szLine+i)!=' ')
{
nWords++;
while ((*(szLine+i)!=' ')&&(*(szLine+i)!=' '))
{
i++;
}
}
}
//printf("%d ",nWords);
return nWords;
}
实验体会:
- 课上时间能力不足,没能完成实验,课下参考了同学们的代码,自己还有很多不足。