Cuốn sách “API Linux. Hướng dẫn toàn diện"


Cuốn sách “API Linux. Hướng dẫn toàn diện"

Chào buổi chiều Tôi xin giới thiệu với các bạn cuốn sách “Linux API. Hướng dẫn toàn diện” (bản dịch sách Giao diện lập trình Linux). Nó có thể được đặt hàng trên trang web của nhà xuất bản và nếu bạn áp dụng mã khuyến mại API Linux , bạn sẽ được giảm giá 30%.

Trích từ cuốn sách để tham khảo:

Ổ cắm: Kiến trúc máy chủ

Trong chương này, chúng ta sẽ thảo luận những kiến ​​thức cơ bản về thiết kế máy chủ lặp và song song, đồng thời xem xét một daemon đặc biệt gọi là inetd, giúp tạo các ứng dụng máy chủ Internet dễ dàng hơn.

Máy chủ lặp và song song

Có hai kiến ​​trúc máy chủ mạng dựa trên socket phổ biến:

  • lặp lại: máy chủ phục vụ từng máy khách một, trước tiên xử lý một yêu cầu (hoặc một số yêu cầu) từ một máy khách rồi chuyển sang máy khách tiếp theo;

  • song song: máy chủ được thiết kế để phục vụ nhiều khách hàng cùng một lúc.

Một ví dụ về máy chủ lặp dựa trên hàng đợi FIFO đã được trình bày trong Phần 44.8.

Máy chủ lặp thường chỉ phù hợp trong trường hợp yêu cầu của máy khách có thể được xử lý khá nhanh, vì mỗi máy khách buộc phải đợi cho đến khi bất kỳ máy khách nào khác ở phía trước nó được phục vụ. Trường hợp sử dụng phổ biến của phương pháp này là trao đổi các yêu cầu và phản hồi đơn lẻ giữa máy khách và máy chủ.

Máy chủ song song phù hợp trong trường hợp mỗi yêu cầu mất một lượng thời gian đáng kể để xử lý hoặc khi máy khách và máy chủ tham gia trao đổi tin nhắn dài. Trong chương này, chúng ta sẽ chủ yếu tập trung vào cách thiết kế máy chủ song song truyền thống (và đơn giản nhất), đó là tạo ra một tiến trình con riêng biệt cho mỗi máy khách mới. Quá trình này thực hiện tất cả các công việc để phục vụ client và sau đó kết thúc. Bởi vì mỗi quy trình này hoạt động độc lập nên có thể phục vụ nhiều khách hàng cùng một lúc. Nhiệm vụ chính của tiến trình máy chủ chính (cha) là tạo một tiến trình con riêng biệt cho mỗi máy khách mới (cách khác, các luồng thực thi có thể được tạo thay vì các tiến trình).

Trong các phần sau, chúng ta sẽ xem xét các ví dụ về máy chủ ổ cắm miền internet lặp và song song. Hai máy chủ này triển khai một phiên bản đơn giản của dịch vụ echo (RFC 862), trả về bản sao của bất kỳ tin nhắn nào được khách hàng gửi tới nó.

Tiếng vang của máy chủ UDP lặp lại

Trong phần này và phần tiếp theo, chúng tôi sẽ giới thiệu các máy chủ cho dịch vụ echo. Nó có sẵn trên cổng số 7 và hoạt động trên cả UDP và TCP (cổng này được bảo lưu và do đó máy chủ echo phải được chạy với đặc quyền của quản trị viên).

Máy chủ echo UDP liên tục đọc các datagram và trả về bản sao của chúng cho người gửi. Vì máy chủ chỉ cần xử lý một tin nhắn mỗi lần nên kiến ​​trúc lặp lại là đủ. Tệp tiêu đề cho các máy chủ được hiển thị trong Liệt kê 56.1.

Liệt kê 56.1. Tệp tiêu đề cho chương trình id_echo_sv.c và id_echo_cl.c

#include "inet_sockets.h" /* Khai báo các hàm socket của chúng ta */
#include "tlpi_hdr.h"

#define DỊCH VỤ "echo" /* Tên dịch vụ UDP */

#define BUF_SIZE 500 /* Kích thước tối đa của datagram
có thể được đọc bởi máy khách và máy chủ */
_______________________________________________________________________________sockets/id_echo.h

Liệt kê 56.2 cho thấy việc triển khai máy chủ. Những điểm sau đây đáng lưu ý:

  • để đưa máy chủ vào chế độ daemon, chúng ta sử dụng hàm BecomeDaemon() từ phần 37.2;

  • để làm cho chương trình gọn hơn, chúng tôi sử dụng thư viện để làm việc với các ổ cắm tên miền Internet, được phát triển trong phần 55.12;

  • nếu máy chủ không thể trả lời phản hồi cho máy khách, nó sẽ ghi một thông báo vào nhật ký bằng lệnh gọi syslog().

Trong một ứng dụng thực tế, chúng tôi có thể sẽ áp đặt một số giới hạn về tần suất ghi nhật ký thông báo bằng syslog(). Điều này sẽ loại bỏ khả năng kẻ tấn công tràn nhật ký hệ thống. Ngoài ra, đừng quên rằng mỗi lệnh gọi tới syslog() khá tốn kém vì nó sử dụng fsync() theo mặc định.

Liệt kê 56.2. Máy chủ lặp thực hiện dịch vụ echo UDP

_________________________________________________________________sockets/id_echo_sv.c
#bao gồm
#include "id_echo.h"
#include "trở thành_daemon.h"

int
main (int argc, char * argv [])
{
int sfd;
ssize_t numRead;
socklen_t len;
struct sockaddr_storage claddr;
char buf[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];

if (trở thànhDaemon(0) == -1)
errExit("trở thànhDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
nếu (sfd == -1) {
syslog(LOG_ERR, "Không thể tạo socket máy chủ (%s)",
strerror (errno));
thoát (EXIT_FAILURE);

/* Nhận datagram và trả lại bản sao của chúng cho người gửi */
}
vì (;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

nếu (numRead == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numRead)
syslog(LOG_WARNING, "Lỗi phản hồi tới %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror (errno));
}
}
_________________________________________________________________sockets/id_echo_sv.c

Để kiểm tra hoạt động của máy chủ, chúng tôi sử dụng chương trình từ Liệt kê 56.3. Nó cũng sử dụng thư viện để làm việc với các ổ cắm tên miền Internet, được phát triển trong phần 55.12. Là đối số dòng lệnh đầu tiên, chương trình máy khách lấy tên của nút mạng nơi đặt máy chủ. Máy khách bước vào một vòng lặp trong đó nó gửi từng đối số còn lại đến máy chủ dưới dạng các gói dữ liệu riêng biệt, sau đó đọc và in các gói dữ liệu mà nó nhận được từ máy chủ để phản hồi.

Liệt kê 56.3. Máy khách cho dịch vụ tiếng vang UDP

#include "id_echo.h"

int
main (int argc, char * argv [])
{
int sfd, j;
size_t len;
ssize_t numRead;
char buf[BUF_SIZE];

if (argc < 2 || strcmp(argv[1], "--help") == 0)
useErr("%s tin nhắn máy chủ…n", argv[0]);

/* Tạo địa chỉ máy chủ dựa trên đối số dòng lệnh đầu tiên */
sfd = inetConnect(argv[1], DỊCH VỤ, SOCK_DGRAM);
nếu (sfd == -1)
gây tử vong("Không thể kết nối với ổ cắm máy chủ");

/* Gửi các đối số còn lại đến máy chủ dưới dạng các datagram riêng biệt */
cho (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
gây tử vong ("ghi một phần/không thành công");

numRead = đọc(sfd, buf, BUF_SIZE);
nếu (numRead == -1)
errExit("đọc");
printf("[%ld bytes] %.*sn", (long) numRead, (int) numRead, buf);
}
thoát ra (EXIT_SUCCESS);
}
_________________________________________________________________sockets/id_echo_cl.c

Dưới đây là ví dụ về những gì chúng ta sẽ thấy khi chạy máy chủ và hai phiên bản máy khách:

$su // Cần có đặc quyền để liên kết với cổng dành riêng
Mật khẩu:
# ./id_echo_sv // Máy chủ chuyển sang chế độ nền
# exit // Từ bỏ quyền quản trị viên
$ ./id_echo_cl localhost hello world // Máy khách này gửi hai datagram
[5 byte] xin chào // Client hiển thị phản hồi nhận được từ máy chủ
[5 byte] thế giới
$ ./id_echo_cl tạm biệt localhost // Client này gửi một datagram
[7 byte] tạm biệt

Chúc bạn đọc vui vẻ)

Nguồn: linux.org.ru