Xây dựng kịch bản giao tiếp giữa hai tiến trìnhQuá trình giao tiếp đợc mô tả bằng sơ đồ sau Để xây dựng kịch bản trên ta có thể định nghĩa một số biến sau trên vùng nhớ chung: request :
Trang 1Bài tập lớn môn Hệ điều hành Linux
Sinh viên thực hiện:
Lớp:
I Đề tài
Xây dựng 2 chơng trình, một chơng trình đóng vai trò là Server chơng trình còn lại là Client Chơng trình Client sẽ gửi tên file đến cho Server và yêu cầu Server gửi cho nội dung của file đó.
II Phơng án giải quyết
Xem xét các cơ chế giao tiếp nh Pipe, Queue đều là những giao tiếp tuần tự,
do đó để xây dựng một giao thức cho hai tiến trình có thể giao tiếp truyền thông với nhau là khá phức tạp Nếu sử dụng cơ chế giao tiếp bằng vùng nhớ chung thì việc tạo một giao thức cho hai tiến trình đơn giản hơn bằng cách khai báo các cờ trạng thái của hai tiến trình trên vùng nhớ chung Khi giao tiếp với nhau hai tiến trình chỉ cần kiểm tra các biến trạng thái tơng ứng thì
sẽ biết đợc tiến trình kia phản hồi lại nh thế nào Tuy việc xây dựng giao thức
là dễ dàng hơn so với các cơ chế giao tiếp nh Pipe, Queue nhng để quá trình giao tiếp diễn ra một cách đúng đắn và không mất dữ liệu thì phải cần đến cơ chế đồng bộ hai tiến trinh khi truy nhập vào vùng nhớ chung để kiểm tra trạng thái hay lấy dữ liệu từ tiến trình còn lại.
Trang 2III Xây dựng kịch bản giao tiếp giữa hai tiến trình
Quá trình giao tiếp đợc mô tả bằng sơ đồ sau
Để xây dựng kịch bản trên ta có thể định nghĩa một số biến sau trên vùng
nhớ chung:
request : là cờ báo yêu cầu của Client
confirm : là cờ báo chấp nhận yêu cầu của Server
filenam : là tên file Client cần truyền
Đợi
Tìm file Chấp nhận yêu cầu
Kiểm tra trạng thái của Server Kiểm tra yêu cầu
Nếu có file thì trả lời sẵn sàng
Kết thúc
Nếu không có Kiểm tra Client sẵn sàng
Gửi dữ liệu
Yêu cầu truyền file
Nhận dữ liệu và báo đã nhận
Gửi tên file
Trả lời có (hay không có) file đó
Kiểm tra trạng thái của Server
Hết dữ liệu
*
*
*
* Gửi dữ liệu
Nhận dữ liệu và báo đã nhận
Kết thúc
Trang 3have_file : là cờ báo của Server là có file Client yêu cầu (1: có;0: không có ) realy : là cờ báo sẵn sàng của Client
have_data : là cờ báo có dữ liệu của Server
count : là kích thớc gói dữ liệu Server gửi cho Client
message : thông báo kèm theo các cờ
data : dữ liệu
Ngoài ra còn có các biến sau nh:
hand_file : thẻ file đợc mở để ghi hay đọc
sem_set_id : ID của Semaphore
share_id : ID của vùng nhớ chung
share_add : Địa chỉ của vùng nhớ chung
IV Cài đặt Server
1 Chơng trình chính
Khởi tạo
Bắt tay
Thành công
Kết thúc
y
n
Truyền file
Giải phóng
Trang 4b, Cài đặt
int main()
{
int sem_set_id; // ID cua Semaphore dung de dong bo
int share_id; // ID cua Vung nho chung
int size_share; // Kich thuoc cua vung nho chung
char *share_add; // Dia chi cua vung nho chung
int hand_file; // The file
int rc; // Lay ket qua thuc hien cua cac ham
struct shmid_ds share_desc;// Dung de xoa Semaphore
int *request; // Thong bao tu Client yeu cau Server truyen du lieu
int *confirm; // Thong bao tu Server tra loi co truyen du lieu hay khong int *have_file;// Thong bao tu Server cho Client biet la co file
int *realy;//Thong bao tu Client cho Server biet la da san sang nhan du lieu int *have_data;// Thong bao tu Server cho Client biet la van con du lieu int *count; //Do dai cua du lieu duoc truyen tu Server
char *filename; //Ten file
char *message; //Thong bao kem theo de hien ra man hinh
char *data; //Du lieu
size_share = 2000;
//Cap phat vung nho kich thuoc la size_share
share_id = shmget(100,size_share,IPC_CREAT | 0777);
if(share_id == -1)
{
printf("Loi khi cap phat vung nho chung.");
exit(EXIT_FAILURE);
}
//Gan dia chi vung nho trung vao khong gian bo nho cua tien trinh
share_add = shmat(share_id,NULL,0);
if(!share_add)
{
printf("Loi ket gan vung nho chung.");
exit(EXIT_FAILURE);
}
//Tao semaphore
sem_set_id = create_sem(1);
//Khoi tao semaphore
init_sem(sem_set_id,1);
Trang 5//Tro bien request vao vung du lieu chung
printf("1\n");
request = (int*)((void*)share_add);
(*request) = 0;
//Tro bien confirm vao vung du lieu chung
printf("2\n");
confirm = (int*)((void*)share_add + sizeof(int));
(*confirm) = 0;
//Tro bien have_file vao vung du lieu chung
printf("3\n");
have_file = (int*)((void*)share_add + sizeof(int)*2);
(*have_file) = 0;
//Tro bien realy vao vung du lieu chung
printf("4\n");
realy = (int*)((void*)share_add + sizeof(int)*3);
(*realy) = 0;
//Tro bien have_data vao vung du lieu chung
printf("5\n");
have_data = (int*)((void*)share_add + sizeof(int)*4);
(*have_data) = 0;
//Tro bien count vao vung du lieu chung
count = (int*)((void*)share_add + sizeof(int)*5);
(*count) = 0;
//Tro bien filename vao vung du lieu chung
printf("6\n");
filename = (char*)((void*)share_add + sizeof(int)*6);
//Tro bien message vao vung du lieu chung
printf("7\n");
message = (char*)((void*)share_add + MAX_FILENAME + sizeof(int)*6);
//Tro bien data vao vung du lieu chung
printf("8\n");
data = (char*)((void*)share_add + MAX_MESSAGE + MAX_FILENAME + sizeof(int)*6);
//Bat tay voi Client
hand_file = server_hand_shaking(sem_set_id,request,confirm,message
,filename,hand_file,have_file,realy);
Trang 6if(hand_file > 0)
{
server_transfer(sem_set_id,message,have_data,data,hand_file,
count);
close(hand_file);
}
//Xoa Semaphore
remove_sem(sem_set_id);
//Go vung nho chung
shmdt(share_add);
//Giai phong vung nho chung
shmctl(share_id,IPC_RMID,&share_desc);
printf("Server da ket thuc\n");
exit(EXIT_SUCCESS);
}
Phần khởi tạo sử dụng các hàm th viện để khởi tạo Semaphore, vùng nhớ chung, gắn vùng nhớ chung vào vùng nhớ của chơng trình các hàm này đã
đ-ợc trình bày trong phần lý thuyết Sau phần khởi tạo là phần gán địa chị các biến vào vùng nhớ chung.
Chơng trình chính đợc chia ra làm hai phần Phần bắt tay và phần truyền file Phần bắt tay đợc cài đặt trong hàm server_hand_shaking, hàm này dùng để thực hiện một số giao tiếp ban đầu trớc khi truyền file nh trả lời chấp nhận,
có file.
Phần truyền file đợc cài đặt trong hàm server_transfer để truyền file.
Sau khi hoàn thành quá trình truyền file thì giải phóng những gì đã đợc khởi tạo.
2 Hàm bắt tay với Client
a, Giải thuật:
Trang 7b, Cài đặt
int server_hand_shaking(int sem_set_id,int *request,int *confirm,char*message
,char *filename,int hand_file,int *have_file,int *realy) {
printf("Dang doi yeu cau \n");
//Doi yeu cau tu Client
Bắt đầu
Nhận tên file từ Client
Trả lời Confirm = 1 Request = 1
Kết thúc
y
n
Have_file = 1 Trả lời có file và hỏi sẵn sàng chưa
Kiểm tra file
Tên file = “exit”
y
n
Có file
n
y
Realy = 1
y
Have_file = 0 Trả lời không có file
n
Trả lại thẻ file cho chương trình chính
Trang 8{
sleep(1);
}
sem_lock(sem_set_id); //Doi de vao su dung tai nguyen, khi da vao thi cam cac tien trinh khac su dung tai nguyen printf("1.Client: %s\n",message);
*confirm = 1;//Tra loi dong y truyen du lieu
strcpy(message,"Dong y truyen.");
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac tien trinh
khac co the vao su dung tai nguyen sleep(1);//Doi Client gui ten file
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam
cac tien trinh khac vao su dung tai nguyen
while(1)
{
printf("2.Client: %s\n",message);
if(strcasecmp(filename,"exit")==0)return -1;
hand_file = open(filename,O_RDONLY);
//Kiem tra su ton tai cua file Cleint yeu cau
if(hand_file > 0 )
{
strcpy(message,"San sang chua?");
*have_file = 1;//Thong bao cho Client biet la co file, va hoi da
san sang chua sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao
su dung tai nguyen sleep(2);//Doi tra loi san sang cua Client
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen,
khi da vao thi cam cac tien trinh khac vao su dung tai nguyen printf("3.Client: %s\n",message);
if(*realy == 0) return -1;
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao
su dung tai nguyen
break;
}
else
{
strcpy(message,"Khong tim thay file");
*have_file = 0;//Thong bao cho Client biet khong co file ma
no yeu cau sleep(1);
Trang 9sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao
su dung tai nguyen sleep(1);//Doi Client goi ten file khac
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen,
khi da vao thi cam cac tien trinh khac vao su dung tai nguyen }
}
return hand_file;
}
Hàm này hoạt động nh sau: ban đầu lặp liên tục kiểm tra biến request nếu =
1 sẽ khoá semaphore và vào sử dụng vùng nhớ chung gán giá trị 1 cho biến confirm, mở khoá semaphore cho Client vào kiểm tra biến confirm Lúc này Client đã gửi tên file và Server lại vào lấy tên file và kiểm tra sự tồn tại của file đó, sau đó trả lời Client
3 Hàm truyền dữ liệu
a, Giải thuật
b, Cài đặt
Bắt đầu
Nhận và hiển thị thông báo từ Client
Đọc dữ liệu từ file vào biến data, count = sizeof(data) have_data = 1 Chưa hết file
Kết thúc
y n
Have_data = 0
Trang 10void server_transfer(int sem_set_id,char *message,int *have_data,char
*data,int hand_file,int *count)
{
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam
cac tien trinh khac vao su dung tai nguyen
while((*count = read(hand_file,data,MAX_DATA))!=0)
{
*have_data = 1;
sleep(1);
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao
su dung tai nguyen sleep(1);//Doi thong bao tu Client da nhan duoc du lieu sem_lock(sem_set_id);//Doi de vao su dung tai nguyen,
khi da vao thi cam cac tien trinh khac vao su dung tai nguyen printf("Client: %s\n",message);
}
*have_data = 0;
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac tien trinh
khac co the vao su dung tai nguyen }
Hàm này hoạt động cho đến khi dữ liệu đã đợc gửi hết Trong vòng lặp gửi dữ liệu, sau mỗi lần gửi dữ liệu Server phải đợi cho Client nhận đợc dữ liệu rồi mới gửi tiếp.
V Cài đặt Client
Trang 111 Chơng trình chính
a, Giải thuật
b, Cài đặt
Chơng trình chính của Client đợc cài đặt giống với chơng trình chính của Server chỉ thay hai hàm server_hand_shaking bằng hàm
client_hand_shaking, hàm server_transfer bằng hàm client_transfer.
2 Hàm bắt tay với Server
Bắt đầu
Khởi tạo
Bắt tay
Thành công
Kết thúc
y
n
Truyền file
Giải phóng
Trang 12a, Giải thuật
b, Cài đặt
int client_hand_shaking(int sem_set_id,int *request,int *confirm,char
*message,char *filename,int hand_file,int *have_file,int *realy)
{
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam
cac tien trinh khac vao su dung tai nguyen
Băt đầu
Gửi yêu cầu Request = 1
Kiểm tra sự phản hồi
từ Server
Confirm = 1
Gửi tên file tới Server
realy = 1
Trả về thẻ file cho chương trình chính
y
Tên file = “exit”
Kiểm tra sự phản hồi
từ Server
Have_file = 1
Kết thúc y
y n
n
n
Trang 13*request = 1;//Client gui yeu cau can truyen du lieu
strcpy(message,"Toi muon truyen file");
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac tien trinh
khac co the vao su dung tai nguyen sleep(1);
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam
cac tien trinh khac vao su dung tai nguyen printf("1.Server: %s\n",message);
if(*confirm==1)//Kiem tra trang thai cua server co dong y truyen du lieu
khong {
while(1)
{
//Gui ten file yeu cau server
printf(" Ten file can truyen: ");fflush(stdin);
fgets(filename,MAX_FILENAME,stdin);
//Trong truong hop yeu cau server nhieu lan nhung server khong
tim thay file do thi danh ten file la "exit" de thoat
if(strcasecmp(str_no_return(filename),"exit")==0)
{
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao su dung tai nguyen
return -1;
}
strcpy(message,"Toi muon co file ");
strcat(message,str_no_return(filename));
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac
tien trinh khac co the vao su dung tai nguyen sleep(1);
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen,
khi da vao thi cam cac tien trinh khac vao su dung tai nguyen
//Kiem tra thong bao tra loi cua server la co file dang yeu cau khong printf("2.Server: %s\n",message);
if(*have_file==1)
{
strcpy(message,"Da san sang");
*realy = 1;//Tra loi da san sang cho qua trinh truyen du lieu
strcat(filename,"_cp");
hand_file = open(filename,O_WRONLY|
O_TRUNC|O_CREAT);
break;
}
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac
tien trinh khac co the vao su dung tai nguyen
Trang 14sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao
thi cam cac tien trinh khac vao su dung tai nguyen }
}
else return -1;
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac tien trinh
khac co the vao su dung tai nguyen sleep(2);
return hand_file;
}
3 Hàm nhận dữ liệu
a, Giải thuật
b, Cài đặt
void client_transfer(int sem_set_id,char *message,int *have_data,char *data,
int hand_file,int *count)
{
int i;
Bắt đầu
Nhậndữ liệu và hiển thị thông báo từ Server
Ghi dữ liệu vào file với kích thước là count, trả lời đã
nhận được Have_data=1
Kết thúc y n
Trang 15sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam
cac tien trinh khac vao su dung tai nguyen
i = 0;
while(*have_data)
{
i++;
write(hand_file,data,*count);
printf("Block %d: %d bytes\n",i,*count);
sprintf(message,"Da nhan duoc block %d",i);
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong
va cac tien trinh khac co the vao su dung tai nguyen sleep(2);
sem_lock(sem_set_id);//Doi de vao su dung tai nguyen, khi da vao thi cam cac tien trinh khac vao su dung tai nguyen }
printf("Het \n");
sem_unlock(sem_set_id);//Tra lai tai nguyen cho he thong va cac tien trinh
khac co the vao su dung tai nguyen }
Hàm này thực hiện việc nhận dữ liệu từ Server và trả lời đã nhận đợc dữ liệu cho đến khi biến have_data = 0.
VI Một số chú ý:
Chơng trình gồm có 3 file: server3.c, client3.c, ttcs.h
Khi chạy 2 file từ hai terminal khác nhau, cần chạy server3 trớc, client3 sau.
Mục lục:
Trang 16I §Ò tµi 1
III X©y dùng kÞch b¶n giao tiÕp gi÷a hai tiÕn tr×nh 2
1 Ch¬ng tr×nh chÝnh 3
2 Hµm b¾t tay víi Client 6
3 Hµm truyÒn d÷ liÖu 9
1 Ch¬ng tr×nh chÝnh 11
2 Hµm b¾t tay víi Server 12
3 Hµm nhËn d÷ liÖu 14