2018-2019-1 20165318 實驗三 實時系統
阿新 • • 發佈:2018-11-19
2018-2019-1 20165318 實驗三 實時系統
任務一
實驗要求
- 學習使用Linux命令wc(1)
- 基於Linux Socket程式設計實現wc(1)伺服器(埠號是你學號的後6位)和客戶端
- 客戶端傳一個文字檔案給伺服器
- 伺服器返加文字檔案中的單詞數
實驗步驟
- 實現wc功能
- 實現客戶端給伺服器傳檔案功能
在客戶端呼叫wc函式統計傳過來的檔案的單詞個數
實現wc功能:使用「man 1 wc」檢視wc命令的manpages
- wc指令功能:統計指定檔案中的位元組數、字數、行數,並將統計結果顯示輸出。
- wc指令格式:wc [選項] 檔案...
- wc指令描述:其中word字長是由空格分隔的非零長度序列。
- wc命令引數:
- -c 統計位元組數。
- -l 統計行數。
- -m 統計字元數。這個標誌不能與 -c 標誌一起使用。
- -w 統計字數。一個字被定義為由空白、跳格或換行字元分隔的字串。
- -L 列印最長行的長度。
可以使用wc -w
命令統計字數,但是字的定義是“空白、跳格或換行字元分隔的字串”,和單詞數不完全相同。
程式碼實現
- 伺服器
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #define MYPORT 165318 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); }
- 客戶端
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #define MYPORT 165318 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); }
實驗截圖
任務二
實驗要求
- 使用多執行緒實現wc伺服器並使用同步互斥機制保證計數正確
實驗步驟
- 任務一中的客戶端程式碼不需要改變,只需要改變伺服器程式碼即可。
- 伺服器程式碼需要增加兩個功能
- 增加多執行緒
- 使用同步互斥
程式碼實現
- 伺服器端
#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 165318
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
int serverfd, clientfd;
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];
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_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));
pthread_create(&t, NULL, &wc, NULL);
pthread_join(&t, NULL);
}
close(serverfd);
}
- 客戶端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define MYPORT 165318
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);
}
實驗截圖
實驗遇到的問題及解決方法
問題:在進行任務二時,在伺服器程式碼的標頭檔案中有
<pthread.h>
,可是編譯的時候卻報錯“對pthread_create未定義的引用“。解決方法:通過參考對pthread_create未定義的引用,因為pthread庫不是Linux系統預設的庫,連線時需要使用庫libpthread.a,所以在使用
pthread_create
建立執行緒時,在編譯中要加-lpthread
引數:gcc createThread.c -lpthread -o createThread
. 加上這個以後編譯成功!