2017-2018-1 20155311 實驗三 實時系統
阿新 • • 發佈:2017-11-19
ets 基於 [] not main ket string accept ase
2017-2018-1 20155311 實驗三 實時系統
實驗內容
任務一
- 學習使用Linux命令wc(1)
- 基於Linux Socket程序設計實現wc(1)服務器(端口號是你學號的後6位155203)和客戶端
- 客戶端傳一個文本文件給服務器
- 服務器返加文本文件中的單詞數
實現mywc
- Linux系統中的wc(Word Count)命令的功能為統計指定文件中的字節數、字數、行數,並將統計結果顯示輸出。
- 命令格式:wc[選項]文件...
- 命令功能:統計指定文件中的字節數、字數、行數,並將統計結果顯示輸出。該命令統計指定文件中的字節數、字數、行數。如果沒有給出文件名,則從標準輸入讀取。wc同時也給出所指定文件的總統計數。
- 命令參數:
- -c 統計字節數。
- -l 統計行數。
- -m 統計字符數。這個標誌不能與-c標誌一起使用。
- -w 統計字數。一個字被定義為由空白、跳格或換行字符分隔的字符串。
- -L 打印最長行的長度。
- -help 顯示幫助信息
- --version顯示版本信息
wc代碼如下
#include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) { char ch; FILE *fp; long count=0; char s[21]; if(argc !=2) { printf("此文件名為:%s\n",argv[0]); exit(EXIT_FAILURE); } if ((fp=fopen(argv[1],"r+"))==NULL) { fprintf(stderr,"這個文件打不開\"%s\"\n",argv[1]); exit(EXIT_FAILURE); } while(fscanf(fp,"%s",s)!=EOF) count++; fclose(fp); printf("File %s has %ld characters\n",argv[1],count); return 0; }
截圖如下
服務器端代碼server.c:
#include<netinet/in.h> // sockaddr_in #include<sys/types.h> // socket #include<sys/socket.h> // socket #include<stdio.h> // printf #include<stdlib.h> // exit #include<string.h> // bzero #define SERVER_PORT 8000 #define LENGTH_OF_LISTEN_QUEUE 20 #define BUFFER_SIZE 1024 #define FILE_NAME_MAX_SIZE 512 int main(void) { // 聲明並初始化一個服務器端的socket地址結構 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htons(INADDR_ANY); server_addr.sin_port = htons(SERVER_PORT); // 創建socket,若成功,返回socket描述符 int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0); if(server_socket_fd < 0) { perror("Create Socket Failed:"); exit(1); } int opt = 1; setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 綁定socket和socket地址結構 if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)))) { perror("Server Bind Failed:"); exit(1); } // socket監聽 if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE))) { perror("Server Listen Failed:"); exit(1); } while(1) { // 定義客戶端的socket地址結構 struct sockaddr_in client_addr; socklen_t client_addr_length = sizeof(client_addr); // 接受連接請求,返回一個新的socket(描述符),這個新socket用於同連接的客戶端通信 // accept函數會把連接到的客戶端信息寫到client_addr中 int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length); if(new_server_socket_fd < 0) { perror("Server Accept Failed:"); break; } // recv函數接收數據到緩沖區buffer中 char buffer[BUFFER_SIZE]; bzero(buffer, BUFFER_SIZE); if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0) { perror("Server Recieve Data Failed:"); break; } // 然後從buffer(緩沖區)拷貝到file_name中 char file_name[FILE_NAME_MAX_SIZE+1]; bzero(file_name, FILE_NAME_MAX_SIZE+1); strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer)); printf("%s\n", file_name); // 打開文件並讀取文件數據 FILE *fp = fopen(file_name, "r"); if(NULL == fp) { printf("File:%s Not Found\n", file_name); } else { bzero(buffer, BUFFER_SIZE); int length = 0; // 每讀取一段數據,便將其發送給客戶端,循環直到文件讀完為止 while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) { if(send(new_server_socket_fd, buffer, length, 0) < 0) { printf("Send File:%s Failed./n", file_name); break; } bzero(buffer, BUFFER_SIZE); } // 關閉文件 fclose(fp); printf("File:%s Transfer Successful!\n", file_name); } // 關閉與客戶端的連接 close(new_server_socket_fd); } // 關閉監聽用的socket close(server_socket_fd); return 0; }
客戶端代碼client.c
#include<netinet/in.h> // sockaddr_in
#include<sys/types.h> // socket
#include<sys/socket.h> // socket
#include<stdio.h> // printf
#include<stdlib.h> // exit
#include<string.h> // bzero
#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main()
{
// 聲明並初始化一個客戶端的socket地址結構
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htons(INADDR_ANY);
client_addr.sin_port = htons(0);
// 創建socket,若成功,返回socket描述符
int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(client_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
}
// 綁定客戶端的socket和客戶端的socket地址結構 非必需
if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
{
perror("Client Bind Failed:");
exit(1);
}
// 聲明一個服務器端的socket地址結構,並用服務器那邊的IP地址及端口對其進行初始化,用於後面的連接
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)
{
perror("Server IP Address Error:");
exit(1);
}
server_addr.sin_port = htons(SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
// 向服務器發起連接,連接成功後client_socket_fd代表了客戶端和服務器的一個socket連接
if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
perror("Can Not Connect To Server IP:");
exit(0);
}
// 輸入文件名 並放到緩沖區buffer中等待發送
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
printf("Please Input File Name On Server:\t");
scanf("%s", file_name);
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
// 向服務器發送buffer中的數據
if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Send File Name Failed:");
exit(1);
}
// 打開文件,準備寫入
FILE *fp = fopen(file_name, "w");
if(NULL == fp)
{
printf("File:\t%s Can Not Open To Write\n", file_name);
exit(1);
}
// 從服務器接收數據到buffer中
// 每接收一段數據,便將其寫入文件中,循環直到文件接收完並寫完為止
bzero(buffer, BUFFER_SIZE);
int length = 0;
while((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
{
if(fwrite(buffer, sizeof(char), length, fp) < length)
{
printf("File:\t%s Write Failed\n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
}
// 接收成功後,關閉文件,關閉socket
printf("Receive File:\t%s From Server IP Successful!\n", file_name);
close(fp);
close(client_socket_fd);
char *argv[]={"wc","-w",file_name,0};
execvp("wc",argv);
return 0;
}
將test1.txt和test2.txt文件復制到server.c文件夾下 先運行server.c再運行client.c運行結果如圖
2017-2018-1 20155311 實驗三 實時系統