/41
lOMoARcPSD| 61549570
BỘ 200 CÂU HỎI TRẮC NGHIỆM ÔN TẬP LẬP TRÌNH MẠNG
Nội dung 1: Hàm select()
1. Hàm select() trong C được sử dụng chính để làm gì trong lập trình mạng?
A. Khởi tạo một socket mới cho việc truyền dữ liệu.
B. Gửi dữ liệu một cách tuần tự qua nhiều socket.
C. Theo dõi nhiều le descriptor (socket) đồng thời để kiểm tra xem có hoạt động (đọc, ghi,
lỗi) nào xảy ra không.
D. Thiết lập một kết nối TCP an toàn giữa client và server.
2. Tham số nfds trong hàm select() đại diện cho điều gì? A. Tng số le
descriptor có trong tất cả các tập fd_set.
B. Gia tri le descriptor lớn nhất cần theo dõi, cộng thêm 1.
C. Kích thước của cấu trúc fd_set nh bằng byte.
D. Số lượng tối đa các kết nối đồng thời mà select() có thể xử lý.
3. Nếu tham số meout của hàm select() được đặt là NULL, hàm select() sẽ hoạt động như
thế nào?
A. select() sẽ trả về ngay lập tức mà không chờ đợi.
B. select() sẽ chờ vô thời hạn cho đến khi có ít nhất một le descriptor sẵn sàng hoặc có lỗi.
C. select() sẽ sử dụng một giá trị meout mặc định của hệ thống.
D. select() sẽ báo lỗi vì meout không được để là NULL.
4. Giá trị trả về của hàm select() là 0 có ý nghĩa gì? A. Có một lỗi
nghiêm trọng đã xảy ra với hàm select().
B. Không có le descriptor nào được cung cấp để theo dõi.
C. Thời gian chờ (meout) đã hết mà không có le descriptor nào sẵn sàng.
D. Tất cả các le descriptor trong các tập đều đã sẵn sàng.
5. Macro nào được sử dụng để thêm một le descriptor vào một tập fd_set?
A. FD_ZERO(fd, &set)
lOMoARcPSD| 61549570
B. FD_ISSET(fd, &set)
C. FD_SET(fd, &set)
D. FD_CLR(fd, &set)
6. Tại sao cần phải khởi tạo lại các tập fd_set (sử dụng FD_ZERO và FD_SET) trước mỗi lần
gọi lại hàm select() trong một vòng lặp?
A. Đgiải phóng bộ nhớ đã được cấp phát cho các tập fd_set ở lần gọi trước.
B. Vì hàm select() sẽ sửa đổi nội dung của các tập fd_set để chỉ ra những descriptor nào đã
sẵn sàng.
C. Để đảm bảo rằng select() không theo dõi các socket đã bị đóng.
D. Đây là một yêu cầu của chuẩn POSIX để đồng bộ hóa luồng.
7. Hàm FD_ISSET(sockfd, &readfds) được sử dụng để làm gì sau khi select() trả về?
A. Đkiểm tra xem sockfd có phải là một socket hợp lệ không.
B. Để xóa sockfd khỏi tập readfds.
C. Để kiểm tra xem sockfd có nằm trong tập readfds và đã sẵn sàng để đọc hay không.
D. Để thêm sockfd vào tập readfds cho lần gọi select() ếp theo.
8. Tham số readfds trong hàm select() được dùng để chỉ định điều gì?
A. Tập hợp các le descriptor cần kiểm tra xem có thể ghi dữ liệu vào được
không.
B. Tập hợp các le descriptor cần kiểm tra xem có dữ liệu để đọc haykhông.
C. Tập hợp các le descriptor cần kiểm tra các sự kiện ngoại lệ.
D. Tập hợp tất cả các le descriptor đang hoạt động trong hệ thống.
9. Nếu meout.tv_sec = 0 và meout.tv_usec = 0 khi gọi select(), điều gì sẽ xảy ra?
A. select() sẽ chvô thời hạn.
B. select() sẽ kiểm tra trạng thái các FD ngay lập tức rồi trả về, không chờ.
C. select() sẽ báo lỗi vì meout bằng 0.
D. select() sẽ chờ một khoảng thời gian tối thiểu do hệ thống quy định.
10. Giá trị trả về -1 từ select() thường cho biết điều gì? A. Timeout đã xảy ra.
lOMoARcPSD| 61549570
B. Không có FD nào sẵn sàng.
C. Có lỗi xy ra (ví dụ: signal ngắt hoặc lỗi khi truyền FD).
D. Một FD đã được đóng.
11. Trong struct meval, trường tv_usec quy định đơn vị thời gian là gì?
A. Giây.
B. Mili giây.
C. Micro giây.
D. Nano giây.
12. Mục đích chính của việc sử dụng select() trong các ứng dụng mạng phi đồng bộ là gì?
A. Để tăng tốc độ truyền dữ liệu qua mạng.
B. Để quản lý nhiều kết nối mà không cần tạo nhiều luồng hoặc ến
trình.
C. Để mã hóa dữ liệu truyền đi.
D. Để tự động cân bằng tải giữa các server.
13. Macro FD_CLR(sockfd, &fdset) dùng để làm gì? A. Xóa tất cả các FD
khỏi tập fdset.
B. Thêm sockfd vào tập fdset.
C. Xóa sockfd khỏi tập fdset.
D. Kiểm tra xem sockfd có trong fdset không.
14. "fds_bits" trong cấu trúc fd_set thường được triển khai như thế nào?
A. Một mảng các ký tự.
B. Một danh sách liên kết các socket.
C. Một mảng các số nguyên dài (long int), mỗi bit đại diện cho một
socket.
D. Một cây nhị phân m kiếm các le descriptor.
15. Nếu select() trả về một giá trị lớn hơn 0, giá trị đó biểu thị điều gì?
A. Mã lỗi cụ thể.
lOMoARcPSD| 61549570
B. Số ợng le descriptor đã sẵn sàng cho một thao tác nào đó.
C. Số lượng le descriptor tối đa có thể theo dõi.
D. PID của ến trình đã gây ra sự kin.
16. Khi sử dụng select() để theo dõi nhiều socket, tham số nfds nên được nh như thế nào
nếu sockfd1, sockfd2, và sockfd3 là các socket đang được theo dõi?
A. sockfd1 + sockfd2 + sockfd3 + 1
B. max(sockfd1, sockfd2, sockfd3) + 1
C. 3 (tổng số socket)
D. FD_SETSIZE
17. Trong ví dụ minh họa của select(), hàm listen() được gọi với mục đích gì?
A. Đchấp nhận một kết nối mới từ client.
B. Để gán địa chỉ IP và cổng cho socket.
C. Để đặt socket ở trạng thái sẵn sàng lắng nghe các yêu cầu kết nốến.
D. Để gửi dữ liệu đến client.
18. Lưu ý nào sau đây là KHÔNG ĐÚNG khi sử dụng select()? A. nfds là FD lớn nhất
cộng 1.
B. Phải khởi tạo lại các tập FD mỗi lần trước khi gọi select().
C. select() sẽ tự động xóa các FD đã đóng khỏi các tập FD.
D. meout có thể dùng để tránh bị block vô thời hạn.
19. Nếu bạn muốn select() kiểm tra khả năng ghi trên socket_ghi và khả năng đọc trên
socket_doc, bạn sẽ:
A. Đặt cả socket_ghi và socket_doc vào readfds.
B. Đặt socket_ghi vào writefds và socket_doc vào readfds.
C. Đặt cả socket_ghi và socket_doc vào excepds.
D. Đặt socket_ghi vào readfds và socket_doc vào writefds.
20. Trong đoạn FD_SET(3, &fdset); FD_SET(4, &fdset);, nếu fdset.fds_bits[0] có giá trị 24,
điều này có nghĩa là gì theo hệ nhị phân? A. Bit thứ 3 và bit thứ 4 được set (ví dụ: ...00011000).
lOMoARcPSD| 61549570
B. Chỉ bit thứ 24 được set.
C. Bit thứ 2 và bit thứ 4 được set.
D. Các bit từ 0 đến 23 đều được set.
Nội dung 2: Hàm poll() và cấu trúc pollfd
21. Hàm poll() cung cấp giải pháp thay thế cho select() với ưu điểm nổi bật nào?
A. Luôn nhanh hơn select() bất kể số lượng FD.
B. Không bị gii hạn bởi FD_SETSIZE (thường là 1024 FD).
C. Sử dụng ít bộ nhớ hơn select().
D. Chhoạt động trên Linux.
22. Trong cấu trúc pollfd, trường nào được sử dụng để chỉ định các sự kiện mà người dùng
muốn theo dõi trên một le descriptor?
A. fd
B. events
C. revents
D. status
23. Tham số meout của hàm poll() được nh bằng đơn vị nào? A. Giây (seconds).
B. Micro giây (microseconds).
C. Mili giây (milliseconds).
D. Nano giây (nanoseconds).
24. Giá trị trả về 0 từ hàm poll() có ý nghĩa gì? A. Có lỗi xảy ra
trong quá trình gọi hàm.
B. Không có le descriptor nào được cung cấp để theo dõi.
C. Hết thời gian chờ (meout) nhưng không có FD nào sẵn sàng.
D. Một FD đã sẵn sàng.
25. Cờ sự kiện POLLIN trong trường events hoặc revents của struct pollfd cho biết điều gì?
A. Có thể ghi dữ liệu vào FD mà không bị block.
B. Dữ liệu đã sẵn sàng để đọc từ FD.
lOMoARcPSD| 61549570
C. lỗi xảy ra trên FD.
D. FD không hợp lệ.
26. Sau khi hàm poll() trả về, trường nào trong struct pollfd cho biết sự kiện thực tế đã xy
ra trên le descriptor tương ứng?
A. fd
B. events
C. revents
D. result
27. Nếu muốn poll() chờ vô thời hạn cho đến khi có sự kiện xảy ra, giá trị nào nên được
truyền cho tham số meout?
A. 0
B. -1
C. NULL
D. Một giá trị dương rất lớn.
28. Cờ sự kiện POLLOUT dùng để theo dõi sự kiện gì? A. Dữ liệu đến từ
FD.
B. Khả năng ghi dữ liệu vào FD mà không bị block.
C. Kết nối bị đóng bởi đầu kia.
D. File descriptor đã được mở.
29. Để theo dõi đồng thời sự kiện đọc và lỗi trên một socket sockfd bằng poll(), trường
events của struct pollfd tương ứng nên được thiết lập như thế nào?
A. fds[0].events = POLLIN; fds[0].events = POLLERR;
B. fds[0].events = POLLIN | POLLERR;
C. fds[0].events = POLLIN & POLLERR;
D. fds[0].events = POLLIN; và kiểm tra lỗi riêng.
30. Nếu trường revents của một struct pollfd chứa cờ POLLNVAL sau khi poll() được gọi,
điều này có nghĩa là gì? A. Dữ liệu không hợp lệ đã được nhận.
B. File descriptor (fd) không hợp lệ (ví dụ: chưa mở hoặc đã đóng).
lOMoARcPSD| 61549570
C. Yêu cầu không hợp lệ.
D. Không có sự kiện nào xảy ra.
31. Khi sử dụng poll(), làm thế nào để yêu cầu poll() bỏ qua một phần tử cụ thể trong mảng
pollfd[] mà không cần xóa nó khỏi mảng? A. Đặt trường events của phần tử đó thành 0.
B. Đặt trường fd của phần tử đó thành một giá trị âm (ví dụ: -1).
C. Đặt trường revents của phần tử đó thành POLLNVAL.
D. Giảm giá trị của tham số nfds đi 1.
32. So với select(), poll() KHÔNG có nhược điểm nào sau đây? A. Khó khăn khi xử lý
số lượng FD vượt quá FD_SETSIZE.
B. Cấu trúc lưu trữ phc tạp hơn (bitmask).
C. Phải khởi tạo lại toàn bộ mảng pollfd sau mỗi lần gọi.
D. Hiệu suất giảm dần khi số lượng FD quá lớn.
33. Sự kiện POLLHUP trong revents thường chỉ ra điều gì? A. Dữ liệu khẩn cấp
đã đến.
B. FD đã sẵn sàng để ghi.
C. Đầu kia của kết nối đã đóng (hung up).
D. Một lỗi hthống đã xảy ra.
34. Trong ví dụ theo dõi một socket và stdin bằng poll(), fds[0].fd = 0; có ý nghĩa gì?
A. File descriptor 0, thường là đầu vào chuẩn (stdin).
B. Socket đầu ên được tạo.
C. Bỏ qua le descriptor này.
D. Chỉ ra đây là socket lắng nghe.
35. Giá trị trả về của poll() là số dương có ý nghĩa gì? A. Số lượng FD có lỗi.
B. Số ợng FD sẵn sàng cho thao tác (có sự kiện trong revents).
C. Mã lỗi cụ thể.
D. Số mili giây đã chờ.
36. Header le cần thiết để sử dụng hàm poll() là gì?
lOMoARcPSD| 61549570
A. <sys/select.h>
B. <sys/poll.h>
C. <poll.h>
D. <unistd.h>
37. Tham số nfds trong hàm poll(struct pollfd fds[], nfds_t nfds, int meout) là gì?
A. File descriptor lớn nhất cộng 1.
B. Tổng số le descriptor trong hệ thống.
C. Số ợng phần tử trong mảng fds[] cần được theo dõi.
D. Kích thước tối đa của mảng fds[].
38. Nếu poll() trả về -1, điều gì có khả năng đã xảy ra? A. Timeout.
B. Không có FD nào sẵn sàng.
C. Một lỗi đã xảy ra (ví dụ, tham số không hợp lệ).
D. Một FD đã được đóng bởi client.
39. Khi muốn kiểm tra ngay lập tức trạng thái của các FD mà không chờ đợi, tham số
meout của poll() nên được đặt là bao nhiêu?
A. -1
B. 0
C. 1
D. 1000
40. Trong mảng struct pollfd fds[], nếu fds[i].revents & POLLIN là true, điều này có
nghĩa là: A. Đã xảy ra lỗi trên fds[i].fd.
B. fds[i].fd sẵn sàng để ghi.
C. Có dữ liệu để đọc trên fds[i].fd.
D. fds[i].fd là một FD không hợp lệ.
Nội dung 3: Đa ến trình với fork()
41. Hàm fork() được sử dụng để làm gì?
A. Tạo một luồng mới trong ến trình hiện tại.
lOMoARcPSD| 61549570
B. Tạo một ến trình con mới, là bản sao của ến trình cha.
C. Thực thi một chương trình mới thay thế ến trình hiện tại.
D. Chờ một ến trình con kết thúc.
42. Sau khi fork() được gọi thành công, giá trị trả về trong ến trình con là gì?
A. PID (Process ID) của ến trình cha.
B. PID (Process ID) của chính nó (ến trình con).
C. 0.
D. -1.
43. Trong ến trình cha, giá trị trả về của fork() khi tạo ến trình con thành công là gì? A. 0.
B. PID (Process ID) của ến trình con vừa được tạo.
C. PID (Process ID) của chính nó (ến trình cha).
D. Một giá trị âm.
44. Nếu fork() trả về -1, điều đó có nghĩa là gì? A. Tiến trình
con đã kết thúc thành công.
B. Tiến trình cha đã kết thúc.
C. Không thể tạo được ến trình con (có lỗi xảy ra).
D. Đây là ến trình con.
45. Sau khi fork() được gọi, không gian bộ nhớ của ến trình cha và ến trình con như thế nào?
A. Chúng chia sẻ cùng một không gian bộ nhớ hoàn toàn.
B. Tiến trình con có không gian bộ nhớ riêng biệt, được sao chép từ ến trình cha tại thời
điểm fork().
C. Chỉ có vùng mã lệnh (text segment) được chia sẻ, vùng dữ liệu (data segment) thì riêng biệt.
D. Tiến trình cha và con giao ếp qua một vùng nhớ chia sẻ đặc biệt do fork()tạo ra.
46. Hiện tượng "zombie process" xảy ra khi nào?
A. Khi một ến trình con cố gắng truy cập vào bộ nhớ của ến trình cha.
B. Khi ến trình cha kết thúc trước ến trình con.
lOMoARcPSD| 61549570
C. Khi ến trình con đã kết thúc nhưng ến trình cha chưa thu thập trạng thái kết thúc của
nó (chưa gọi wait() hoặc waitpid()).
D. Khi một ến trình không thể tạo thêm ến trình con do hết tài nguyên.
47. Trong mô hình server đa ến trình sử dụng fork(), sau khi một kết nối client được accept(),
ến trình con thường làm gì với socket lắng nghe (listening socket)?
A. Tiếp tục sử dụng socket lắng nghe để chấp nhận thêm client.
B. Đóng socket lắng nghe vì nó không cần thiết cho việc xử lý client cụ thể này.
C. Gọi listen() trên socket lắng nghe một lần nữa.
D. Chuyển socket lắng nghe cho một ến trình khác.
48. Tương tự, trong mô hình server đa ến trình, ến trình cha thường làm gì với socket kết nối
của client (client socket) sau khi đã fork() ra ến trình con để xử lý client đó?
A. Tiếp tục đọc ghi dữ liệu vi client trên socket đó.
B. Đóng socket kết nối của client vì ến trình con sẽ đảm nhận việc này.
C. Chuyển socket đó cho một ến trình con khác.
D. Chờ ến trình con xử lý xong rồi mới đóng.
49. Hàm nào thường được ến trình cha sử dụng để đợi và thu thập trạng thái kết thúc của một
ến trình con, nhằm tránh zombie process?
A. fork()
B. exit()
C. wait() hoặc waitpid()
D. kill()
50. Nếu một đoạn mã gọi fork() hai lần liên ếp, tổng cộng sẽ có bao nhiêu ến trình được
tạo ra (bao gồm cả ến trình ban đầu)? A. 2 ến trình. B. 3 ến trình.
C. 4 ến trình.
D. 5 ến trình.
51. File descriptor của socket được mở trước khi gọi fork() sẽ như thế nào trong ến trình cha
và con?
A. Chỉ ến trình cha giữ lại le descriptor đó.
lOMoARcPSD| 61549570
B. Chỉ ến trình con giữ lại le descriptor đó.
C. Cả ến trình cha và con đều có bản sao của le descriptor đó, và chúng trỏ đến cùng một
đối tượng le trong kernel.
D. File descriptor sẽ bị đóng tự động trong cả hai ến trình.
52. Điều kiện nào sau đây thường được dùng trong mã nguồn để xác định đoạn mã nào sẽ
được thực thi bởi ến trình con?
A. if (fork() > 0)
B. if (pid == 0) (sau khi pid = fork();)
C. if (fork() < 0)
D. if (fork() != 0)
53. "Fork bomb" là hiện tượng gì?
A. Một lỗi trong hàm fork() khiến hệ thống bị treo.
B. Việc một ến trình liên tục tạo ra các ến trình con một cách không kiểm soát, dẫn đến
cạn kiệt tài nguyên hệ thống. C. Việc gửi một lượng lớn yêu cầu fork() đến một server từ
xa.
D. Một ến trình con cố gng "giết" ến trình cha của nó.
54. Header le nào cần được bao gồm để sử dụng hàm fork()?
A. <sys/socket.h>
B. <stdio.h>
C. <unistd.h>
D. <sys/wait.h>
55. Trong đoạn mã: fork(); fork(); prin("Hello\n");, "Hello" sẽ đưc in ra bao nhiêu
lần? A. 1 lần. B. 2 lần. C. 3 lần.
D. 4 lần.
56. Lợi ích chính của việc sử dụng mô hình server đa ến trình (mỗi client một ến trình) là gì?
A. Tiết kiệm bộ nhớ hơn mô hình đa luồng.
B. Xử lý đồng thời nhiều client, mỗi client được phục vụ bởi một ến trình riêng biệt, tăng
nh độc lập.
lOMoARcPSD| 61549570
C. Khởi tạo ến trình nhanh hơn khởi tạo luồng.
D. Dễ dàng chia sẻ dữ liệu giữa các client hơn.
57. Để tránh zombie process mà không cần wait() hoặc waitpid(), một cách là gì?
A. Tiến trình con gọi exit(0) ngay lập tức.
B. Tiến trình cha đặt cờ SIGCHLD thành SIG_IGN. (Đáp án B của câu trắc nghiệm gốc)
C. Tiến trình cha gọi sleep() một lúc lâu.
D. Sử dụng pthread_detach() cho ến trình con.
58. Biến toàn cục được khai báo trước khi gọi fork() sẽ như thế nào trong ến trình cha và con?
A. Chỉ ến trình cha có thể truy cập.
B. Chỉ ến trình con có thể truy cập.
C. Cả hai cùng chia sẻ và thay đổi của một ến trình sẽ ảnh hưởng đến ến trình kia.
D. Mỗi ến trình có một bản sao riêng của biến toàn cục đó, thay đổiở ến trình này không
ảnh hưởng đến ến trình kia.
59. Lệnh waitpid(-1, NULL, WNOHANG) có ý nghĩa gì?
A. Chờ một ến trình con bất kỳ kết thúc, block cho đến khi có con kết thúc.
B. Chờ một ến trình con cụ thkết thúc, không block.
C. Chờ một ến trình con bất kỳ kết thúc, không block (trả về ngay nếu không có con nào kết
thúc).
D. Gửi n hiệu WNOHANG đến tất cả ến trình con.
60. Trong một server đa ến trình, nếu ến trình cha không đóng socket của client sau khi fork,
điều gì có thể xảy ra?
A. Client sẽ không thể gửi dữ liệu.
B. Tiến trình con sẽ không thể nhận dữ liệu.
C. Có thể gây rò rỉ tài nguyên le descriptor nếu server chạy lâu dài và xử lý nhiều client.
D. Kết nối sẽ tự động đóng sau một khoảng thời gian.
Nội dung 4: Lập trình mạng đa luồng với pthread
lOMoARcPSD| 61549570
61. Luồng (thread) là gì?
A. Một ến trình (process) độc lập hoàn toàn.
B. Đơn vị xử lý nhỏ nhất trong một ến trình, có thể chạy song song với các luồng khác trong
cùng ến trình. C. Một cơ chế giao ếp giữa các ến trình.
D. Một bản sao của ến trình cha.
62. Các luồng trong cùng một ến trình chia sẻ những tài nguyên nào sau đây?
A. Không gian địa chỉ bộ nhớ (bao gồm biến toàn cục, heap), le descriptor.
B. Chỉ có con trỏ lệnh (instrucon pointer) và thanh ghi.
C. Mỗi luồng có không gian bộ nhớ hoàn toàn tách biệt.
D. Chỉ chia sẻ các biến được khai báo với từ khóa shared.
63. Tài nguyên nào sau đây là RIÊNG BIỆT cho mỗi luồng trong cùng một ến trình?
A. Biến toàn cục.
B. Vùng nhớ heap.
C. Ngăn xếp (stack) dùng cho biến cục bộ và thông n cuộc gọi hàm.
D. Bảng mô tả le (le descriptor table).
64. Hàm nào trong thư viện pthread được sử dụng để tạo một luồng mới?
A. pthread_start()
B. pthread_create()
C. pthread_init()
D. pthread_begin()
65. Tham số thba của hàm pthread_create() (start_roune) có ý nghĩa gì? A. Con trỏ tới
biến kiểu pthread_t để lưu ID của luồng mới.
B. Thuộc nh của luồng mới (ví dụ: detached state, stack size).
C. Con trỏ tới hàm mà luồng mới sẽ bắt đầu thực thi.
D. Tham số sẽ được truyền vào hàm start_roune.
66. Hàm pthread_join(pthread_t thread, void **retval) được sử dụng để làm gì?
A. Để một luồng kết thúc chính nó.
lOMoARcPSD| 61549570
B. Để một luồng chờ một luồng khác (được xác định bởi thread) kết thúc và có thể lấy g
trtrả về của luồng đó. C. Để gộp hai luồng thành một.
D. Để tách một luồng ra khỏi luồng gọi, cho phép nó tự giải phóng tài nguyên khi kết thúc.
67. Khi một luồng được tạo trạng thái "detached" (ví dụ, bằng pthread_detach()), điều gì xảy
ra khi luồng đó kết thúc?
A. Nó sẽ đợi cho đến khi một luồng khác gọi pthread_join() trên nó.
B. Nó sẽ tự động giải phóng tài nguyên của mình mà không cần luồng khác join.
C. Nó sẽ trở thành một zombie thread.
D. Nó sẽ gửi một n hiệu đến luồng chính.
68. "Race condion" (nh trạng tranh chấp) trong lập trình đa luồng xảy ra khi nào?
A. Khi hai luồng cố gắng thực thi cùng một hàm.
B. Khi nhiều luồng cùng truy cập và cố gắng sửa đổi một tài nguyên chia sẻ (ví dụ: biến toàn
cục) mà không có sự đồng bộ hóa thích hợp, dẫn đến kết quả không thể đoán trước.
C. Khi một luồng chạy nhanh hơn một luồng khác đáng kể.
D. Khi một luồng bị block vô thời hạn.
69. Mutex (pthread_mutex_t) được sử dụng để làm gì trong lập trình đa luồng?
A. Để truyền dữ liệu giữa các luồng.
B. Để đảm bảo rằng chỉ một luồng có thể truy cập vào một đoạn mã tới hạn (crical secon)
hoặc tài nguyên chia sẻ tại một thời điểm, tránh race condion.
C. Để tạo ra các luồng mới.
D. Để đặt độ ưu ên cho các luồng.
70. Cặp hàm nào thường được sử dụng để khóa và mở khóa một mutex?
A. pthread_mutex_begin() và pthread_mutex_end()
B. pthread_mutex_wait() và pthread_mutex_signal()
C. pthread_mutex_lock() và pthread_mutex_unlock()
D. pthread_mutex_acquire() và pthread_mutex_release()
71. Làm thế nào để truyền một đối số (ví dụ, một số nguyên) vào hàm thực thi của luồng
(start_roune)?
lOMoARcPSD| 61549570
A. Bằng cách sử dụng biến toàn cục.
B. Truyền trực ếp giá trị vào tham số thứ tư của pthread_create().
C. Truyền địa chỉ của biến chứa đối số (ép kiểu thành void*) vào tham số thứ tư của
pthread_create(), và trong start_roune, ép kiểu ngược lại.
D. pthread không hỗ trợ truyền đối số trực ếp.
72. Hàm pthread_exit(void *retval) được dùng để làm gì? A. Để luồng
chính kết thúc toàn bộ ến trình.
B. Để một luồng tự kết thúc và có thể trả về một giá trị (retval).
C. Để tạm dừng một luồng khác.
D. Để giải phóng mutex.
73. Khi biên dịch một chương trình C sử dụng thư viện pthread trên Linux với GCC, cờ (ag) nào
thường được sử dụng?
A. -lthread
B. -pthreads
C. -lpthread hoặc -pthread
D. -enable-threading
74. Header le nào cần được bao gồm để sử dụng các hàm của thư viện pthread?
A. <thread.h>
B. <threads.h>
C. <pthread.h>
D. <multhread.h>
75. Trong mô hình server đa luồng, khi một kết nối client mới được chấp nhận, server thường
làm gì?
A. Tạo một ến trình con mới bằng fork() để xử lý client.
B. Tạo một luồng mới bằng pthread_create() để xử lý client đó, truyền socket của client làm
đối s.
C. Xử lý client đó ngay trong luồng chính.
D. Đưa client vào một hàng đợi để xử lý tuần tự.
lOMoARcPSD| 61549570
76. Sự khác biệt chính giữa vùng nhớ heap và stack là gì?
A. Stack được quản lý tự động cho biến cục bộ và lời gọi hàm, heap được cấp phát và giải
phóng thủ công bởi lập trình viên.
B. Heap chỉ dùng cho biến toàn cục, stack dùng cho biến cục bộ.
C. Stack có kích thước lớn hơn heap.
D. Heap được chia sẻ giữa các ến trình, stack thì không.
77. Nếu hai luồng cùng cố gắng tăng một biến toàn cục counter mà không dùng mutex, giá
trcuối cùng của counter có thể như thế nào? A. Luôn luôn là tổng số lần tăng từ cả hai luồng.
B. Có thể nhỏ hơn tổng số lần tăng mong đợi do race condion.
C. Luôn luôn bằng 0.
D. Sẽ gây ra lỗi biên dịch.
78. Hàm pthread_mutex_init(pthread_mutex_t *mutex, const
pthread_mutexar_t *ar) dùng để làm gì? A. Khóa một mutex.
B. Hủy một mutex đã được khởi tạo.
C. Khi tạo một đối tượng mutex với các thuộc nh tùy chọn.
D. Mở khóa một mutex.
79. Việc giải phóng bộ nhđược cấp phát trên heap (ví dụ, bằng malloc) cho một đối số truyn
vào luồng nên được thực hiện ở đâu trong ví dụ server TCP đa luồng?
A. Trong luồng chính ngay sau khi pthread_create() được gọi.
B. Trong luồng con, sau khi đã sử dụng xong đối số đó.
C. Không cần giải phóng, hệ điều hành sẽ tự động thu hồi.
D. Trước khi gọi pthread_create().
80. Khi nào KHÔNG cần đồng bộ hóa (ví dụ, dùng mutex) giữa các luồng? A. Khi nhiều luồng
cùng ghi vào một biến toàn cục.
B. Khi nhiều luồng cùng đọc và ghi vào một le chia sẻ.
C. Khi các luồng chỉ thao tác với các biến cục bộ của riêng chúng.
D. Khi một luồng đọc biến toàn cục trong khi một luồng khác có thể đang ghi vào biến đó.
Nội dung 5: Socket cơ bản
lOMoARcPSD| 61549570
81. Socket trong lập trình mạng được định nghĩa là gì? A. Một loại
cáp mạng đặc biệt.
B. Một giao thức truyền thông.
C. Một điểm cuối (endpoint) của một kết nối mạng hai chiều, cho phép giao ếp giữa các
chương trình. D. Một phần cứng trên card mạng.
82. Trong hàm socket(int domain, int type, int protocol), tham số type với giá trị
SOCK_STREAM chỉ định loại socket nào? A. Socket UDP (User Datagram Protocol).
B. Socket TCP (Transmission Control Protocol), hướng kết nối, đáng n cậy.
C. Socket Raw, cho phép truy cập trực ếp vào IP.
D. Socket cho giao ếp liên ến trình (IPC).
83. Tham số domain với giá trị AF_INET trong hàm socket() chỉ định điều gì?
A. Giao thức IPv6.
B. Giao thức IPv4.
C. Giao ếp cục bộ trên cùng máy (Unix domain sockets).
D. Một loại giao thức mạng không dây.
84. Hàm bind() trong lập trình socket phía server được sử dụng để làm gì? A. Để tạo một
socket mới.
B. Để thiết lập kết nối đến một client.
C. Để gán một địa chỉ IP và một số hiệu cổng (port) cụ thể cho socket.
D. Để lắng nghe các yêu cầu kết nối đến.
85. Hàm listen(int sockfd, int backlog) có chức năng gì? A. Chấp nhận
một kết nối đến từ client.
B. Đặt socket sockfd vào trạng thái sẵn sàng lắng nghe các yêu cầu kết nối đến, với backlog
kích thước hàng đợi các kết nối đang chờ. C. Gửi một yêu cầu lắng nghe đến một server từ xa.
D. Đóng một socket đang lắng nghe.
86. Hàm accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) phía server trả về cái gì khi
có một kết nối từ client được chấp nhận thành công?
lOMoARcPSD| 61549570
A. Địa chỉ IP của client.
B. Một socket descriptor mới, được sử dụng để giao ếp với client vừa kết nối.
C. Số hiệu cổng của client.
D. 0 nếu thành công, -1 nếu lỗi.
87. Phía client, hàm nào được sử dụng để thiết lập một kết nối TCP đến một server?
A. bind()
B. listen()
C. accept()
D. connect()
88. Hàm htons() (host to network short) được sử dụng để làm gì? A. Chuyển đổi
một địa chỉ IP từ dạng chuỗi sang dạng số.
B. Chuyển đổi một số nguyên 16-bit (ví dụ: số hiệu cổng) từ th tự byte của máy chủ (host
byte order) sang thứ tự byte của mạng (network byte order).
C. Chuyển đổi một số nguyên 32-bit từ thứ tự byte của máy chủ sang thứ tự byte của mạng.
D. Lấy tên host từ địa chỉ IP.
89. Trong cấu trúc struct sockaddr_in (dùng cho IPv4), trường nào được dùng để lưu trữ số hiu
cổng?
A. sin_family
B. sin_port
C. sin_addr
D. s_addr
90. Để server có thể chấp nhận kết nối từ bất kỳ địa chỉ IP nào trên máy, trường sin_addr.s_addr
của struct sockaddr_in thường được gán giá trị gì?
A. inet_addr("127.0.0.1")
B. INADDR_LOOPBACK
C. INADDR_ANY
D. 0
lOMoARcPSD| 61549570
91. Cặp hàm nào thường được sử dụng để gửi và nhận dữ liu qua socket TCP sau khi kết nối đã
được thiết lập?
A. write() và read()
B. put() và get()
C. send() và recv()
D. sendto() và recvfrom()
92. Đối với lập trình socket UDP, hàm nào được sử dụng thay thế cho send() để gửi dữ liệu và có
thchỉ định địa chỉ đích?
A. sendmsg() B.
sendall()
C. sendto()
D. udpsend()
93. Tương tự, hàm nào được sử dụng thay thế cho recv() trong UDP đnhận dữ liệu và có thể
lấy thông n địa chỉ nguồn?
A. recvmsg()
B. recvall()
C. recvfrom()
D. udprecv()
94. Hàm close(int sockfd) có tác dụng gì? A. Chỉ tạm
dừng việc sử dụng socket.
B. Đóng kết nối socket và giải phóng le descriptor liên quan.
C. Xóa socket khỏi hệ thống.
D. Đặt socket về trạng thái lắng nghe.
95. Thứ tự các hàm gọi phổ biến cho một TCP server là gì?
A. socket() -> listen() -> bind() -> accept()
B. socket() -> bind() -> listen() -> accept()
C. socket() -> accept() -> bind() -> listen()
D. bind() -> socket() -> listen() -> accept()
lOMoARcPSD| 61549570
96. Trong lập trình socket, SOCK_DGRAM thường được liên kết với giao thức nào?
A. TCP
B. UDP
C. ICMP
D. SCTP
97. Client TCP thường KHÔNG gọi hàm nào sau đây?
A. socket()
B. connect()
C. send() / recv()
D. listen()
98. Hàm inet_addr("127.0.0.1") làm gì?
A. Chuyển đổi một địa chỉ IP dạng số sang dạng chuỗi.
B. Chuyển đổi một địa chỉ IP dạng chuỗi (ví dụ: "127.0.0.1") sang dạng số nh phân 32-bit
theo thứ tự byte mạng. C. Lấy tên miền từ địa chỉ IP.
D. Kiểm tra xem địa chỉ IP có hợp lệ không.
99. Khi accept() trvề một socket mới, socket lắng nghe ban đầu sẽ: A. Bị đóng lại.
B. Tiếp tục trạng thái lắng nghe để chấp nhận các kết nối khác.
C. Được truyền cho ến trình con.
D. Chuyển sang chế độ gửi/nhận.
100. Giao thức UDP KHÔNG có đặc điểm nào sau đây? A. Hướng
không kết nối (conneconless).
B. Không đảm bảo độ n cậy và thứ tự gói n.
C. Yêu cầu các bước listen() và accept() ở phía server.
D. Thường nhanh hơn TCP do ít overhead hơn.
Nội dung 6: Giao thức HTTP

Preview text:

lOMoAR cPSD| 61549570
BỘ 200 CÂU HỎI TRẮC NGHIỆM ÔN TẬP LẬP TRÌNH MẠNG
Nội dung 1: Hàm select()
1. Hàm select() trong C được sử dụng chính để làm gì trong lập trình mạng? A.
Khởi tạo một socket mới cho việc truyền dữ liệu. B.
Gửi dữ liệu một cách tuần tự qua nhiều socket. C.
Theo dõi nhiều file descriptor (socket) đồng thời để kiểm tra xem có hoạt động (đọc, ghi, lỗi) nào xảy ra không. D.
Thiết lập một kết nối TCP an toàn giữa client và server.
2. Tham số nfds trong hàm select() đại diện cho điều gì? A. Tổng số file
descriptor có trong tất cả các tập fd_set.
B. Gia tri file descriptor lớn nhất cần theo dõi, cộng thêm 1.
C. Kích thước của cấu trúc fd_set tính bằng byte.
D. Số lượng tối đa các kết nối đồng thời mà select() có thể xử lý.
3. Nếu tham số timeout của hàm select() được đặt là NULL, hàm select() sẽ hoạt động như thế nào?
A. select() sẽ trả về ngay lập tức mà không chờ đợi.
B. select() sẽ chờ vô thời hạn cho đến khi có ít nhất một file descriptor sẵn sàng hoặc có lỗi.
C. select() sẽ sử dụng một giá trị timeout mặc định của hệ thống.
D. select() sẽ báo lỗi vì timeout không được để là NULL.
4. Giá trị trả về của hàm select() là 0 có ý nghĩa gì? A. Có một lỗi
nghiêm trọng đã xảy ra với hàm select().
B. Không có file descriptor nào được cung cấp để theo dõi.
C. Thời gian chờ (timeout) đã hết mà không có file descriptor nào sẵn sàng.
D. Tất cả các file descriptor trong các tập đều đã sẵn sàng.
5. Macro nào được sử dụng để thêm một file descriptor vào một tập fd_set? A. FD_ZERO(fd, &set) lOMoAR cPSD| 61549570 B. FD_ISSET(fd, &set)
C. FD_SET(fd, &set) D. FD_CLR(fd, &set)
6. Tại sao cần phải khởi tạo lại các tập fd_set (sử dụng FD_ZERO và FD_SET) trước mỗi lần
gọi lại hàm select() trong một vòng lặp?
A. Để giải phóng bộ nhớ đã được cấp phát cho các tập fd_set ở lần gọi trước.
B. Vì hàm select() sẽ sửa đổi nội dung của các tập fd_set để chỉ ra những descriptor nào đã sẵn sàng.
C. Để đảm bảo rằng select() không theo dõi các socket đã bị đóng.
D. Đây là một yêu cầu của chuẩn POSIX để đồng bộ hóa luồng.
7. Hàm FD_ISSET(sockfd, &readfds) được sử dụng để làm gì sau khi select() trả về?
A. Để kiểm tra xem sockfd có phải là một socket hợp lệ không.
B. Để xóa sockfd khỏi tập readfds.
C. Để kiểm tra xem sockfd có nằm trong tập readfds và đã sẵn sàng để đọc hay không.
D. Để thêm sockfd vào tập readfds cho lần gọi select() tiếp theo.
8. Tham số readfds trong hàm select() được dùng để chỉ định điều gì?
A. Tập hợp các file descriptor cần kiểm tra xem có thể ghi dữ liệu vào được không.
B. Tập hợp các file descriptor cần kiểm tra xem có dữ liệu để đọc haykhông.
C. Tập hợp các file descriptor cần kiểm tra các sự kiện ngoại lệ.
D. Tập hợp tất cả các file descriptor đang hoạt động trong hệ thống.
9. Nếu timeout.tv_sec = 0 và timeout.tv_usec = 0 khi gọi select(), điều gì sẽ xảy ra?
A. select() sẽ chờ vô thời hạn.
B. select() sẽ kiểm tra trạng thái các FD ngay lập tức rồi trả về, không chờ.
C. select() sẽ báo lỗi vì timeout bằng 0.
D. select() sẽ chờ một khoảng thời gian tối thiểu do hệ thống quy định.
10. Giá trị trả về -1 từ select() thường cho biết điều gì? A. Timeout đã xảy ra. lOMoAR cPSD| 61549570
B. Không có FD nào sẵn sàng.
C. Có lỗi xảy ra (ví dụ: signal ngắt hoặc lỗi khi truyền FD).
D. Một FD đã được đóng.
11. Trong struct timeval, trường tv_usec quy định đơn vị thời gian là gì? A. Giây. B. Mili giây. C. Micro giây. D. Nano giây.
12. Mục đích chính của việc sử dụng select() trong các ứng dụng mạng phi đồng bộ là gì?
A. Để tăng tốc độ truyền dữ liệu qua mạng.
B. Để quản lý nhiều kết nối mà không cần tạo nhiều luồng hoặc tiến trình.
C. Để mã hóa dữ liệu truyền đi.
D. Để tự động cân bằng tải giữa các server.
13. Macro FD_CLR(sockfd, &fdset) dùng để làm gì? A. Xóa tất cả các FD khỏi tập fdset.
B. Thêm sockfd vào tập fdset.
C. Xóa sockfd khỏi tập fdset.
D. Kiểm tra xem sockfd có trong fdset không.
14. "fds_bits" trong cấu trúc fd_set thường được triển khai như thế nào?
A. Một mảng các ký tự.
B. Một danh sách liên kết các socket.
C. Một mảng các số nguyên dài (long int), mỗi bit đại diện cho một socket.
D. Một cây nhị phân tìm kiếm các file descriptor.
15. Nếu select() trả về một giá trị lớn hơn 0, giá trị đó biểu thị điều gì? A. Mã lỗi cụ thể. lOMoAR cPSD| 61549570
B. Số lượng file descriptor đã sẵn sàng cho một thao tác nào đó.
C. Số lượng file descriptor tối đa có thể theo dõi.
D. PID của tiến trình đã gây ra sự kiện.
16. Khi sử dụng select() để theo dõi nhiều socket, tham số nfds nên được tính như thế nào
nếu sockfd1, sockfd2, và sockfd3 là các socket đang được theo dõi?
A. sockfd1 + sockfd2 + sockfd3 + 1
B. max(sockfd1, sockfd2, sockfd3) + 1 C. 3 (tổng số socket) D. FD_SETSIZE
17. Trong ví dụ minh họa của select(), hàm listen() được gọi với mục đích gì?
A. Để chấp nhận một kết nối mới từ client.
B. Để gán địa chỉ IP và cổng cho socket.
C. Để đặt socket ở trạng thái sẵn sàng lắng nghe các yêu cầu kết nốiđến.
D. Để gửi dữ liệu đến client.
18. Lưu ý nào sau đây là KHÔNG ĐÚNG khi sử dụng select()? A. nfds là FD lớn nhất cộng 1.
B. Phải khởi tạo lại các tập FD mỗi lần trước khi gọi select().
C. select() sẽ tự động xóa các FD đã đóng khỏi các tập FD.
D. timeout có thể dùng để tránh bị block vô thời hạn.
19. Nếu bạn muốn select() kiểm tra khả năng ghi trên socket_ghi và khả năng đọc trên socket_doc, bạn sẽ:
A. Đặt cả socket_ghi và socket_doc vào readfds.
B. Đặt socket_ghi vào writefds và socket_doc vào readfds.
C. Đặt cả socket_ghi và socket_doc vào exceptfds.
D. Đặt socket_ghi vào readfds và socket_doc vào writefds.
20. Trong đoạn mã FD_SET(3, &fdset); FD_SET(4, &fdset);, nếu fdset.fds_bits[0] có giá trị 24,
điều này có nghĩa là gì theo hệ nhị phân? A. Bit thứ 3 và bit thứ 4 được set (ví dụ: ...00011000). lOMoAR cPSD| 61549570
B. Chỉ bit thứ 24 được set.
C. Bit thứ 2 và bit thứ 4 được set.
D. Các bit từ 0 đến 23 đều được set.
Nội dung 2: Hàm poll() và cấu trúc pollfd
21. Hàm poll() cung cấp giải pháp thay thế cho select() với ưu điểm nổi bật nào?
A. Luôn nhanh hơn select() bất kể số lượng FD.
B. Không bị giới hạn bởi FD_SETSIZE (thường là 1024 FD).
C. Sử dụng ít bộ nhớ hơn select().
D. Chỉ hoạt động trên Linux.
22. Trong cấu trúc pollfd, trường nào được sử dụng để chỉ định các sự kiện mà người dùng
muốn theo dõi trên một file descriptor? A. fd B. events C. revents D. status
23. Tham số timeout của hàm poll() được tính bằng đơn vị nào? A. Giây (seconds).
B. Micro giây (microseconds).
C. Mili giây (milliseconds). D. Nano giây (nanoseconds).
24. Giá trị trả về 0 từ hàm poll() có ý nghĩa gì? A. Có lỗi xảy ra trong quá trình gọi hàm.
B. Không có file descriptor nào được cung cấp để theo dõi.
C. Hết thời gian chờ (timeout) nhưng không có FD nào sẵn sàng. D. Một FD đã sẵn sàng.
25. Cờ sự kiện POLLIN trong trường events hoặc revents của struct pollfd cho biết điều gì?
A. Có thể ghi dữ liệu vào FD mà không bị block.
B. Dữ liệu đã sẵn sàng để đọc từ FD. lOMoAR cPSD| 61549570
C. Có lỗi xảy ra trên FD. D. FD không hợp lệ.
26. Sau khi hàm poll() trả về, trường nào trong struct pollfd cho biết sự kiện thực tế đã xảy
ra trên file descriptor tương ứng? A. fd B. events C. revents D. result
27. Nếu muốn poll() chờ vô thời hạn cho đến khi có sự kiện xảy ra, giá trị nào nên được
truyền cho tham số timeout? A. 0 B. -1 C. NULL
D. Một giá trị dương rất lớn.
28. Cờ sự kiện POLLOUT dùng để theo dõi sự kiện gì? A. Dữ liệu đến từ FD.
B. Khả năng ghi dữ liệu vào FD mà không bị block.
C. Kết nối bị đóng bởi đầu kia.
D. File descriptor đã được mở.
29. Để theo dõi đồng thời sự kiện đọc và lỗi trên một socket sockfd bằng poll(), trường
events của struct pollfd tương ứng nên được thiết lập như thế nào?
A. fds[0].events = POLLIN; fds[0].events = POLLERR;
B. fds[0].events = POLLIN | POLLERR;
C. fds[0].events = POLLIN & POLLERR;
D. fds[0].events = POLLIN; và kiểm tra lỗi riêng.
30. Nếu trường revents của một struct pollfd chứa cờ POLLNVAL sau khi poll() được gọi,
điều này có nghĩa là gì? A. Dữ liệu không hợp lệ đã được nhận.
B. File descriptor (fd) không hợp lệ (ví dụ: chưa mở hoặc đã đóng). lOMoAR cPSD| 61549570
C. Yêu cầu không hợp lệ.
D. Không có sự kiện nào xảy ra.
31. Khi sử dụng poll(), làm thế nào để yêu cầu poll() bỏ qua một phần tử cụ thể trong mảng
pollfd[] mà không cần xóa nó khỏi mảng? A. Đặt trường events của phần tử đó thành 0.
B. Đặt trường fd của phần tử đó thành một giá trị âm (ví dụ: -1).
C. Đặt trường revents của phần tử đó thành POLLNVAL.
D. Giảm giá trị của tham số nfds đi 1.
32. So với select(), poll() KHÔNG có nhược điểm nào sau đây? A. Khó khăn khi xử lý
số lượng FD vượt quá FD_SETSIZE.
B. Cấu trúc lưu trữ phức tạp hơn (bitmask).
C. Phải khởi tạo lại toàn bộ mảng pollfd sau mỗi lần gọi.
D. Hiệu suất giảm dần khi số lượng FD quá lớn.
33. Sự kiện POLLHUP trong revents thường chỉ ra điều gì? A. Dữ liệu khẩn cấp đã đến.
B. FD đã sẵn sàng để ghi.
C. Đầu kia của kết nối đã đóng (hung up).
D. Một lỗi hệ thống đã xảy ra.
34. Trong ví dụ theo dõi một socket và stdin bằng poll(), fds[0].fd = 0; có ý nghĩa gì?
A. File descriptor 0, thường là đầu vào chuẩn (stdin).
B. Socket đầu tiên được tạo.
C. Bỏ qua file descriptor này.
D. Chỉ ra đây là socket lắng nghe.
35. Giá trị trả về của poll() là số dương có ý nghĩa gì? A. Số lượng FD có lỗi.
B. Số lượng FD sẵn sàng cho thao tác (có sự kiện trong revents).
C. Mã lỗi cụ thể.
D. Số mili giây đã chờ. 36.
Header file cần thiết để sử dụng hàm poll() là gì? lOMoAR cPSD| 61549570 A. B. C. D.
37. Tham số nfds trong hàm poll(struct pollfd fds[], nfds_t nfds, int timeout) là gì?
A. File descriptor lớn nhất cộng 1.
B. Tổng số file descriptor trong hệ thống.
C. Số lượng phần tử trong mảng fds[] cần được theo dõi.
D. Kích thước tối đa của mảng fds[].
38. Nếu poll() trả về -1, điều gì có khả năng đã xảy ra? A. Timeout.
B. Không có FD nào sẵn sàng.
C. Một lỗi đã xảy ra (ví dụ, tham số không hợp lệ).
D. Một FD đã được đóng bởi client.
39. Khi muốn kiểm tra ngay lập tức trạng thái của các FD mà không chờ đợi, tham số
timeout của poll() nên được đặt là bao nhiêu? A. -1 B. 0 C. 1 D. 1000
40. Trong mảng struct pollfd fds[], nếu fds[i].revents & POLLIN là true, điều này có
nghĩa là: A. Đã xảy ra lỗi trên fds[i].fd.
B. fds[i].fd sẵn sàng để ghi.
C. Có dữ liệu để đọc trên fds[i].fd.
D. fds[i].fd là một FD không hợp lệ.
Nội dung 3: Đa tiến trình với fork() 41.
Hàm fork() được sử dụng để làm gì?
A. Tạo một luồng mới trong tiến trình hiện tại. lOMoAR cPSD| 61549570
B. Tạo một tiến trình con mới, là bản sao của tiến trình cha.
C. Thực thi một chương trình mới thay thế tiến trình hiện tại.
D. Chờ một tiến trình con kết thúc.
42. Sau khi fork() được gọi thành công, giá trị trả về trong tiến trình con là gì?
A. PID (Process ID) của tiến trình cha.
B. PID (Process ID) của chính nó (tiến trình con). C. 0. D. -1.
43. Trong tiến trình cha, giá trị trả về của fork() khi tạo tiến trình con thành công là gì? A. 0.
B. PID (Process ID) của tiến trình con vừa được tạo.
C. PID (Process ID) của chính nó (tiến trình cha).
D. Một giá trị âm. 44.
Nếu fork() trả về -1, điều đó có nghĩa là gì? A. Tiến trình
con đã kết thúc thành công.
B. Tiến trình cha đã kết thúc.
C. Không thể tạo được tiến trình con (có lỗi xảy ra).
D. Đây là tiến trình con.
45. Sau khi fork() được gọi, không gian bộ nhớ của tiến trình cha và tiến trình con như thế nào?
A. Chúng chia sẻ cùng một không gian bộ nhớ hoàn toàn.
B. Tiến trình con có không gian bộ nhớ riêng biệt, được sao chép từ tiến trình cha tại thời điểm fork().
C. Chỉ có vùng mã lệnh (text segment) được chia sẻ, vùng dữ liệu (data segment) thì riêng biệt.
D. Tiến trình cha và con giao tiếp qua một vùng nhớ chia sẻ đặc biệt do fork()tạo ra. 46.
Hiện tượng "zombie process" xảy ra khi nào?
A. Khi một tiến trình con cố gắng truy cập vào bộ nhớ của tiến trình cha.
B. Khi tiến trình cha kết thúc trước tiến trình con. lOMoAR cPSD| 61549570
C. Khi tiến trình con đã kết thúc nhưng tiến trình cha chưa thu thập trạng thái kết thúc của
nó (chưa gọi wait() hoặc waitpid()).
D. Khi một tiến trình không thể tạo thêm tiến trình con do hết tài nguyên.
47. Trong mô hình server đa tiến trình sử dụng fork(), sau khi một kết nối client được accept(),
tiến trình con thường làm gì với socket lắng nghe (listening socket)?
A. Tiếp tục sử dụng socket lắng nghe để chấp nhận thêm client.
B. Đóng socket lắng nghe vì nó không cần thiết cho việc xử lý client cụ thể này.
C. Gọi listen() trên socket lắng nghe một lần nữa.
D. Chuyển socket lắng nghe cho một tiến trình khác.
48. Tương tự, trong mô hình server đa tiến trình, tiến trình cha thường làm gì với socket kết nối
của client (client socket) sau khi đã fork() ra tiến trình con để xử lý client đó?
A. Tiếp tục đọc ghi dữ liệu với client trên socket đó.
B. Đóng socket kết nối của client vì tiến trình con sẽ đảm nhận việc này.
C. Chuyển socket đó cho một tiến trình con khác.
D. Chờ tiến trình con xử lý xong rồi mới đóng.
49. Hàm nào thường được tiến trình cha sử dụng để đợi và thu thập trạng thái kết thúc của một
tiến trình con, nhằm tránh zombie process? A. fork() B. exit()
C. wait() hoặc waitpid() D. kill() 50.
Nếu một đoạn mã gọi fork() hai lần liên tiếp, tổng cộng sẽ có bao nhiêu tiến trình được
tạo ra (bao gồm cả tiến trình ban đầu)? A. 2 tiến trình. B. 3 tiến trình. C. 4 tiến trình. D. 5 tiến trình.
51. File descriptor của socket được mở trước khi gọi fork() sẽ như thế nào trong tiến trình cha và con?
A. Chỉ tiến trình cha giữ lại file descriptor đó. lOMoAR cPSD| 61549570
B. Chỉ tiến trình con giữ lại file descriptor đó.
C. Cả tiến trình cha và con đều có bản sao của file descriptor đó, và chúng trỏ đến cùng một
đối tượng file trong kernel.
D. File descriptor sẽ bị đóng tự động trong cả hai tiến trình.
52. Điều kiện nào sau đây thường được dùng trong mã nguồn để xác định đoạn mã nào sẽ
được thực thi bởi tiến trình con? A. if (fork() > 0)
B. if (pid == 0) (sau khi pid = fork();) C. if (fork() < 0) D. if (fork() != 0) 53.
"Fork bomb" là hiện tượng gì?
A. Một lỗi trong hàm fork() khiến hệ thống bị treo.
B. Việc một tiến trình liên tục tạo ra các tiến trình con một cách không kiểm soát, dẫn đến
cạn kiệt tài nguyên hệ thống. C. Việc gửi một lượng lớn yêu cầu fork() đến một server từ xa.
D. Một tiến trình con cố gắng "giết" tiến trình cha của nó. 54.
Header file nào cần được bao gồm để sử dụng hàm fork()? A. B. C. D. 55.
Trong đoạn mã: fork(); fork(); printf("Hello\n");, "Hello" sẽ được in ra bao nhiêu
lần? A. 1 lần. B. 2 lần. C. 3 lần. D. 4 lần.
56. Lợi ích chính của việc sử dụng mô hình server đa tiến trình (mỗi client một tiến trình) là gì?
A. Tiết kiệm bộ nhớ hơn mô hình đa luồng.
B. Xử lý đồng thời nhiều client, mỗi client được phục vụ bởi một tiến trình riêng biệt, tăng tính độc lập. lOMoAR cPSD| 61549570
C. Khởi tạo tiến trình nhanh hơn khởi tạo luồng.
D. Dễ dàng chia sẻ dữ liệu giữa các client hơn.
57. Để tránh zombie process mà không cần wait() hoặc waitpid(), một cách là gì?
A. Tiến trình con gọi exit(0) ngay lập tức.
B. Tiến trình cha đặt cờ SIGCHLD thành SIG_IGN. (Đáp án B của câu trắc nghiệm gốc)
C. Tiến trình cha gọi sleep() một lúc lâu.
D. Sử dụng pthread_detach() cho tiến trình con.
58. Biến toàn cục được khai báo trước khi gọi fork() sẽ như thế nào trong tiến trình cha và con?
A. Chỉ tiến trình cha có thể truy cập.
B. Chỉ tiến trình con có thể truy cập.
C. Cả hai cùng chia sẻ và thay đổi của một tiến trình sẽ ảnh hưởng đến tiến trình kia.
D. Mỗi tiến trình có một bản sao riêng của biến toàn cục đó, thay đổiở tiến trình này không
ảnh hưởng đến tiến trình kia. 59.
Lệnh waitpid(-1, NULL, WNOHANG) có ý nghĩa gì?
A. Chờ một tiến trình con bất kỳ kết thúc, block cho đến khi có con kết thúc.
B. Chờ một tiến trình con cụ thể kết thúc, không block.
C. Chờ một tiến trình con bất kỳ kết thúc, không block (trả về ngay nếu không có con nào kết thúc).
D. Gửi tín hiệu WNOHANG đến tất cả tiến trình con.
60. Trong một server đa tiến trình, nếu tiến trình cha không đóng socket của client sau khi fork,
điều gì có thể xảy ra?
A. Client sẽ không thể gửi dữ liệu.
B. Tiến trình con sẽ không thể nhận dữ liệu.
C. Có thể gây rò rỉ tài nguyên file descriptor nếu server chạy lâu dài và xử lý nhiều client.
D. Kết nối sẽ tự động đóng sau một khoảng thời gian.
Nội dung 4: Lập trình mạng đa luồng với pthread lOMoAR cPSD| 61549570 61. Luồng (thread) là gì?
A. Một tiến trình (process) độc lập hoàn toàn.
B. Đơn vị xử lý nhỏ nhất trong một tiến trình, có thể chạy song song với các luồng khác trong
cùng tiến trình. C. Một cơ chế giao tiếp giữa các tiến trình.
D. Một bản sao của tiến trình cha.
62. Các luồng trong cùng một tiến trình chia sẻ những tài nguyên nào sau đây?
A. Không gian địa chỉ bộ nhớ (bao gồm biến toàn cục, heap), file descriptor.
B. Chỉ có con trỏ lệnh (instruction pointer) và thanh ghi.
C. Mỗi luồng có không gian bộ nhớ hoàn toàn tách biệt.
D. Chỉ chia sẻ các biến được khai báo với từ khóa shared.
63. Tài nguyên nào sau đây là RIÊNG BIỆT cho mỗi luồng trong cùng một tiến trình? A. Biến toàn cục. B. Vùng nhớ heap.
C. Ngăn xếp (stack) dùng cho biến cục bộ và thông tin cuộc gọi hàm.
D. Bảng mô tả file (file descriptor table). 64.
Hàm nào trong thư viện pthread được sử dụng để tạo một luồng mới? A. pthread_start() B. pthread_create() C. pthread_init() D. pthread_begin() 65.
Tham số thứ ba của hàm pthread_create() (start_routine) có ý nghĩa gì? A. Con trỏ tới
biến kiểu pthread_t để lưu ID của luồng mới.
B. Thuộc tính của luồng mới (ví dụ: detached state, stack size).
C. Con trỏ tới hàm mà luồng mới sẽ bắt đầu thực thi.
D. Tham số sẽ được truyền vào hàm start_routine.
66. Hàm pthread_join(pthread_t thread, void **retval) được sử dụng để làm gì?
A. Để một luồng kết thúc chính nó. lOMoAR cPSD| 61549570
B. Để một luồng chờ một luồng khác (được xác định bởi thread) kết thúc và có thể lấy giá
trị trả về của luồng đó. C. Để gộp hai luồng thành một.
D. Để tách một luồng ra khỏi luồng gọi, cho phép nó tự giải phóng tài nguyên khi kết thúc.
67. Khi một luồng được tạo ở trạng thái "detached" (ví dụ, bằng pthread_detach()), điều gì xảy
ra khi luồng đó kết thúc?
A. Nó sẽ đợi cho đến khi một luồng khác gọi pthread_join() trên nó.
B. Nó sẽ tự động giải phóng tài nguyên của mình mà không cần luồng khác join.
C. Nó sẽ trở thành một zombie thread.
D. Nó sẽ gửi một tín hiệu đến luồng chính.
68. "Race condition" (tình trạng tranh chấp) trong lập trình đa luồng xảy ra khi nào?
A. Khi hai luồng cố gắng thực thi cùng một hàm.
B. Khi nhiều luồng cùng truy cập và cố gắng sửa đổi một tài nguyên chia sẻ (ví dụ: biến toàn
cục) mà không có sự đồng bộ hóa thích hợp, dẫn đến kết quả không thể đoán trước.
C. Khi một luồng chạy nhanh hơn một luồng khác đáng kể.
D. Khi một luồng bị block vô thời hạn.
69. Mutex (pthread_mutex_t) được sử dụng để làm gì trong lập trình đa luồng?
A. Để truyền dữ liệu giữa các luồng.
B. Để đảm bảo rằng chỉ một luồng có thể truy cập vào một đoạn mã tới hạn (critical section)
hoặc tài nguyên chia sẻ tại một thời điểm, tránh race condition.
C. Để tạo ra các luồng mới.
D. Để đặt độ ưu tiên cho các luồng. 70.
Cặp hàm nào thường được sử dụng để khóa và mở khóa một mutex?
A. pthread_mutex_begin() và pthread_mutex_end()
B. pthread_mutex_wait() và pthread_mutex_signal()
C. pthread_mutex_lock() và pthread_mutex_unlock()
D. pthread_mutex_acquire() và pthread_mutex_release()
71. Làm thế nào để truyền một đối số (ví dụ, một số nguyên) vào hàm thực thi của luồng (start_routine)? lOMoAR cPSD| 61549570
A. Bằng cách sử dụng biến toàn cục.
B. Truyền trực tiếp giá trị vào tham số thứ tư của pthread_create().
C. Truyền địa chỉ của biến chứa đối số (ép kiểu thành void*) vào tham số thứ tư của
pthread_create(), và trong start_routine, ép kiểu ngược lại.
D. pthread không hỗ trợ truyền đối số trực tiếp. 72.
Hàm pthread_exit(void *retval) được dùng để làm gì? A. Để luồng
chính kết thúc toàn bộ tiến trình.
B. Để một luồng tự kết thúc và có thể trả về một giá trị (retval).
C. Để tạm dừng một luồng khác. D. Để giải phóng mutex.
73. Khi biên dịch một chương trình C sử dụng thư viện pthread trên Linux với GCC, cờ (flag) nào
thường được sử dụng? A. -lthread B. -pthreads
C. -lpthread hoặc -pthread D. -enable-threading
74. Header file nào cần được bao gồm để sử dụng các hàm của thư viện pthread? A. B. C. D.
75. Trong mô hình server đa luồng, khi một kết nối client mới được chấp nhận, server thường làm gì?
A. Tạo một tiến trình con mới bằng fork() để xử lý client.
B. Tạo một luồng mới bằng pthread_create() để xử lý client đó, truyền socket của client làm đối số.
C. Xử lý client đó ngay trong luồng chính.
D. Đưa client vào một hàng đợi để xử lý tuần tự. lOMoAR cPSD| 61549570 76.
Sự khác biệt chính giữa vùng nhớ heap và stack là gì?
A. Stack được quản lý tự động cho biến cục bộ và lời gọi hàm, heap được cấp phát và giải
phóng thủ công bởi lập trình viên.
B. Heap chỉ dùng cho biến toàn cục, stack dùng cho biến cục bộ.
C. Stack có kích thước lớn hơn heap.
D. Heap được chia sẻ giữa các tiến trình, stack thì không. 77.
Nếu hai luồng cùng cố gắng tăng một biến toàn cục counter mà không dùng mutex, giá
trị cuối cùng của counter có thể như thế nào? A. Luôn luôn là tổng số lần tăng từ cả hai luồng.
B. Có thể nhỏ hơn tổng số lần tăng mong đợi do race condition.
C. Luôn luôn bằng 0.
D. Sẽ gây ra lỗi biên dịch. 78.
Hàm pthread_mutex_init(pthread_mutex_t *mutex, const
pthread_mutexattr_t *attr) dùng để làm gì? A. Khóa một mutex.
B. Hủy một mutex đã được khởi tạo.
C. Khởi tạo một đối tượng mutex với các thuộc tính tùy chọn. D. Mở khóa một mutex.
79. Việc giải phóng bộ nhớ được cấp phát trên heap (ví dụ, bằng malloc) cho một đối số truyền
vào luồng nên được thực hiện ở đâu trong ví dụ server TCP đa luồng?
A. Trong luồng chính ngay sau khi pthread_create() được gọi.
B. Trong luồng con, sau khi đã sử dụng xong đối số đó.
C. Không cần giải phóng, hệ điều hành sẽ tự động thu hồi.
D. Trước khi gọi pthread_create(). 80.
Khi nào KHÔNG cần đồng bộ hóa (ví dụ, dùng mutex) giữa các luồng? A. Khi nhiều luồng
cùng ghi vào một biến toàn cục.
B. Khi nhiều luồng cùng đọc và ghi vào một file chia sẻ.
C. Khi các luồng chỉ thao tác với các biến cục bộ của riêng chúng.
D. Khi một luồng đọc biến toàn cục trong khi một luồng khác có thể đang ghi vào biến đó.
Nội dung 5: Socket cơ bản lOMoAR cPSD| 61549570 81.
Socket trong lập trình mạng được định nghĩa là gì? A. Một loại cáp mạng đặc biệt.
B. Một giao thức truyền thông.
C. Một điểm cuối (endpoint) của một kết nối mạng hai chiều, cho phép giao tiếp giữa các
chương trình. D. Một phần cứng trên card mạng. 82.
Trong hàm socket(int domain, int type, int protocol), tham số type với giá trị
SOCK_STREAM chỉ định loại socket nào? A. Socket UDP (User Datagram Protocol).
B. Socket TCP (Transmission Control Protocol), hướng kết nối, đáng tin cậy.
C. Socket Raw, cho phép truy cập trực tiếp vào IP.
D. Socket cho giao tiếp liên tiến trình (IPC).
83. Tham số domain với giá trị AF_INET trong hàm socket() chỉ định điều gì? A. Giao thức IPv6. B. Giao thức IPv4.
C. Giao tiếp cục bộ trên cùng máy (Unix domain sockets).
D. Một loại giao thức mạng không dây. 84.
Hàm bind() trong lập trình socket phía server được sử dụng để làm gì? A. Để tạo một socket mới.
B. Để thiết lập kết nối đến một client.
C. Để gán một địa chỉ IP và một số hiệu cổng (port) cụ thể cho socket.
D. Để lắng nghe các yêu cầu kết nối đến. 85.
Hàm listen(int sockfd, int backlog) có chức năng gì? A. Chấp nhận
một kết nối đến từ client.
B. Đặt socket sockfd vào trạng thái sẵn sàng lắng nghe các yêu cầu kết nối đến, với backlog là
kích thước hàng đợi các kết nối đang chờ. C. Gửi một yêu cầu lắng nghe đến một server từ xa.
D. Đóng một socket đang lắng nghe.
86. Hàm accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) phía server trả về cái gì khi
có một kết nối từ client được chấp nhận thành công? lOMoAR cPSD| 61549570
A. Địa chỉ IP của client.
B. Một socket descriptor mới, được sử dụng để giao tiếp với client vừa kết nối.
C. Số hiệu cổng của client.
D. 0 nếu thành công, -1 nếu lỗi.
87. Phía client, hàm nào được sử dụng để thiết lập một kết nối TCP đến một server? A. bind() B. listen() C. accept() D. connect() 88.
Hàm htons() (host to network short) được sử dụng để làm gì? A. Chuyển đổi
một địa chỉ IP từ dạng chuỗi sang dạng số.
B. Chuyển đổi một số nguyên 16-bit (ví dụ: số hiệu cổng) từ thứ tự byte của máy chủ (host
byte order) sang thứ tự byte của mạng (network byte order).
C. Chuyển đổi một số nguyên 32-bit từ thứ tự byte của máy chủ sang thứ tự byte của mạng.
D. Lấy tên host từ địa chỉ IP.
89. Trong cấu trúc struct sockaddr_in (dùng cho IPv4), trường nào được dùng để lưu trữ số hiệu cổng? A. sin_family B. sin_port C. sin_addr D. s_addr
90. Để server có thể chấp nhận kết nối từ bất kỳ địa chỉ IP nào trên máy, trường sin_addr.s_addr
của struct sockaddr_in thường được gán giá trị gì? A. inet_addr("127.0.0.1") B. INADDR_LOOPBACK C. INADDR_ANY D. 0 lOMoAR cPSD| 61549570
91. Cặp hàm nào thường được sử dụng để gửi và nhận dữ liệu qua socket TCP sau khi kết nối đã được thiết lập? A. write() và read() B. put() và get() C. send() và recv() D. sendto() và recvfrom()
92. Đối với lập trình socket UDP, hàm nào được sử dụng thay thế cho send() để gửi dữ liệu và có
thể chỉ định địa chỉ đích? A. sendmsg() B. sendall() C. sendto() D. udpsend()
93. Tương tự, hàm nào được sử dụng thay thế cho recv() trong UDP để nhận dữ liệu và có thể
lấy thông tin địa chỉ nguồn? A. recvmsg() B. recvall() C. recvfrom() D. udprecv() 94.
Hàm close(int sockfd) có tác dụng gì? A. Chỉ tạm
dừng việc sử dụng socket.
B. Đóng kết nối socket và giải phóng file descriptor liên quan.
C. Xóa socket khỏi hệ thống.
D. Đặt socket về trạng thái lắng nghe. 95.
Thứ tự các hàm gọi phổ biến cho một TCP server là gì?
A. socket() -> listen() -> bind() -> accept()
B. socket() -> bind() -> listen() -> accept()
C. socket() -> accept() -> bind() -> listen()
D. bind() -> socket() -> listen() -> accept() lOMoAR cPSD| 61549570
96. Trong lập trình socket, SOCK_DGRAM thường được liên kết với giao thức nào? A. TCP B. UDP C. ICMP D. SCTP 97.
Client TCP thường KHÔNG gọi hàm nào sau đây? A. socket() B. connect() C. send() / recv() D. listen() 98.
Hàm inet_addr("127.0.0.1") làm gì?
A. Chuyển đổi một địa chỉ IP dạng số sang dạng chuỗi.
B. Chuyển đổi một địa chỉ IP dạng chuỗi (ví dụ: "127.0.0.1") sang dạng số nhị phân 32-bit
theo thứ tự byte mạng. C. Lấy tên miền từ địa chỉ IP.
D. Kiểm tra xem địa chỉ IP có hợp lệ không. 99.
Khi accept() trả về một socket mới, socket lắng nghe ban đầu sẽ: A. Bị đóng lại.
B. Tiếp tục ở trạng thái lắng nghe để chấp nhận các kết nối khác.
C. Được truyền cho tiến trình con.
D. Chuyển sang chế độ gửi/nhận.
100. Giao thức UDP KHÔNG có đặc điểm nào sau đây? A. Hướng
không kết nối (connectionless).
B. Không đảm bảo độ tin cậy và thứ tự gói tin.
C. Yêu cầu các bước listen() và accept() ở phía server.
D. Thường nhanh hơn TCP do ít overhead hơn.
Nội dung 6: Giao thức HTTP