Tổng hợp những câu hỏi cần thiết và quan trọng của môn Lập trình nhân Linux (KMA). Tài liệu này giúp các bạn sinh viên có thể vượt qua các bài kiểm tra giữa kỳ, cuối kỳ và đạt kết quả cao nhất. Xin cảm ơn các bạn đã xem và tải tài liệu.
GIỚI THIỆU CHUNG
Tổng quan về Linux
1.1.1 Khái niệm hệ điều hành Linux
Hệ điều hành Linux là một hệ điều hành mã nguồn mở (open – source) dựa trên nhân Linux (Linux kernel), một phần cốt lõi của hệ thống Linux kernel được phát triển bởi một nhóm lập trình viên trên toàn thế giới dưới sự chỉ đạo của Linus Torvalds từ năm 1991 Hệ điều hành Linux không chỉ là một kernel, mà còn bao gồm một số các thành phần khác như các tiện ích dòng lệnh, thư viện, và các công cụ hỗ trợ
Linux được thiết kế để hoạt động trên nhiều loại phần cứng khác nhau, từ các máy tính cá nhân thông thường đến máy chủ, thiết bị nhúng, và các hệ thống nhúng
Sự linh hoạt và tính đa dạng này là một trong những điểm mạnh của Linux, giúp nó trở thành một trong những hệ điều hành phổ biến nhất trên thế giới
Một trong những đặc điểm quan trọng của Linux là tính bảo mật và ổn định cao Do là một hệ điều hành mã nguồn mở, Linux thường nhận được sự hỗ trợ đa dạng từ cộng đồng lập trình viên trên toàn cầu, điều này giúp nó có những bản vá lỗi và cập nhật định kỳ, giữ cho hệ thống luôn được bảo mật và ổn định
Linux cũng là nền tảng cho nhiều hệ điều hành khác nhau, được gọi là các bản phân phối (distribution) Linux Các bản phân phối này có thể được tinh chỉnh và tùy chỉnh cho các mục đích sử dụng cụ thể, từ việc sử dụng cho máy tính cá nhân đến máy chủ, điện thoại thông minh, máy tính bảng, và nhiều thiết bị khác nữa
Hầu hết các bản Linux đều hỗ trợ rất nhiều ngôn ngữ lập trình, đặc biệt công cụ GCC cho phép người lập trình có thể biên dịch và thực thi ứng dụng viết bằng nhiều ngôn ngữ lập trình khác nhau: C/C++, Java, Ngoài ra, Linux còn hỗ trợ ngôn ngữ lập trình để phát triển các ứng dụng đồ họa như: JTK+, Qt,
Ngày nay, Linux được phân ra làm nhiều nhánh như: Ubuntu, Linux Mint, Fedora,… Được sử dụng thông dụng nhất hiện nay đang là Ubuntu
Hình 1.1 Hệ điều hành Linux
1.1.2 Cấu trúc hệ điều hành Linux
Cấu trúc của hệ điều hành Linux bao gồm nhân Linux là lõi, Shell là giao diện giữa người dùng và hệ thống, và các ứng dụng là các chương trình mà người dùng chạy trên hệ điều hành để thực hiện các tác vụ cụ thể
✓ Nhân Linux (Linux Kernel) là lõi của hệ điều hành Linux Nó là phần chịu trách nhiệm trực tiếp cho việc quản lý tài nguyên phần cứng và cung cấp các dịch vụ cho các chương trình ứng dụng
✓ Nhiệm vụ chính của nhân bao gồm quản lý tiến trình, quản lý bộ nhớ, quản lý tập tin, giao tiếp với thiết bị phần cứng và cung cấp các dịch vụ hệ thống
✓ Shell là giao diện giữa người dùng và hệ điều hành Linux Nó cho phép người dùng tương tác với hệ thống thông qua dòng lệnh hoặc giao diện đồ họa
✓ Shell cũng là một ngôn ngữ lập trình kịch bản, cho phép người dùng viết các tập lệnh để tự động hóa công việc hoặc thực hiện các tác vụ phức tạp hơn Ứng dụng (Applications):
✓ Các ứng dụng là các chương trình mà người dùng chạy trên hệ điều hành Linux để thực hiện các nhiệm vụ cụ thể
✓ Ứng dụng có thể là các tiện ích dòng lệnh (command – line utilities) hoặc ứng dụng đồ họa (graphical applications)
✓ Các ứng dụng có thể thực hiện nhiều chức năng khác nhau, từ xử lý văn bản, duyệt web, gửi email, đến phát triển phần mềm và quản lý dữ liệu
Hình 1.2 Cấu trúc hệ điều hành Linux
1.1.3 Ưu và nhược điểm của hệ điều hành Linux
Hệ điều hành Linux có nhiều ưu điểm như tính mã nguồn mở, bảo mật và ổn định cao, khả năng tùy chỉnh và hiệu suất cao, nhưng vẫn có một số nhược điểm như độ dễ sử dụng, hỗ trợ ứng dụng, hỗ trợ phần cứng và yêu cầu kiến thức kỹ thuật Ưu điểm của hệ điều hành Linux:
✓ Mã nguồn mở (Open Source): Linux là một hệ điều hành mã nguồn mở, điều này có nghĩa là mã nguồn của nó có thể được xem xét, sửa đổi và phân phối miễn phí Điều này tạo điều kiện cho sự linh hoạt và sự phát triển không giới hạn từ cộng đồng lập trình viên trên toàn thế giới
✓ Bảo mật và ổn định: Linux nổi tiếng với tính bảo mật và ổn định cao Cộng đồng lập trình viên luôn cập nhật và vá lỗi hệ thống, giúp người dùng tránh khỏi các lỗ hổng bảo mật và các vấn đề không mong muốn khác
Tổng quan về lập trình Shell
Lập trình Shell là quá trình viết các tập lệnh hoặc scripts sử dụng ngôn ngữ lập trình shell để thực hiện các tác vụ trên hệ điều hành Unix – like (bao gồm cả Linux) Shell scripting cho phép người dùng tự động hóa các công việc hằng ngày, thực hiện
8 các tác vụ hệ thống phức tạp, và tương tác với các chương trình và dịch vụ khác trên hệ thống
Một số khái niệm cơ bản trong lập trình shell bao gồm:
✓ Shell: Là môi trường hoạt động nơi người dùng nhập các lệnh và chạy các scripts Các shell phổ biến nhất trong Unix – like là Bash (Bourne Again Shell), cùng với sh, csh, ksh và zsh
✓ Tập lệnh (Script): Là một tập hợp các lệnh và các câu lệnh điều kiện được viết trong một tập tin văn bản để thực hiện một loạt các tác vụ nhất định
✓ Biến (Variables): Được sử dụng để lưu trữ dữ liệu và giá trị tạm thời trong quá trình thực thi script
✓ Câu lệnh (Commands): Là các hành động được thực thi bởi shell, bao gồm các lệnh hệ thống như ls, mkdir, rm, và cũng có thể là các ứng dụng hoặc các tập lệnh khác
✓ Cấu trúc điều khiển (Control Structures): Bao gồm các cấu trúc như điều kiện (if, elif, else), vòng lặp (for, while) để điều khiển luồng thực thi của script
✓ Đối số (Arguments): Là các giá trị được truyền vào script khi nó được gọi, giúp tạo ra các script linh hoạt và tái sử dụng được
Lập trình shell có thể được sử dụng cho nhiều mục đích, bao gồm quản lý file, tự động hóa công việc, xử lý dữ liệu và tương tác với hệ thống và các ứng dụng khác Điều này giúp tiết kiệm thời gian và giảm thiểu sai sót trong quá trình thao tác và quản lý hệ thống
1.2.2 Các loại Shell thông dụng
Lập trình Shell là quá trình tạo ra các tập lệnh (scripts) để thực thi các tác vụ trên hệ thống thông qua môi trường dòng lệnh của hệ điều hành Shell scripting thường sử dụng các ngôn ngữ lập trình như Bash (Bourne Again Shell), Zsh (Z Shell), Fish (Friendly Interactive Shell), hoặc các phiên bản khác của các shell để tạo ra các tập lệnh có thể tự động hóa các tác vụ, thực hiện chuỗi lệnh, xử lý dữ liệu, và thực hiện các thao tác hệ thống khác
Các loại shell thông dụng bao gồm:
✓ Bash (Bourne Again Shell): Bash là một trong những shell phổ biến nhất và thường được mặc định trên hầu hết các hệ thống Linux Nó là một phiên bản mở rộng của Bourne Shell (sh), với nhiều tính năng tiện ích và dễ sử dụng hơn
✓ Zsh (Z Shell): Zsh là một shell mạnh mẽ và linh hoạt, cung cấp nhiều tính năng tiên tiến hơn so với Bash như tự hoàn thành (auto – completion), các themes và plugins, và nhiều tính năng khác
✓ Fish (Friendly Interactive Shell): Fish là một shell dòng lệnh hiện đại, được thiết kế để có trải nghiệm người dùng tốt nhất với giao diện thân thiện và tính năng tự động hoàn thành thông minh
✓ Dash (Debian Almquist Shell): Dash là một shell nhỏ gọn và tối ưu được sử dụng trong môi trường hệ thống Linux như Debian và Ubuntu Nó được biết đến với tốc độ thực thi nhanh và sử dụng ít tài nguyên hệ thống
✓ Ksh (Korn Shell): Ksh là một shell mạnh mẽ và phổ biến, cung cấp nhiều tính năng mở rộng so với Bourne Shell
Mỗi loại shell có các tính năng và cú pháp riêng biệt, phù hợp cho các mục đích và yêu cầu sử dụng khác nhau Người dùng có thể chọn loại shell phù hợp nhất với nhu cầu và kỹ năng lập trình của mình
Shell là một phần quan trọng của hệ thống điều hành Linux, cung cấp giao diện tương tác giữa người dùng và hệ thống, cho phép thực thi các lệnh, quản lý tiến trình, thực hiện các tập lệnh tự động, và thực hiện nhiều chức năng khác Shell có nhiều chức năng quan trọng trong hệ thống điều hành Linux, bao gồm:
✓ Tương tác với người dùng: Shell cung cấp một giao diện dòng lệnh cho người dùng để tương tác với hệ thống Người dùng có thể nhập lệnh và nhận kết quả ngay lập tức từ hệ thống
✓ Thực thi các lệnh: Shell thực thi các lệnh mà người dùng nhập vào Điều này bao gồm thực hiện các lệnh hệ thống như quản lý tập tin, chạy chương trình, quản lý tiến trình, và nhiều hơn nữa
✓ Quản lý tiến trình (Process Management): Shell cho phép người dùng quản lý các tiến trình trên hệ thống Các lệnh như ps, top, kill được sử dụng để liệt kê, kiểm soát và kết thúc các tiến trình
Tổng quan về Linux Kernel
Linux Kernel là một phần cốt lõi của hệ điều hành Linux, là một chương trình máy tính cung cấp giao tiếp trực tiếp với phần cứng và quản lý tài nguyên phần cứng
Nó là trái tim của hệ thống Linux, đảm bảo hoạt động của các phần mềm và cung cấp các dịch vụ cho người dùng và các ứng dụng khác
1.3.2 Chức năng của Linux Kernel
Linux Kernel chịu trách nhiệm quản lý và điều phối các tài nguyên của hệ thống, cung cấp giao diện cho các ứng dụng và người dùng sử dụng để tương tác với phần cứng và các tài nguyên hệ thống Linux Kernel có nhiều chức năng quan trọng trong hệ thống điều hành Linux, bao gồm:
✓ Quản lý tiến trình (Process Management): Kernel quản lý việc tạo, quản lý và lập lịch cho các tiến trình trên hệ thống Nó cung cấp các cơ chế cho việc tạo tiến trình mới, xử lý việc chuyển đổi giữa các tiến trình, quản lý bộ nhớ và ngắt, cũng như điều phối tài nguyên giữa các tiến trình
✓ Quản lý bộ nhớ (Memory Management): Kernel quản lý việc phân bổ và sử dụng bộ nhớ trên hệ thống Nó quản lý bộ nhớ ảo, bộ nhớ vật lý, và các phân trang bộ nhớ để đảm bảo rằng mỗi tiến trình có quyền truy cập vào bộ nhớ một cách an toàn và hiệu quả
✓ Quản lý File System: Kernel quản lý hệ thống tập tin trên hệ thống Nó cung cấp giao diện cho việc tạo, đọc, ghi và xóa các tập tin và thư mục trên các hệ thống tập tin được gắn kết Kernel hỗ trợ nhiều hệ thống tập tin như EXT4, Btrfs, XFS, NTFS, và nhiều hơn nữa
✓ Quản lý thiết bị (Device Management): Kernel quản lý các thiết bị phần cứng trên hệ thống, bao gồm các ổ đĩa, bàn phím, màn hình, card mạng và
11 các thiết bị ngoại vi khác Nó cung cấp giao diện cho việc truy cập vào các thiết bị này thông qua các driver thiết bị
✓ Quản lý mạng (Networking): Kernel triển khai các giao thức mạng như TCP/IP, UDP, và ICMP để hỗ trợ kết nối mạng Nó cung cấp giao diện cho việc tạo và quản lý các kết nối mạng, cũng như thực hiện các giao tiếp mạng qua các card mạng
✓ Bảo Mật: Kernel cung cấp các cơ chế bảo mật để bảo vệ hệ thống khỏi các mối đe dọa Điều này bao gồm kiểm soát quyền truy cập tập tin, quản lý người dùng và nhóm, và thiết lập các chính sách bảo mật khác
✓ Quản lý tài nguyên hệ thống (System Resource Management): Kernel quản lý và phân phối các tài nguyên hệ thống như CPU, bộ nhớ, I/O và mạng giữa các tiến trình và ứng dụng trên hệ thống Điều này bao gồm việc quản lý lịch trình CPU, bộ đệm I/O, và các khối nhớ được chia sẻ
XÂY DỰNG CHƯƠNG TRÌNH
Lập trình Shell
2.1.1.1 Phân tích thiết kế Đối với chức năng quản lý file, chúng em tìm hiểu và phân tích ra bảy chức năng chính liên quan đến file bao gồm:
Chức năng Mô tả Cách thực hiện
Hiển thị danh sách file Chức năng này sẽ tiến hành thực hiện hiển thị tất cả các file và thư mục có trong folder hiện tại
Thực hiện bằng cách sử dụng chương trình ls ở trong linux
Tạo file mới Chức năng này sẽ tiến hành tạo ra file ở trong thư mục hiện tại và sử dụng tên được truyền vào làm tên file
Thực hiện bằng cách sử dụng chương trình touch ở trong linux
Xoá file Chức năng này sẽ tiến hành xoá file ở trong thư mục hiện tại
Thực hiện bằng cách sử dụng chương trình rm ở trong linux
Chỉnh sửa file Chức năng này sẽ tiến hành mở trình soạn thảo trên file, cho phép thực hiện chỉnh sửa nội dung file
Thực hiện bằng cách sử dụng chương trình vim ở trong linux
Hiển thị nội dung file Chức năng này sẽ tiến hành hiển thị nội dung của file lên console
Thực hiện bằng cách sử dụng chương trình cat ở trong linux
Thay đổi thuộc tính file Chức năng này cho phép người dùng thay đổi thuộc tính của một file, bao gồm chỉ đọc (chỉnh sửa quyền ghi), chỉ ghi (chỉnh sửa
Thực hiện bằng cách thay đổi quyền bằng lệnh chmod và mv để chuyển thành file ẩn
13 quyền đọc), chuyển đổi file thành file ẩn
Nén file Chức năng này cho phép người dùng nén một file trên hệ thống Linux
Thực hiện bằng cách sử dụng lệnh tar với các tuỳ chọn -czf để nén file thành một file tar.gz
Bảng 2.1 Mô tả các chức năng của Quản lý file
#Hàm hiển thị danh sách file display_files () { echo "Danh sách các file:" ls -l echo " "
#Tạo file mới create_file () { echo "Nhập tên file mới:" read filename touch $filename echo "File $filename đã được tạo." echo " "
#Xóa file delete_file () { echo "Nhập tên file cần xóa:" read filename rm -i $filename echo "File $filename đã được xóa." echo " "
#Chỉnh sửa file edit_file () { echo "Nhập tên file cần chỉnh sửa:"
14 read filename nano $filename echo "File $filename đã được chỉnh sửa." echo " "
#Hiển thị nội dung file display_file_content () { echo "Nhập tên file cần xem nội dung:" read filename cat $filename echo " "
#Thay đổi thuộc tính file change_file_attribute () { echo "Nhập tên file cần thay đổi thuộc tính:" read filename while true do echo "Chọn loại thuộc tính muốn thay đổi:" echo "1 Chỉ đọc" echo "2 Chỉ ghi" echo "3 File ẩn" echo "4 Thoát" read attribute_choice case $attribute_choice in
1) chmod u-w $filename #Loại bỏ quyền ghi của người dùng echo "Đã thay đổi thuộc tính của $filename thành chỉ đọc." echo " "
2) chmod u-r $filename #Loại bỏ quyền đọc của người dùng echo "Đã thay đổi thuộc tính của $filename thành chỉ ghi." echo " "
3) mv $filename $filename #Chuyển file thành file ẩn echo "Đã chuyển $filename thành file ẩn."
4) echo "Thoát chương trình" echo " " break
*) echo "Lựa chọn không hợp lệ" echo " "
#Nén file compress_file () { echo "Nhập tên file hoặc thư mục cần nén:" read input_name echo "Nhập tên cho file nén:" read output_name if [ -f "$input_name" ]; then tar -czf "$output_name.tar.gz" "$input_name" echo "Đã nén $input_name thành $output_name.tar.gz" else echo "Không tìm thấy $input_name" fi echo " "
} while true do echo "===============MENU===============" echo "Chọn một trong các chức năng sau:" echo "1 Hiển thị danh sách file" echo "2 Tạo file mới" echo "3 Xóa file" echo "4 Chỉnh sửa file" echo "5 Hiển thị nội dung file"
16 echo "6 Thay đổi thuộc tính file" echo "7 Nén file" echo "8 Thoát" read choice case $choice in
8) echo "Thoát chương trình!!!" echo " " break ;;
*) echo "Lựa chọn không hợp lệ" echo " "
2.1.1.3 Kết quả thực thi chương trình
17 Hình 2.1 Chức năng Hiển thị danh sách file
Hình 2.2 Chức năng Tạo file mới
Hình 2.3 Chức năng Xoá file
Hình 2.4 Chức năng Chỉnh sửa file
Hình 2.5 Chức năng Hiển thị nội dung file
19 Hình 2.6 Chức năng Thay đổi thuộc tính file thành Chỉ đọc
Hình 2.7 Chức năng thay đổi thuộc tính file thành Chỉ ghi và File ẩn
Hình 2.8 Chức năng Nén file
2.1.2.1 Phân tích thiết kế Đối với lập lịch tác vụ chúng em phân tích ra như sau:
Chức năng Mô tả Cách thực hiện
Tạo lập lịch Chức năng này sẽ tiến hành tạo lập lịch tiến trình tuỳ thuộc vào thông tin người dùng nhập vào
Sử dụng chương trình crontab để tạo lập lịch tiến trình
Bảng 2.2 Mô tả các chức năng của Lập lịch tác vụ
# Đặt đường dẫn đến tệp cần tạo filepath="/home/van/bc/shell"
# Đặt lệnh cron job croncmd="touch $filepath"
# Đặt chuỗi công việc định kỳ '00 8 * * *' nghĩa là công việc sẽ chạy vào lúc 8 giờ sáng hàng ngày cronjob="00 8 * * * $croncmd"
# Thêm công việc định kỳ mới vào danh sách công việc định kỳ hiện tại
# In thông báo xác nhận echo "Đã thêm lịch trình tạo tệp vào 8:00 sáng hàng ngày."
2.1.2.3 Kết quả thực thi chương trình
Hình 2.9 Chức năng Tạo lập lịch
2.1.3 Thiết lập thời gian hệ thống
Chương trình thiết lập thời gian hệ thống được thiết kế thành các chức năng con: Hiển thị thời gian thực, cài đặt thời gian hệ thống, đồng bộ thời gian hệ thống
Chức năng Mô tả Cách thực hiện
Hiển thị thời gian thực Chức năng hiển thị thời gian thực sẽ hiển thị thời gian ngày tháng của hệ thống cũng như múi giờ
Sử dụng chương trình date để thực hiện xem giờ của hệ thống
Cài đặt thời gian hệ thống Chức năng cài đặt thời gian hệ thống được sử dụng để cập nhật lại thời gian ở trong hệ thống
Sử dụng chương trình date để thực hiện sửa thời gian ở trong hệ thống Đồng bộ thời gian hệ thống
Chức năng đồng bộ thời gian hệ thống được sử dụng để tự động cập nhật lại thời gian thực của hệ thống
Sử dụng chương trình ntpdate để thực hiện tự động cập nhật lại thời gian của hệ thống
Bảng 2.3 Mô tả các chức năng của Thiết lập thời gian hệ thống
# Hàm hiển thị thời gian thực function hien_thi_thoi_gian_thuc { date +"%A, %d %B %Y %T %Z" echo " "
# Hàm cài đặt thời gian hệ thống function cai_dat_thoi_gian_he_thong {
# Tạm thời tắt dịch vụ systemd-timesyncd sudo systemctl stop systemd-timesyncd
# Nhập thời gian mới từ người dùng read -p "Nhập thời gian mới (YYYY-MM-DD HH:MM:SS): " thoi_gian_moi
# Kiểm tra định dạng thời gian mới if ! date -d "$thoi_gian_moi" >/dev/null 2>&1; then echo "Định dạng thời gian không hợp lệ Thời gian phải có định dạng YYYY-MM-DD HH:MM:SS" return fi
# Cài đặt thời gian hệ thống bằng timedatectl sudo timedatectl set-time "$thoi_gian_moi"
# Kiểm tra trạng thái và thông tin thời gian hệ thống sudo timedatectl status sudo date -s "$thoi_gian_moi" echo "Đã cập nhật thời gian hệ thống thành công" echo " "
# Hàm tự động cập nhật lại thời gian thực function dong_bo_thoi_gian_he_thong {
# Đồng bộ hóa thời gian với máy chủ thời gian sudo systemctl restart systemd-timesyncd echo "Đã cập nhật thời gian hệ thống từ máy chủ thời gian thành công" echo " "
# Hiển thị menu chức năng và yêu cầu người dùng chọn while true;
23 do echo "============MENU============" echo "1 Hiển thị thời gian thực" echo "2 Cài đặt thời gian hệ thống" echo "3 Đồng bộ thời gian hệ thống" echo "0 Thoát" read -p "Chọn chức năng: " lua_chon case $lua_chon in
1) echo "Thời gian hiện tại là: $(hien_thi_thoi_gian_thuc)"
2) cai_dat_thoi_gian_he_thong
3) dong_bo_thoi_gian_he_thong
0) echo "Cảm ơn bạn đã sử dụng chương trình!!!" echo " " break;
2.1.3.3 Kết quả thực thi chương trình
Hình 2.10 Chức năng Hiển thị thời gian hệ thống
Hình 2.11 Chức năng Cài đặt thời gian hệ thống
Hình 2.12 Chức năng Đồng bộ thời gian hệ thống
2.1.4 Cài đặt/ gỡ bỏ chương trình tự động
Chức năng cài đặt và gỡ bỏ các chương trình tự động, chúng em xây dựng hai chương trình đó là install và uninstall
Chức năng Mô tả Cách thực hiện
Chức năng install sẽ tiến hành cài chương trình được chỉ định
Dùng lệnh sudo apt-get install với cờ -y để tiến hành cài đặt tất cả các gói
Chức năng uninstall sẽ tiến hành gỡ cài đặt chương trình được chỉ định
Dùng lệnh sudo apt-get remove với cờ -y để tiến hành gỡ cài đặt tất cả các gói
Bảng 2.4 Mô tả các chức năng của Cài đặt/gỡ bỏ chương trình tự động
#Nhập tên chương trình và tùy chọn từ người dùng read -p "Nhập tên chương trình:(VD: sl) " program_name read -p "Bạn muốn cài đặt hay gỡ bỏ? (in/un): " action
#Kiểm tra tùy chọn của người dùng và thực hiện hành động tương ứng if [ "$action" = "in" ]; then
#Cài đặt chương trình if sudo apt-get install $program_name; then echo "Đã cài đặt $program_name thành công" else echo "Không thể cài đặt $program_name" fi elif [ "$action" = "un" ]; then
#Gỡ bỏ chương trình if sudo apt-get remove $program_name; then echo "Đã gỡ bỏ $program_name thành công" else echo "Không thể gỡ bỏ $program_name" fi else echo "Tùy chọn không hợp lệ" fi
2.1.4.3 Kết quả thực thi chương trình
Hình 2.13 Chức năng Cài đặt chương trình tự động
Hình 2.14 Chức năng Gỡ bỏ chương trình tự động
Lập trình trong Ubuntu
Chức năng quản lý tiến trình gồm các chức năng: Tạo một tiến trình mới, tạm dừng một tiến trình, tiếp tục một tiến trình đang tạm dừng, kết thúc một tiến trình đang chạy, theo dõi một tiến trình
Chức năng Mô tả Cách thực hiện
Tạo một tiến trình mới Chức năng này sẽ tạo mới một tiến trình mới
Sử dụng lệnh hệ thống fork() để tạo một tiến trình mới
Tạm dừng một tiến trình Chức năng này sẽ tạm dừng một tiến trình
Sử dụng để tạm dừng một tiến trình đang chạy bằng cách sử dụng lệnh hệ thống kill() và gửi tín hiệu SIGSTOP đến tiến trình đó
Tiếp tục một tiến trình đang tạm dừng
Chức năng này sẽ tiếp tục một tiến trình đang tạm dừng
Sử dụng để tiếp tục một tiến trình đang tạm dừng bằng cách sử dụng lệnh kill() và gửi tín hiệu SIGCONT đến tiến trình
Kết thúc một tiến trình đang chạy
Chức năng này sẽ kết thúc một tiến trình đang chạy
Sử dụng để kết thúc một tiến trình đang chạy bằng cách sử dụng lệnh hệ thống kill() và gửi tín hiệu SIGTERM đến tiến trình đó
Theo dõi một tiến trình Chức năng này sẽ theo dõi một tiến trình
Sử dụng để theo dõi trạng thái của một tiến trình đang chạy bằng cách sử dụng hàm waitpid()
Bảng 2.5 Mô tả các chức năng của Quản lý tiến trình
#include int main() { int choice;//Lựa chọn của người dùng int conOrExit;//Lựa chọn tiếp tục, hay thoát chương trình do { printf("\n==========MENU==========\n"); printf("1 Tao mot tien trinh moi\n"); printf("2 Tam dung mot tien trinh\n"); printf("3 Tiep tuc mot tien trinh dang tam dung\n"); printf("4 Ket thuc mot tien trinh dang chay\n"); printf("5 Theo doi mot tien trinh\n"); printf("6 Thoat\n"); printf("Chon: "); scanf("%d", &choice); switch (choice) { case 1: pid_t pid = fork(); if (pid == 0) {//Tien trinh con printf("Tien trinh con da duoc tao "); printf("Tien trinh con se ngu trong 60 giay.\n"); sleep(60); exit(0);
} else if (pid > 0) {//Tien trinh cha printf("Tien trinh cha tiep tuc PID cua tien trinh con: %d\n", pid);
} else { printf("Loi khi tao tien trinh moi.\n");
} break; case 2: printf("Vui long nhap ID cua tien trinh de tam dung: "); pid_t pid_to_suspend; scanf("%d", &pid_to_suspend);
//Sử dụng kill với tín hiệu SIGSTOP để tạm dừng if (kill(pid_to_suspend, SIGSTOP) == -1) { printf("Loi khi tam dung tien trinh.\n");
} else { printf("Tien trinh da duoc tam dung.\n");
} break; case 3: printf("Vui long nhap ID cua tien trinh de tiep tuc: "); pid_t pid_to_resume; scanf("%d", &pid_to_resume);
//Sử dụng kill với tín hiệu SIGCONT để tiếp tục if (kill(pid_to_resume, SIGCONT) == -1) { printf("Loi khi tiep tuc tien trinh.\n");
} else { printf("Tien trinh da duoc tiep tuc.\n");
} break; case 4: printf("Vui long nhap ID cua tien trinh de ket thuc: "); pid_t pid_to_kill; scanf("%d", &pid_to_kill);
//Sử dụng kill với tín hiệu SIGTERM để kết thúc if (kill(pid_to_kill, SIGTERM) == -1) { printf("Loi khi ket thuc tien trinh.\n");
} else { printf("Tien trinh da ket thuc thanh cong.\n");
} break; case 5: printf("Vui long nhap ID cua tien trinh de theo doi: "); pid_t pid_to_monitor; scanf("%d", &pid_to_monitor);
//Sử dụng waitpid để kiểm tra tiến trình đó có đang chạy hay không
//WMOHANG là một cờ để kiểm tra trạng thái của một tiến trình mà không cần chờ đợi nó kết thúc if (waitpid(pid_to_monitor, NULL, WNOHANG) == 0) { printf("Tien trinh dang chay.\n");
} else { printf("Tien trinh da ket thuc.\n");
} break; case 6: printf("Da thoat chuong trinh.\n"); exit(0); default: printf("Vui long chon tuy chon hop le\n");
} printf("\nBan co muon tiep tuc chuong trinh khong\n"); printf("Nhan 1 de tiep tuc\n"); printf("Nhan phim bat ky de thoat\n"); scanf("%d",&conOrExit);
2.2.1.3 Kết quả thực thi chương trình
Hình 2.15 Chức năng Tạo một tiến trình mới
Hình 2.16 Chức năng Tạm dừng một tiến trình
Hình 2.17 Chức năng Tiếp tục một tiến trình đang tạm dừng
Hình 2.18 Chức năng Kết thúc một tiến trình đang chạy
Hình 2.19 Chức năng Theo dõi một tiến trình
Chức năng quản lý file gồm những chức năng nhỏ sau: Hiển thị danh sách file, thêm file mới, cập nhật nội dung của file, xoá file, hiển thị nội dung file, thay đổi thuộc tính file, nén file
Chức năng Mô tả Cách thực hiện
Hiển thị danh sách file
Chức năng này sẽ tiến hành thực hiện hiển thị danh sách file
Sử dụng lệnh ls để hiển thị danh sách file
Chức năng này sẽ tiếnm hành tạo ra file ở trong thư mục hiện tại và sử dụng tên được truyền vào làm tên file
Sử dụng hàm fopen để mở tệp với chế độ w (viết), tạo một tệp mới để viết Nếu tạo thành công, fopen sẽ trả về con trỏ trỏ tới tệp
Cập nhật nội dung của file
Chức năng này sẽ cập nhật nội dung của file bằng trình soạn thảo vim
Sử dụng system thực hiện chuỗi lệnh mở trình soạn thảo vim để cập nhật nội dung của file
Chức năng này sẽ tiến hành xoá file ở trong thư mục hiện tại
Sử dụng hàm revome để xoá file với tên file được nhập
Hiển thị nội dung file Chức năng này sẽ hiển thị nội dung của file
Sử dụng hàm fopen với chế độ r để mở tệp cho việc đọc Dùng vòng lặp
33 while và hàm fgetc để đọc từng ký tự của tệp và sử dụng putchar để in chúng ra
Thay đổi thuộc tính file
Chức năng này sẽ thay đổi thuộc tính của file thành: chỉ đọc, chỉ ghi và file ẩn
Sử dụng hàm chmod với hằng số S_IRUSR đặt quyền chỉ đọc, hằng số S_IWUSR đặt quyền chỉ ghi, đặt thành file ẩn bằng cách thêm dấu “.” vào đầu tên tệp
Chức năng này sẽ nén một file được chọn
Sử dụng system để thực hiện lệnh tar -czf để nén tệp đã chọn
Bảng 2.6 Mô tả các chức năng của Quản lý file
//Menu void display_menu() { printf("\n==========MENU==========\n"); printf("1 Danh sách file\n"); printf("2 Thêm file mới\n"); printf("3 Cập nhập nội dung file\n"); printf("4 Xóa file\n"); printf("5 Hiển thị nội dung file\n"); printf("6 Thay đổi thuộc tính file\n"); printf("7 Nén file\n"); printf("8 Thoát\n"); printf("Nhập lựa chọn: ");
//Hiển thị danh sách file void list_files() { int status = system("ls"); if (status == -1) { printf("Hiển thị danh sách file thất bại.\n");
//Thêm file mới void add_new_file() { char filename[100]; printf("Nhập tên file mới: "); scanf("%s", filename);
FILE *file = fopen(filename, "w"); // Tạo file mới if (file != NULL) { printf("Tạo file mới thành công.\n"); fclose(file);
} else { printf("Tạo file mới thất bại.\n");
//Cập nhật nội dung file void update_file_content() { char filename[100]; printf("Nhập tên file cần chỉnh sửa nội dung: "); scanf("%s", filename); char command[200]; sprintf(command, "vim %s", filename); // Create the vi command system(command); // Execute the vi command
//Xóa file void delete_file() { char filename[100]; printf("Nhập tên file cần xóa: "); scanf("%s", filename); if (remove(filename) == 0) { printf("Xóa file thành công.\n");
} else { printf("Xóa file thất bại.\n");
//Hiển thị nội dung file void display_file_content() { char filename[100]; printf("Nhập tên file cần hiển thị nội dung: "); scanf("%s", filename);
FILE *file = fopen(filename, "r"); //Mở file if (file != NULL) { char c; while ((c = fgetc(file)) != EOF) {//Đọc và in nội dung file putchar(c);
} else { printf("Mở file thất bại.\n");
//Thay đổi thuộc tính file void change_file_attribute() { char filename[256]; int attribute_choice; printf("Nhập tên file cần thay đổi thuộc tính: "); scanf("%255s", filename); //Giới hạn đầu vào ở 255 ký tự while (1) { printf("Chọn loại thuộc tính muốn thay đổi:\n"); printf("1 Chỉ đọc\n"); printf("2 Chỉ ghi\n"); printf("3 File ẩn\n"); printf("4 Thoát\n"); scanf("%d", &attribute_choice); switch (attribute_choice) { case 1: chmod(filename, S_IRUSR); //Quyền truy cập chỉ đọc printf("Đã thay đổi thuộc tính của %s thành chỉ đọc.\n\n", filename); break; case 2:
36 chmod(filename, S_IWUSR); //Quyền truy cập chỉ ghi printf("Đã thay đổi thuộc tính của %s thành chỉ ghi.\n\n", filename); break; case 3: char newname[257]; snprintf(newname,sizeof(newname), ".%s", filename); rename(filename, newname); printf("Đã chuyển %s thành file ẩn.\n\n", filename); break; case 4: printf("Thoát chương trình.\n\n"); return; default: printf("Lựa chọn không hợp lệ.\n\n"); break;
//Nén file void compress_file() { char input_name[256]; char output_name[256]; printf("Nhập tên file hoặc thư mục cần nén: "); scanf("%255s", input_name); printf("Nhập tên cho file nén: "); scanf("%255s", output_name); struct stat st; if (stat(input_name, &st) == 0) { if (S_ISREG(st.st_mode)) { // Kiểm tra xem có phải là file không char command[600]; snprintf(command,sizeof(command), "tar -czf %s.tar.gz %s", output_name, input_name);
//Lưu kết quả trả về từ hàm system int result = system(command); if (result == 0) { printf("Đã nén %s thành %s.tar.gz\n\n", input_name, output_name);
} else { printf("Lỗi khi nén %s\n\n", input_name);
} else { printf("%s không phải là file\n\n", input_name);
} else { printf("Không tìm thấy %s\n\n", input_name);
} int main() { int choice; do { display_menu(); if (scanf("%d", &choice) != 1) { //Kiểm tra xem input có phải là số nguyên printf("Lựa chọn không hợp lệ, mời nhập lại.\n"); while (getchar() != '\n'); //Xóa bỏ ký tự còn lại trong buffer input khi input không hợp lệ continue;//Kết thúc vòng lặp hiện tại và bắt đầu vòng lặp mới } switch (choice) { case 1: list_files(); break; case 2: add_new_file(); break; case 3: update_file_content(); break; case 4: delete_file(); break; case 5: display_file_content(); break; case 6: change_file_attribute(); break; case 7: compress_file(); break;
38 case 8: printf("Thoát chương trình.\n"); break; default: printf("Lựa chọn không hợp lệ Mời thử lại.\n");
2.2.2.3 Kết quả thực thi chương trình
Hình 2.20 Chức năng Hiển thị danh sách file
Hình 2.21 Chức năng Thêm file mới
Hình 2.22 Chức năng Cập nhật nội dung file
Hình 2.23 Chức năng Xoá file
Hình 2.24 Chức năng Hiển thị nội dung file
40 Hình 2.25 Chức năng Thay đổi thuộc tính của file thành Chỉ đọc
Hình 2.26 Chức năng Thay đổi thuộc tính của file thành Chỉ ghi và File ẩn
Chức năng Mô tả Cách thực hiện
Quản lý server Quản lý kết nối và giao tiếp giữa các client
Chạy server trước cùng với cổng được chỉ định
Quản lý client Cho phép người dùng kết nối đến server và tham gia vào phòng chat
Chạy client và nhập địa chỉ IP và cổng của server khi được yêu cầu, nhập tên của client để vào phòng chat
Bảng 2.7 Mô tả Quản lý Socket
#define BUFFER_SZ 2048 static _Atomic unsigned int cli_count = 0; static int uid = 10;
42 struct sockaddr_in address; int sockfd; int uid; char name[32];
} client_t; client_t *clients[MAX_CLIENTS]; pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; void str_overwrite_stdout() { printf("\r%s", "> "); fflush(stdout);
} void str_trim_lf (char* arr, int length) { int i; for (i = 0; i < length; i++) { // trim \n if (arr[i] == '\n') { arr[i] = '\0'; break;
} void print_client_addr(struct sockaddr_in addr){ printf("%d.%d.%d.%d", addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
/* Add clients to queue */ void queue_add(client_t *cl){ pthread_mutex_lock(&clients_mutex);
43 for(int i=0; i < MAX_CLIENTS; ++i){ if(!clients[i]){ clients[i] = cl; break;
} } pthread_mutex_unlock(&clients_mutex);
/* Remove clients to queue */ void queue_remove(int uid){ pthread_mutex_lock(&clients_mutex); for(int i=0; i < MAX_CLIENTS; ++i){ if(clients[i]){ if(clients[i]->uid == uid){ clients[i] = NULL; break;
} pthread_mutex_unlock(&clients_mutex);
/* Send message to all clients except sender */ void send_message(char *s, int uid){ pthread_mutex_lock(&clients_mutex); for(int i=0; iuid != uid){ if(write(clients[i]->sockfd, s, strlen(s)) < 0){ perror("ERROR: write to descriptor failed"); break;
} pthread_mutex_unlock(&clients_mutex);
/* Handle all communication with the client */ void *handle_client(void *arg){ char buff_out[BUFFER_SZ]; char name[32]; int leave_flag = 0; cli_count++; client_t *cli = (client_t *)arg;
// Name if(recv(cli->sockfd, name, 32, 0) = 32-1){ printf("Didn't enter the name.\n"); leave_flag = 1;
} else{ strcpy(cli->name, name); sprintf(buff_out, "%s has joined\n", cli->name); printf("%s", buff_out); send_message(buff_out, cli->uid);
} bzero(buff_out, BUFFER_SZ); while(1){ if (leave_flag) { break;
} int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0); if (receive > 0){ if(strlen(buff_out) > 0){ send_message(buff_out, cli->uid); str_trim_lf(buff_out, strlen(buff_out)); printf("%s -> %s\n", buff_out, cli->name);
} } else if (receive == 0 || strcmp(buff_out, "exit") == 0){ sprintf(buff_out, "%s has left\n", cli->name); printf("%s", buff_out); send_message(buff_out, cli->uid); leave_flag = 1;
} else { printf("ERROR: -1\n"); leave_flag = 1;
} bzero(buff_out, BUFFER_SZ);
/* Delete client from queue and yield thread */ close(cli->sockfd); queue_remove(cli->uid); free(cli); cli_count ; pthread_detach(pthread_self()); return NULL;
} int main(int argc, char **argv){ int port; if(argc != 2){ port = 8888;
} char *ip = "0.0.0.0"; int option = 1; int listenfd = 0, connfd = 0; struct sockaddr_in serv_addr; struct sockaddr_in cli_addr; pthread_t tid;
/* Socket settings */ listenfd = socket(AF_INET, SOCK_STREAM, 0); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(ip); serv_addr.sin_port = htons(port);
/* Ignore pipe signals */ signal(SIGPIPE, SIG_IGN); if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT |
SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){ perror("ERROR: setsockopt failed"); return EXIT_FAILURE;
/* Bind */ if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR: Socket binding failed"); return EXIT_FAILURE;
/* Listen */ if (listen(listenfd, 10) < 0) { perror("ERROR: Socket listening failed"); return EXIT_FAILURE;
} printf("=== WELCOME TO THE CHATROOM ===\n"); while(1){ socklen_t clilen = sizeof(cli_addr); connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen); /* Check if max clients is reached */ if((cli_count + 1) == MAX_CLIENTS){
47 printf("Max clients reached Rejected: "); print_client_addr(cli_addr); printf(":%d\n", cli_addr.sin_port); close(connfd); continue;
/* Client settings */ client_t *cli = (client_t *)malloc(sizeof(client_t)); cli->address = cli_addr; cli->sockfd = connfd; cli->uid = uid++;
/* Add client to the queue and fork thread */ queue_add(cli); pthread_create(&tid, NULL, &handle_client, (void*)cli);
// Global variables volatile sig_atomic_t flag = 0; int sockfd = 0; char name[32]; void str_overwrite_stdout() { printf("%s", "> "); fflush(stdout);
} void str_trim_lf (char* arr, int length) { int i; for (i = 0; i < length; i++) { // trim \n if (arr[i] == '\n') { arr[i] = '\0'; break;
} void catch_ctrl_c_and_exit(int sig) { flag = 1;
} void send_msg_handler() { char message[LENGTH] = {}; char buffer[LENGTH + 32] = {}; while(1) { str_overwrite_stdout(); fgets(message, LENGTH, stdin); str_trim_lf(message, LENGTH); if (strcmp(message, "exit") == 0) { break;
} else { sprintf(buffer, "%s: %s\n", name, message); send(sockfd, buffer, strlen(buffer), 0); } bzero(message, LENGTH);
} void recv_msg_handler() { char message[LENGTH] = {}; while (1) { int receive = recv(sockfd, message, LENGTH, 0); if (receive > 0) { printf("%s", message); str_overwrite_stdout();
Xây dựng mô – đun nhân và tích hợp vào hệ thống
#include int factorial(int n);
56 int matmul(int p, int q, int s, int *a, int *b, int *c); int matadd(int p, int q, int *a, int *b); int primeBetween(int m, int n); int maxandminmatrix(int p, int q, int *a); int numdivisibleinmatrix(int p, int q, int *a, int s); int primeofmat(int p, int q, int *a); int prime(int n); static int choice = 0; static int p, q, s, d; static int a[2500], b[2500], c[2500]; static char message[2500] ; module_param(choice, int, S_IRUGO); module_param(d, int, S_IRUGO); module_param(p, int, S_IRUGO); module_param(q, int, S_IRUGO); module_param(s, int, S_IRUGO); module_param_array(a, int, NULL, S_IRUGO); module_param_array(b, int, NULL, S_IRUGO); module_param_array(c, int, NULL, S_IRUGO); static int p02_init(void)
{ printk(KERN_ALERT "%d! = %d\n", d, factorial(d)); break;
} int matadd(int p, int q, int *a, int *b) { int i, j; for (i = 0; i < p; i++) { for (j = 0; j < q; j++) {
} printk(KERN_ALERT "\n -\nThe sum of 2 matrices is a matrix with height %d and width %d\n",p,q); for (i=0;i