/*
** server.c -- 一個流套接字服務器演示
*/
#include <stdio.h>/span>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>/span>
#include <sys/socket.h>/span>
#include <netinet/in.h>/span>
#include <netdb.h>/span>
#include <arpa/inet.h>
#include <sys/wait.h>/span>
#include <signal.h>
#define PORT "3490" //the port users will be connecting to
#define BACKLOG 10 //span>佇列將容納多少個待定連接。
void sigchld_handler(int s)
{
(void)s; //安靜的未使用變數警告。
// waitpid()可能會覆寫errno,所以我們要保存并恢復它:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0) 。
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:.
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)-> sin_addr);
}
return &(((struct sockaddr_in6*)sa)-> sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new_fd上的新連接。
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; //連接器的地址資訊。
socklen_t sin_size。
struct sigaction sa;
int yes=1。
char s[INET6_ADDRSTRLEN]。
int rv;
memset(&hints, 0, sizeof hints)。
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; //使用我的IP。
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s
", gai_strerror(rv))。
return 1。
}
// loop through all the results and bind to the first we can.
for(p = servinfo; p != NULL; p = p-> ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket")。
continue。
}
if (setockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int) == -1) {
perror("setockopt")。
exit(1)。
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind")。
繼續。
}
break;
}
freeaddrinfo(servinfo); //全部完成這個結構。
if (p == NULL) {
fprintf(stderr, " server: failed to bind
")。)
exit(1)。
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen")。
exit(1)。
}
sa.sa_handler = sigchld_handler; //收割所有死亡的行程。
sigemptyset(&sa.sa_mask)。
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction")。
exit(1)。
}
printf("server: waiting for connections...
")。)
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&they_addr, &sin_size)。
if (new_fd == -1) {
perror("accept")。
continue。
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)& their_addr),
s, sizeof s)。)
printf("server: got connection from %s
", s)。)
if (!fork()) { //this is the child process.
close(sockfd); //孩子不需要監聽器。
if (send(new_fd, "www.luv2shop.net", 16, 0) == 1)
perror("send")。
close(new_fd)。
exit(0)。
}
close(new_fd); // parent doesn't need this; } close(new_fd)
}
return 0;
}
學習c語言的網路編程
我不明白這段代碼是做什么的,為什么我們需要它。 我正在學習Beej的網路編程指南。sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask)。
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction")。
exit(1)。
來自server.c的代碼
另外,那個 void sigchld_handler(int s) 是做什么的,我們在哪里使用它?
uj5u.com熱心網友回復:
該程式分叉了子行程。父行程的責任是等待它們。這就清理了子行程表中的條目。如果你不這樣做,你的子行程一旦退出就會變成僵尸。
這段代碼為 SIGCHLD 信號設定了一個處理程式。如果一個子行程結束,該信號將被發送到行程中。然后處理程式使用 waitpid 來獲得所有已經退出的子行程的退出狀態。
注意,這個程式沒有使用子行程的退出代碼。
uj5u.com熱心網友回復:
這段代碼在做什么
這段代碼在做什么?
它正在注冊一個信號處理程式,以便在收到SIGCHLD信號時執行。
https://en.wikipedia.org/wiki/Signal_(IPC) https://man7.org/linux/man-pages/man7/signal.7.html
我們在哪里使用它?
信號處理程式呼叫waitpid()來移除僵尸行程。當一個子行程終止時,該代碼被執行:父行程收到SIGCHLD信號,并在信號處理程式中執行wait*()呼叫,通知內核,以便內核可以洗掉子行程。
https://en.wikipedia.org/wiki/Process_state https://en.wikipedia.org/wiki/Zombie_process
那個無效的
?sigchld_handler(int s)在做什么
它宣告了一個名為sigchld_handler()的函式,該函式不回傳任何東西,只接收一個int型別的引數。https://en.cppreference.com/w/cpp/language/function
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/311825.html
標籤:
