BÀI 4 GIAO TIẾP GIỮA CÁC TIẾN TRÌNH TRONG LINUX

Similar documents
Internet Protocol. Bởi: Phạm Nguyễn Bảo Nguyên

STACK và QUEUE. Lấy STACK

Cài đặt và cấu hình StarWind iscsi trên Windows. iscsi SAN là gì?

Bộ môn MMT&TT, Khoa Công Nghệ Thông Tin và TT, ĐH Cần Thơ

HƯỚNG DẪN SỬ DỤNG HỆ THỐNG CẬP NHẬT CHỨNG THƯ SỐ HOTLINE:

BÀI 1: VBA LÀ GÌ? TẠO MACRO, ỨNG DỤNG CÁC HÀM TỰ TẠO (UDF), CÀI ĐẶT ADD-INS VBA là gì?

HƯỚNG DẪN CÀI ĐẶT PHẦN MỀM DIỆT VIRUS AVIRA

BÀI TẬP THỰC HÀNH LẬP TRÌNH WINDOWS C#

HƯỚNG DẪN SỬ DỤNG PLESK PANEL

Bài Thực hành Asp.Net - Buổi 1 - Trang: 1

Tạo Project với MPLAB

TÀI LIỆU THỰC HÀNH MÔN CƠ SỞ DỮ LIỆU NÂNG CAO

Chương 6. Transport Layer. Tài liệu : Forouzan, Data Communication and Networking

Hướng dẫn cài đặt FPT

Cụ thể những công việc mà AndroidManifest.xml thực hiện: - Đặt tên cho Java package của ứng dụng.

Tài liệu hướng dẫn: Stored Procedure

Chương 5. Network Layer 19/09/2016 1

HƯỚNG DẪN CÁCH SỬ DỤNG WINDOWS MOVIE MAKER

Bộ môn HTMT&TT, Khoa Công Nghệ Thông Tin và TT, ĐH Cần Thơ

SIMULATE AND CONTROL ROBOT

Nội dung chính của chương. Các công nghệ đĩa cứng Cấu tạo vật lý của đĩa cứng Cấu tạo logic của đĩa cứng Cài đặt đĩa cứng như thế nào?

GIẢI THUẬT ĐỊNH TUYẾN (ROUTING ALGORITHM)

HƯỚNG DẪN SỬ DỤNG ĐẦU GHI H.264 DVR VISION VS (4CH - 8CH - 16CH)

Chương 5. Network Layer. Phần 1 - Địa chỉ IPv4. Tài liệu : Forouzan, Data Communication and Networking

Khối: Cao Đẳng nghề và Trung Cấp Năm 2009

Giáo trình này được biên dịch theo sách hướng dẫn của Sun Light. Vì là hướng dẫn kỹ thuật, trong này những thuật ngữ kỹ thuật bằng tiếng Anh tôi chỉ

Giao tiếp giữa các tiến trình

ĐỌC, GHI XML VỚI C# TRONG ADO.NET --- SỬ DỤNG VISUAL STUDIO

Kỹ thuật thu nhỏ đối tượng trong Design (Layout)

Nhấn nút New để tạo 1 biến mới Trang 17

Tạo repository mới. The working tree. The staging index. Lệnh git init tạo một repository loại git. tại thư mục hiện tại: $ git init

B5: Time to coding. Tới thư mục src/example.java và thay đổi nội dung file như sau: Mã: package at.exam;

Bài tập lớn số 1. Giả lập bộ định thời

Tình huống 1: PPPoE với Username và Password

HƢỚNG DẪN TRIỂN KHAI KASPERSKY - MOBILE DEVICE MANAGEMENT

Dọn "rác" Windows 7 vào dịp cuối năm

Entity Framework (EF)

BELGIUM ONLINE APPOINTMENT

CẤU TRÚC DỮ LIỆU NÂNG CAO

I. Hướng Dẫn Đăng Nhập:

Khoa KH & KTMT Bộ môn Kỹ Thuật Máy Tính

Online Appointment System will work better with below conditions/ Hệ thống đặt hẹn online sẽ hoạt động tốt hơn với điều kiện sau đây:

Bài 10. Cấu trúc liên nối. khác nhau được gọi là cấu trúc liên nối. nhu cầu trao đổi giữa các module.

SIEMENS INDUSTRIAL NETWORKS

Ôn tập Thiết bị mạng và truyền thông DH07TT - Lưu hành nội bộ (không sao chép dưới mọi hình thức)

BẢO MẬT TRONG SQL SERVER

Lecture 12. Trees (1/2) Nội dung bài học:

Mô hình dữ liệu quan hệ (Relational data model)

LẬP TRÌNH WINDOWS FORM VỚI CÁC CONTROL NÂNG CAO (Các control trình bày dữ liệu dưới dạng danh sách)

Google Search Engine. 12/24/2014 Google Search Engine 1

Bài 10: Cấu trúc dữ liệu

LÂ P TRI NH WEB ASP.NET

Bài tập căn bản Visual Basic.Net Vòng lặp. txtn. txtketqua. btntinh. txtn. txtketqua. btntinh. Trang 1

LAB IP SLA Bài 1. Bùi Quốc Kỳ ***

Chương 7. Application Layer. Tài liệu : Forouzan, Data Communication and Networking

TÀI LIỆU HƯỚNG DẪN SỬ DỤNG HOSTING PLESK PANEL

MỤC LỤC. Giáo trình Thiết kế web Trang 1

BÀI GIẢNG CHƯƠNG 3 GIAO TIẾP KẾT NỐI SỐ LIỆU

BÀI THỰC HÀNH SỐ 1. Quản trị tập tin: 1/ Tạo các thư mục sau: Bài tập thực hành linux Linuxlab. bt1 bt11 bt111. bt121. bt12. bh1 bh11 bh111.

BÀI LAB ĐỔI TÊN DOMAIN

BÀI 6 LÀM VIỆC VỚI THÀNH PHẦN MỞ RỘNG CỦA CSS3

HƯỚNG DẪN SỬ DỤNG NHANH MINDJET MIND MANAGER

2.4. GIAO THỨC MQTT Các khái niệm cơ bản MQTT được phát triển bởi IBM và Eurotech, phiên bản mới nhất là MQTT 3.1 MQTT (Giao vận tầm xa) là

GV: Phạm Đình Sắc or

Bài 13: C++11. EE3490: Kỹ thuật lập trình HK1 2017/2018 TS. Đào Trung Kiên ĐH Bách khoa Hà Nội

TỔNG QUAN VỀ.NET VÀ C#

Môn Học: Cơ Sở Dữ Liệu 2. Chương 3 LẤY DỮ LIỆU TỪ NHIỀU NGUỒN

PHÁT TRIỂN ỨNG DỤNG WEB

Các kiểu định địa chỉ họ MSC-51

LẬP TRÌNH 8051 SỐ HỌC VÀ LÔ GIC

Tìm hiểu Group Policy Object và các ví dụ

1 Bước 1: Test thử kit LaunchPad.

HƯỚNG DẪN SỬ DỤNG DỊCH VỤ CDN

HTML DOM - Forms. MSc. nguyenhominhduc

NHÚNG. Vi ñiều khiển BM Kỹ Thuật ðiện Tử - ðh Bách Khoa TP.HCM 2

Qu n ả tr h ố g t p ậ tin

Phần 2. SỬ DỤNG POWERPOINT ĐỂ CHUẨN BỊ NỘI DUNG TRÌNH BÀY

Exceptions. Outline 7/31/2012. Exceptions. Exception handling is an important aspect of objectoriented. Chapter 10 focuses on:

Hệ điều hành Bài tập tuần 7_ Chúng ta làm quen một số lệnh thao tác với hệ thống file trong Linux :

KIẾN TRÚC MÁY TÍNH. Giảng viên: ThS. Phan Thanh Toàn. v

Module2: Lập trình Shell và C Quản lý tiến trình A. TÓM TẮT LÝ THUYẾT:

HƯỚNG DẪN SỬ DỤNG DỊCH VỤ CDN

LINQ TO SQL & ASP.NET

Bài thực hành số 2 QUYỀN và ROLE

dụng một chính sách, điều này giúp dễ dàng quản lý và cung cấp tính năng Load Balancing (cân bằng tải) phục vụ tốt hơn các yêu cầu của tổ chức.

Bài 7: Các cấu trúc điều khiển

Bài 6: Xuất nhập (input/output) EE3490: Kỹ thuật lập trình HK1 2017/2018 TS. Đào Trung Kiên ĐH Bách khoa Hà Nội

NHẬP MÔN LẬP TRÌNH KHOA HỌC DỮ LIỆU. Bài 10: Thư viện Pandas (2)

Hướng Dẫn Thực Hành Tập tin & Thư mục

Parallels Cloud Server 6.0

CHƯƠNG 2: CÁC ĐẶC ĐIỂM VỀ MÔI TRƯỜNG PHÁT TRIỂN (IDE)

HỢP ĐỒNG MUA BÁN HÀNG HÓA QUỐC TẾ GV: NGUYỄN THỊ BÍCH PHƯỢNG

HƯỚNG DẪN QUẢN TRỊ HỆ THỐNG

MA NG MA Y TI NH (Computer Networks)

HƯỚNG DẪN CÀI ĐẶT VÀ SỬ DỤNG KASPERSKY SECURITY CENTER. Version

Đa ngôn ngữ (Internationalization) trong Servlet

Cập nhật ResultSet trong JDBC

B3: Bên khung Package Explore bên trái đi tới thư mục res, bạn sẽ thấy có 3 thư mục con:

Khối: Cao Đẳng nghề và Trung Cấp Năm 2009

CHAPTER 6: DANH SÁCH LIÊN KẾT (LINKED LISTS)

Transcription:

BÀI 4 GIAO TIẾP GIỮA CÁC TIẾN TRÌNH TRONG LINUX I. Khái quát Linux cung cấp một số cơ chế giao tiếp giữa các tiến trình gọi là IPC (Inter-Process Communication): Trao đổi bằng tín hiệu (signals handling) Trao đổi bằng cơ chế đường ống (pipe) Trao đổi thông qua hàng đợi thông điệp (message queue) Trao đổi bằng phân đoạn nhớ chung (shared memory segment) Giao tiếp đồng bộ dùng semaphore Giao tiếp thông qua socket II. Xử lý tín hiệu (signals handling) 1. Khái niệm - Tín hiệu là các thông điệp khác nhau được gởi đến tiến trình nhằm thông báo cho tiến trình một tình huống. Mỗi tín hiệu có thể kết hợp hoặc có sẵn bộ xử lý tín hiệu (signal handler). Tín hiệu sẽ ngắt ngang quá trình xử lý của tiến trình, bắt hệ thống chuyển sang gọi bộ xử lý tín hiệu ngay tức khắc. Khi kết thúc xử lý tín hiệu, tiến trình lại tiếp tục thực thi. - Mỗi tín hiệu được định nghĩa bằng một số nguyên trong /urs/include/signal.h. Danh sách các hằng tín hiệu của hệ thống có thể xem bằng lệnh kill l. 2. Gởi tín hiệu đến tiến trình Tiến trình có thể nhận tín hiệu từ hệ điều hành hoặc các tiến trình khác gởi đến. Các cách gởi tín hiệu đến tiến trình: a) Từ bàn phím Ctrl+C: gởi tín hiệu INT( SIGINT ) đến tiến trình, ngắt ngay tiến trình (interrupt). Ctrl+Z: gởi tín hiệu TSTP( SIGTSTP ) đến tiến trình, dừng tiến trình (suspend). Ctrl+\: gởi tín hiệu ABRT( SIGABRT ) đến tiến trình, kết thúc ngay tiến trình (abort). b) Từ dòng lệnh - Lệnh kill -<signal> <PID> Ví dụ: kill -INT 1234 dùng gởi tín hiệu INT ngắt tiến trình có PID 1234. Nếu không chỉ định tên tín hiệu, tín hiệu TERM được gởi để kết thúc tiến trình. - Lệnh fg: gởi tín hiệu CONT đến tiến trình, dùng đánh thức các tiến trình tạm dừng do tín hiệu TSTP trước đó. c) Bằng các hàm hệ thống kill(): #include <signal.h> /* macro xử lý tín hiệu và hàm kill() */ pid_t my_pid = getpid() /* lấy định danh tiến trình */ kill( my_pid, SIGSTOP ); /* gửi tín hiệu STOP đến tiến trình */ 3. Đón bắt xử lý tín hiệu - Một số tín hiệu hệ thống (như KILL, STOP) không thể đón bắt hay bỏ qua được. - Tuy nhiên, có rất nhiều tín hiệu mà bạn có thể đón bắt, bao gồm cả những tín hiệu nổi tiếng như SEGV và BUS. a) Bộ xử lý tín hiệu mặc định Hệ thống đã dành sẵn các hàm mặc định xử lý tín hiệu cho mỗi tiến trình. Ví dụ, bộ xử lý mặc định cho tín hiệu TERM gọi là hàm exit() chấm dứt tiến trình hiện hành. Bộ xử lý dành cho tín hiệu ABRT là gọi hàm hệ thống abort() để tạo ra file core lưu xuống thư mục hiện hành và thoát chương trình. Mặc dù vậy đối với một số tín hiệu bạn có thể cài đặt hàm thay thế bộ xử lý tín hiệu mặc định của hệ thống. Chúng ta sẽ xem xét vấn đề này ngay sau đây: b) Cài đặt bộ xử lý tín hiệu Có nhiều cách thiết lập bộ xử lý tín hiệu (signal handler) thay cho bộ xử lý tín hiệu mặc định. Ở đây ta dùng cách cơ bản nhất đó là gọi hàm signal(). #include <signal.h> void signal( int signum, void (*sighanldler)( int ) ); III. Đường ống (pipe) 1. Khái niệm - Các tiến trình chạy độc lập có thể chia sẻ hoặc chuyển dữ liệu cho nhau xử lý thông qua cơ chế đường ống (pipe). Ví dụ: ps ax grep ls 1

- Trên đường ống dữ liệu chỉ có thể chuyển đi theo một chiều, dữ liệu vào đường ống tương đương với thao tác ghi (pipe write), lấy dữ liệu từ đường ống tương đương với thao tác đọc (pipe read). Dữ liệu được chuyển theo luồng (stream) theo cơ chế FIFO. 2. Tạo đường ống Hệ thống cung cấp hàm pipe() để tạo đường ống có khả năng đọc / ghi. Sau khi tạo ra, có thể dùng đường ống để giao tiếp giữa hai tiến trình. Đọc / ghi đường ống hoàn toàn tương đương với đọc / ghi file. int pipe( int filedes[2] ); Mảng filedes gồm hai phần tử nguyên dùng lưu lại số mô tả cho đường ống trả về sau lời gọi hàm, ta dùng hai số này để thực hiện thao tác đọc / ghi trên đường ống: phần tử thứ nhất dùng để đọc, phần tử thứ hai dùng để ghi. int pipes[2]; int rc = pipe( pipes ); /*Tạo đường ống*/ /*Có tạo đường ống được không?*/ perror( "Error: pipe not created" ); 3. Đường ống hai chiều Sử dụng cơ chế giao tiếp đường ống hai chiều dễ dàng cho cả hai phía tiến trình cha và tiến trình con. Các tiến trình dùng một đường ống để đọc và một đường ống để ghi. Tuy nhiên cũng rất dễ gây ra tình trạng tắc nghẽn deadlock : - Cả hai đường ống đều rỗng nếu đường ống rỗng hàm read() sẽ block cho đến khi có dữ liệu đổ vào hoặc khi đường ống bị đóng bởi bên ghi. - Cả hai tiến trình cùng ghi dữ liệu: vùng đệm của một đường ống bị đầy, hàm write() sẽ block cho đến khi dữ liệu được lấy bớt ra từ một thao tác đọc read(). 4. Đường ống có đặt tên Đường ống được tạo ra từ hàm pipe() được gọi là đường ống vô danh (anonymouse pipe). Nó chỉ được sử dụng giữa các tiến trình cha con do bạn chủ động điều khiển tạo ra từ hàm fork(). Một vấn đề đặt ra, nếu hai tiến trình không quan hệ gì với nhau thì có thể sử dụng được cơ chế pipe để trao đổi dữ liệu hay không? Câu trả lời là có. Linux cho phép bạn tạo ra các đường ống đặt tên (named pipe). Những đường ống mang tên sẽ nhìn thấy và truy xuất bởi các tiến trình khác nhau. a) Tạo pipe đặt tên với hàm mkfifo() Đường ống có đặt tên gọi là đối tượng FIFO, được biểu diễn như một file trong hệ thống. Vì vậy có thể dùng lệnh mkfifo() để tạo file đường ống với tên chỉ định. mkfifo( const char *filename, mode_t mode ); Đối số thứ nhất là tên đường ống cần tạo, đối số thứ hai là chế độ đọc ghi của đường ống. Ví dụ: int res = mkfifo( "~/tmp/my_fifo", 0777 ); if ( res == 0 ) printf( "FIFO object created" ); exit ( EXIT_SUCCESS ); - Có thể xem file đường ống này trong thư mục tạo nó. - Có thể tạo đường ống có đặt tên từ dòng lệnh, ví dụ: mkfifo ~/tmp/my_fifo --mode=0777 b) Đọc / ghi trên đường ống có đặt tên - Dùng dòng lệnh với > (ghi dữ liệu) hoặc < (đọc dữ liệu), ví dụ: echo Hello world! > ~/tmp/my_fifo cat < /tmp/my_fifo hoặc: echo Hello world! > ~/tmp/my_fifo & cat < ~/tmp/my_fifo - Lập trình: thao tác trên đường ống có đặt tên giống như thao tác trên file nhưng chỉ có chế độ O_RDONLY (chỉ đọc) hoặc O_WRONLY (chỉ ghi). 2

IV. Thực hành Bài 1: Chương trình đặt bẫy tín hiệu (hay thiết lập bộ xử lý) tín hiệu INT. Đây là tín hiệu gửi đến tiến trình khi người dùng nhấn Ctrl + C. Chúng ta không muốn chương trình bị ngắt ngang do người dùng vô tình (hay cố ý) nhấn tổ hợp phím này. #include <signal.h> /*Hàm nhập xuất chuẩn*/ /*các hàm chuẩn của UNIX như getpid()*/ /*các hàm xử lý tín hiệu()*/ /*Trước hết cài đặt hàm xử lý tín hiệu*/ void catch_int( int sig_num ) signal( SIGINT, catch_int ); /*Thực hiện công việc của bạn ở đây*/ printf( "Do not press Ctrl+C\n" ); /*Chương trình chính*/ int count = 0; /*Thiết lập hàm xử lý cho tín hiệu INT(Ctrl + C)*/ signal( SIGINT, catch_int ); /*Đặt bẫy tín hiệu INT*/ while ( 1 ) printf( "Counting %d\n", count++ ); sleep( 1 ); Bài 2: Tạo đường ống, gọi hàm fork() để tạo ra tiến trình con. Tiến trình cha sẽ đọc dữ liệu nhập vào từ phía người dùng và ghi vào đường ống trong khi tiến trình con phía bên kia đường ống tiếp nhận dữ liệu bằng cách đọc từ đường ống và in ra màn hình. /*Cài đặt hàm dùng thực thi tiến trình con*/ void do_child( int data_pipes[] ) int c; /*Chứa dữ liệu từ tiến trình cha*/ int rc; /*Lưu trạng thái trả về của read()*/ /*Tiến trình con chỉ đọc đường ống nên đóng đầu ghi do không cần*/ close( data_pipes[1] ); /*Tiến trình con đọc dữ liệu từ đầu đọc */ while ( ( rc = read( data_pipes[0], &c, 1 ) ) > 0 ) putchar( c ); exit( 0 ); /*Cài đặt hàm xử lý công việc của tiến trình cha*/ void do_parent( int data_pipes[] ) int c; /*Dữ liệu đọc được do người dùng nhập vào*/ int rc; /*Lưu trạng thái trả về của write()*/ /*Tiến trình cha chỉ ghi đường ống nên đóng đầu đọc do không cần*/ close( data_pipes[0] ); /*Nhận dữ liệu do người dùng nhập vào và ghi vào đường ống */ while ( ( c = getchar() ) > 0 ) /*Ghi dữ liệu vào đường ống*/ rc = write( data_pipes[1], &c, 1 ); perror( "Parent: pipe write error" ); close( data_pipes[1] ); /*Đóng đường ống phía đầu ghi để thông báo cho phía cuối đường ống dữ liệu đã hết*/ close(data_pipe[1]); exit(0); /*Chương trình chính*/ int data_pipes[2]; int pid; int rc; rc = pipe( data_pipes ); /*Mảng chứa số mô tả đọc ghi của đường ống*/ /*pid của tiến trình con*/ /*Lưu mã lỗi trả về*/ /*Tạo đường ống*/ 3

perror( "Error: pipe not created" ); /*Tạo tiến trình con*/ pid = fork(); switch ( pid ) case -1: /*Không tạo được tiến trình con*/ perror( "Child process not create" ); case 0: /*Tiến trình con*/ do_child( data_pipes ); default: /*Tiến trình cha*/ return 0; do_parent( data_pipes ); Bài 3: Chương trình sử dụng cơ chế đường ống giao tiếp hai chiều, dùng hàm fork() để nhân bản tiến trình. Tiến trình thứ nhất (tiến trình cha) sẽ đọc nhập liệu từ phía người dùng và chuyển vào đường ống đến tiến trình thứ hai (tiến trình con). Tiến trình thứ hai xử lý dữ liệu bằng cách chuyển tất cả ký tự thành chữ hoa sau đó gửi về tiến trình cha qua một đường ống khác. Cuối cùng tiến trình cha sẽ đọc từ đường ống và in kết quả của tiến trình con ra màn hình (Sinh viên tự làm). Bài 4: Tạo hai tiến trình tách biệt: producer.c là tiến trình sản xuất, liên tục ghi dữ liệu vào đường ống mang tên /tmp/my_fifo trong khi consumer.c là tiến trình tiêu thụ liên tục đọc dữ liệu từ đường ống /tmp/my_fifo cho đến khi nào hết dữ liệu trong đường ống thì thôi. Khi hoàn tất quá trình nhận dữ liệu, tiến trình consumer sẽ in ra thông báo kết thúc. /* producer.c */ #include <string.h> #include <fcntl.h> #include <limits.h> #define FIFO_NAME "my_fifo" /*Tạo đường ống*/ #define BUFFER_SIZE PIPE_BUF /*Vùng đệm dùng cho đường ống*/ #define TEN_MEG ( 1024 * 1024 * 10 ) /*Dữ liệu*/ int pipe_fd; int res; int open_mode = O_WRONLY; int bytes_sent = 0; char buffer[buffer_size + 1]; /*Tạo pipe nếu chưa có*/ if ( access( FIFO_NAME, F_OK ) == -1 ) res = mkfifo( FIFO_NAME, (S_IRUSR S_IWUSR) ); if ( res!= 0 ) fprintf( stderr, "FIFO object not created [%s]\n", FIFO_NAME); /*Mở đường ống để ghi*/ printf( "Process %d starting to write on pipe\n", getpid() ); pipe_fd = open( FIFO_NAME, open_mode); if ( pipe_fd!= -1 ) /*Liên tục đổ vào đường ống*/ while ( bytes_sent < TEN_MEG ) res = write( pipe_fd, buffer, BUFFER_SIZE ); if ( res == -1 ) fprintf( stderr, "Write error on pipe\n" ); bytes_sent += res; /*Kết thúc quá trình ghi dữ liệu*/ ( void ) close( pipe_fd ); else 4

printf( "Process %d finished, %d bytes sent\n", getpid(), bytes_sent ); exit( EXIT_SUCCESS ); /* consumer.c */ #include <string.h> #include <fcntl.h> #include <limits.h> #define FIFO_NAME "my_fifo" #define BUFFER_SIZE PIPE_BUF int pipe_fd; int res; int open_mode = O_RDONLY; int bytes_read = 0; char buffer[buffer_size + 1]; /* Mở đường ống để đọc */ printf( "Process %d starting to read on pipe\n", getpid() ); pipe_fd = open( FIFO_NAME, open_mode); if ( pipe_fd!= -1 ) do res = read( pipe_fd, buffer, BUFFER_SIZE ); bytes_read += res; while ( res > 0 ); ( void ) close( pipe_fd ); /Kết thúc đọc*/ else printf( "Process %d finished, %d bytes read\n", getpid(), bytes_read ); exit( EXIT_SUCCESS ); Chạy producer dưới nền, tiếp đến là consumer:./producer &./consumer 5