2018-2019-1 20165303 實驗三 實時系統
實驗三-並發程序-1
- 學習使用Linux命令wc(1)
基於Linux Socket程序設計實現wc(1)服務器(端口號是你學號的後6位)和客戶端
客戶端傳一個文本文件給服務器
服務器返加文本文件中的單詞數
上方提交代碼
附件提交測試截圖,至少要測試附件中的兩個文件
命令參數:
-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; /
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;
}
′′′
實驗三-並發程序-2
使用多線程實現wc服務器並使用同步互斥機制保證計數正確
上方提交代碼
下方提交測試
對比單線程版本的性能,並分析原因
server
′′′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!\n");
exit(1);
}
fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
if(fd_temp == -1)
{
fprintf(stderr,"listen error!\n");
exit(1);
}
while(1)
{
printf("waiting for new connection...\n");
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!\n");
continue; //ignore current socket ,continue while loop.
}
printf("A new connection occurs!\n");
if(pthread_create(&thread_id,NULL,(void )(&Data_handle),(void )(&sockfd)) == -1)
{
fprintf(stderr,"pthread_create error!\n");
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\n");
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!\n";
while(1)
{
printf("waiting for file_name...\n");
//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\n");
break;
}
if(i_recvBytes == -1)
{
fprintf(stderr,"read error!\n");
break;
}
if(strcmp(data_recv,"quit")==0)
{
printf("Quit command!\n");
break; //Break the while loop.
}
printf("read from client : %s\n",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...\n");
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)!=‘\0‘))
{
i++;
}
}}
//printf("%d\t",nWords);return nWords;
}
′′′client
′′′include<stdlib.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
int main()
{
int sockfd;
int tempfd;
struct sockaddr_in s_addr_in;
char data_send[BUFFER_LENGTH];
char data_recv[BUFFER_LENGTH];
memset(data_send,0,BUFFER_LENGTH);
memset(data_recv,0,BUFFER_LENGTH);
sockfd = socket(AF_INET,SOCK_STREAM,0); //ipv4,TCP
if(sockfd == -1)
{
fprintf(stderr,"socket error!\n");
exit(1);
}
//before func connect, set the attr of structure sockaddr.
memset(&s_addr_in,0,sizeof(s_addr_in));
s_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1"); //trans char * to in_addr_t
s_addr_in.sin_family = AF_INET;
s_addr_in.sin_port = htons(SOCK_PORT);
tempfd = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
if(tempfd == -1)
{
fprintf(stderr,"Connect error! \n");
exit(1);
}
while(1)
{
printf("Please Input File Name On Server(input "quit" to quit):\t");
scanf("%s", data_send);
//gets(data_send);
//scanf("%[^\n]",data_send); //or you can also use this
tempfd = write(sockfd,data_send,BUFFER_LENGTH);
if(tempfd == -1)
{
fprintf(stderr,"write error\n");
exit(0);
}
char buffer[BUFFER_LENGTH];if(strcmp(data_send,"quit") == 0) //quit,write the quit request and shutdown client { break; } else { tempfd = read(sockfd,data_recv,BUFFER_LENGTH); assert(tempfd != -1); printf("%s\n",data_recv); memset(data_send,0,BUFFER_LENGTH); memset(data_recv,0,BUFFER_LENGTH); }
int length=0;
bzero(buffer, BUFFER_LENGTH);
length = recv(sockfd, buffer, BUFFER_LENGTH, 0);
buffer[length] = ‘\0‘;
printf("count=%s\n", buffer);
bzero(buffer, BUFFER_LENGTH);
}
int ret = shutdown(sockfd,SHUT_WR); //or you can use func close()--<unistd.h> to close the fd
assert(ret != -1);
return 0;
}
′′′
多線程(英語:multithreading),是指從軟件或者硬件上實現多個線程並發執行的技術。具有多線程能力的計算機因有硬件支持而能夠在同一時間執行多於一個線程,進而提升整體處理性能。
2018-2019-1 20165303 實驗三 實時系統