2015-05-20 16 views
5

Tôi đang viết một ứng dụng C chạy với tư cách là systemd service khi khởi động (distro: Arch Linux) và kết nối với máy chủ. Vì ứng dụng được chạy khi khởi động, cuối cùng nó xảy ra khi kết nối mạng chưa được thiết lập. Điều này tự nhiên dẫn đến sự thất bại của hàm đầu tiên yêu cầu một hàm, trong trường hợp của tôi là getaddrinfo.Nếu getaddrinfo thất bại khi nó không thành công (ngay cả sau khi mạng đã sẵn sàng)

Vì vậy, tôi nghĩ rằng tôi sẽ chỉ viết một vòng lặp liên tục gọi getaddrinfo cho đến khi nó thành công khi mạng đã sẵn sàng. Thật không may tôi thấy rằng getaddrinfo giữ không thành công với name or service not known ngay cả sau khi kết nối được thiết lập.

Tôi có thể ping máy chủ theo tên máy chủ nhưng getaddrinfo vẫn không thực hiện. Nếu tôi dừng ứng dụng và chạy lại, mọi thứ sẽ hoạt động tốt. Nếu kết nối mạng đã được thiết lập trước cuộc gọi đầu tiên, getaddrinfo cũng hoạt động tốt.

Rõ ràng, nếu getaddrinfo không thành công một lần vì mạng không sẵn sàng, mạng sẽ không thành công mãi mãi. Có vẻ như không nhận thức được kết nối hiện có. Khi sử dụng không được chấp nhận gethostbyname, hành vi là như nhau.

Lý do của hành vi này là gì? Có cách nào để buộc getaddrinfo để làm mới các biến nội bộ (nếu tồn tại) hoặc tương tự có thể giải thích tại sao hàm vẫn tin rằng không có kết nối? Có chức năng nào khác mà tôi nên gọi trước đó để kiểm tra xem mạng đã sẵn sàng chưa?

Tôi muốn tránh sự chậm trễ chờ đợi một thời gian, hy vọng mạng sẽ được kết nối sau đó. Tôi cũng muốn kiểm tra kết nối từ bên trong ứng dụng của tôi và không có tập lệnh bash đầu tiên kiểm tra nó và sau đó bắt đầu ứng dụng.

Trả lời

4

Bạn có thể hiểu được những câu trả lời bằng cách biên dịch các chương trình thử nghiệm sau, và theo các hướng dẫn dưới đây:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) 
{ 
    while (1) 
    { 
     struct addrinfo *res; 
     int rc=getaddrinfo(argv[1], "http", NULL, &res); 

     printf("getaddrinfo returned %d\n", rc); 

     if (rc == 0) 
      freeaddrinfo(res); 

     sleep(1); 
    } 
} 

Trước khi bạn chạy chương trình thử nghiệm này:

  1. Connect vào mạng.
  2. Đổi tên, tạm thời /etc/resolv.conf thành /etc/resolv.conf.save.
  3. Bắt đầu chương trình thử nghiệm này, sử dụng tên máy chủ tốt.
  4. Ngay sau khi chương trình thử nghiệm bắt đầu và bắt đầu in mã lỗi, đổi tên /etc/resolv.conf.save thành /etc/resolv.conf.
  5. Quan sát rằng chương trình thử nghiệm vẫn báo cáo lỗi giải quyết DNS.
  6. Nếu bạn CTRL-C và khởi động lại, mặc dù, chương trình thử nghiệm hiện sẽ báo cáo độ phân giải DNS hợp lệ.

Khi bạn ngắt kết nối và kết nối lại từ mạng, ngăn xếp mạng của bạn sẽ ghi đè và cập nhật /etc/resolv.conf tương ứng. Tập tin cấu hình này là cần thiết bởi trình phân giải DNS trong thư viện C. Thư viện C đọc cấu hình DNS từ /etc/resolv.conf lần đầu tiên và lưu trữ nó. Nó không kiểm tra, với mọi tra cứu, nếu nội dung của /etc/resolv.conf đã thay đổi.

Cuối cùng:

  1. bài tập về nhà của bạn là thêm một cuộc gọi đến res_init(), quy định tại resolv.h, để chương trình thử nghiệm này, đọc man page tương ứng, và xem những gì sẽ xảy ra. Đó là câu trả lời của bạn.
+0

Bằng cách đó, tôi có nghĩa là res_init() bên trong vòng lặp. –

+0

Điều đó thực sự hoạt động đôi khi (nhưng ít khi xảy ra). Tôi cho rằng nó hoạt động nếu kết nối mạng đã được thiết lập, nhưng 'resolv.conf' vẫn chưa được cập nhật khi ứng dụng được khởi động. Khi 'resolv.conf' được cập nhật, lệnh gọi' res_init' trong vòng lặp tải cấu hình mới và sau đó 'getaddrinfo' suceeds. Nhưng nếu kết nối mạng chưa sẵn sàng khi bắt đầu ứng dụng, nó vẫn không thành công, – kassiopeia

+0

Bản trình diễn từng bước của tôi liên quan đến việc khởi động ứng dụng khi không có cấu hình DNS nào được cấu hình, đó là trường hợp không có kết nối mạng nào. Bạn đã thử bắt đầu mã demo với lệnh gọi rs_init() mà không cần kết nối mạng rồi kết nối với mạng? Mã demo ngắn này khá dễ dàng để kiểm tra. Không cần phải thừa nhận bất cứ điều gì. –

Các vấn đề liên quan