깊이 이해 유 닉 스 / linux 시리즈 중 Select () 모델 [중 영 대조]
THE WORLD OF SELECT() So just why am I so hyped on select()? One traditional way to write network servers is to have the main server block on accept(), waiting for a connection. Once a connection comes in, the server fork()s, the child process handles the connection and the main server is able to service new incoming requests. With select(), instead of having a process for each request, there is usually only one process that "multi-plexes" all requests, servicing each request as much as it can. So one main advantage of using select() is that your server will only require a single process to handle all requests. Thus, your server will not need shared memory or synchronization primitives for different 'tasks' to communicate. One major disadvantage of using select(), is that your server cannot act like there's only one client, like with a fork()'ing solution. For example, with a fork()'ing solution, after the server fork()s, the child process works with the client as if there was only one client in the universe -- the child does not have to worry about new incoming connections or the existence of other sockets. With select(), the programming isn't as transparent.
select () 의 세계 - 왜 나 는 select () 에 이렇게 열광 합 니까?
네트워크 서버 프로그램 을 작성 할 때 전통 적 인 방법 은 주요 서비스 코드 를 accept () 블록 에 넣 고 연결 을 기다 리 는 것 입 니 다.연결 이 도착 하면 서버 는 포크 () 함 수 를 호출 하여 하위 프로 세 스 를 생 성하 여 이번 연결 을 처리 합 니 다. 그 다음 에 메 인 서 비 스 는 새로운 연결 요청 을 받 아들 일 수 있 습 니 다.
select () 가 있 으 면 서버 는 모든 연결 에 하나의 프로 세 스 를 만 들 필요 가 없 으 며, 같은 프로 세 스에 서 모든 연결 요청 을 처리 하여 다 중 재 활용 을 실현 하고 모든 연결 서 비 스 를 위해 최선 을 다 할 수 있 습 니 다.
이렇게 보면 select () 의 가장 큰 장점 은 서버 가 시스템 에 하나의 프로 세 스 만 신청 하면 모든 연결 요청 을 처리 하여 서버 가 메모리 공유 나 서로 다른 작업 간 의 동기 화 원 어 통신 에서 벗 어 날 수 있다 는 것 이다.
그러나 select () 도 단점 이 있 습 니 다. 가장 중요 한 것 은 서버 가 '클 라 이언 트 가 하나 밖 에 없다' 는 가설 에서 실행 되 지 못 하고 fork () 처럼 문 제 를 해결 할 수 없다 는 것 입 니 다.예 를 들 어 서버 가 fork () 후 하위 프로 세 스 를 호출 하여 클 라 이언 트 를 처리 할 때 마치 전 세계 에 이 클 라 이언 트 만 존재 하 는 것 같 습 니 다. 나중에 클 라 이언 트 연결 요청 이나 기 존의 소켓 을 걱정 할 필요 가 없습니다.select () 는 모든 소켓 을 이렇게 투명 하 게 대하 지 않 습 니 다.
Okay, so how do you use select()? select() works by blocking until something happens on a file descriptor (aka a socket). What's 'something'? Data coming in or being able to write to a file descriptor -- you tell select() what you want to be woken up by. How do you tell it? You fill up a fd_set structure with some macros. Most select()-based servers look pretty much the same:
그럼 select () 는 어떻게 사용 하나 요?
select () 의 작업 방식 은 파일 설명자 (즉 socket) 에서 지정 한 이벤트 가 실 행 될 때 까지 차단 하 는 것 입 니 다.어떤 사건 이 죠?데이터 가 전송 되 거나 파일 설명 자 를 쓸 준비 가 되 어 있 습 니 다. 이것 은 모두 select () 가 어떤 사건 에 촉발 되 고 싶 은 지 알려 줍 니 다.어떻게 알려 줘 요?매크로 명령 으로 fd 작성set 구조 체.
대부분의 select () 함 수 를 기반 으로 한 서버 는 매우 비슷 한 구 조 를 가지 고 있다.
Fill up a fd_set structure with the file descriptors you want to know when data comes in on.
fd_set
Fill up a fd_set structure with the file descriptors you want to know when you can write on.
fd_set
Call select() and block until something happens. select() Once select() returns, check to see if any of your file descriptors was the reason you woke up. If so, 'service' that file descriptor in whatever particular way your server needs to (i.e. read
in a request for a Web page). select() , , 。 , 。Repeat this process forever. 。
Quit with the pseudo-code, show me some real code!Okay, let's take a look at a sample server included with Vic Metcalfe's Socket Programming FAQ (my comments are in red):
, !
, Vic Metcalfe's Socket Programming FAQ ( )
/*
PLEASE READ THE FILE NB-APOLOGY!!!! There are some things you should
know about this source before you read it. Thanks.
NB-APOLOGY (http://www.lowtek.com/sockets/NB-APOLOGY.txt), 。 !
Quang Ngo alerted me to a bug where the variable listnum in deal_with_data()
wasn't being passed in by parameter, thus it was always garbage. I have
quick-fixed this in the code below. - Spencer (October 12, 1999)
Quang Ngo deal_with_data() listnum , 。 。-Spencer(1999.10.12)
Non blocking server demo
By Vic Metcalfe ([email protected])
For the unix-socket-faq
:Vic Metcalfe ([email protected])
unix-socket-faq
*/
#include "sockhelp.h"
#include <ctype.h>
#include <sys/time.h>
#include <fcntl.h>
int sock; /* */
int connectlist[5]; /* socket , */
fd_set socks; /* select() socket */
int highsock; /* select() */
void setnonblocking(sock)
int sock;
{
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(sock,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
exit(EXIT_FAILURE);
}
return;
}
void build_select_list() {
int listnum; /* connectlist for */
/* fd_set select() , sock , sockets */
/* FD_ZERO() fd_set , */
FD_ZERO(&socks);
/* FD_SET() “sock” fd_set , select() ( accept() )*/
FD_SET(sock,&socks);
/* fd_set */
for (listnum = 0; listnum < 5; listnum++) {
if (connectlist[listnum] != 0) {
FD_SET(connectlist[listnum],&socks);
if (connectlist[listnum] > highsock)
highsock = connectlist[listnum];
}
}
}
void handle_new_connection() {
int listnum; /* connectlist for */
int connection; /* socket */
/* ! connectlist */
connection = accept(sock, NULL, NULL);
if (connection < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(connection);
for (listnum = 0; (listnum < 5) && (connection != -1); listnum ++)
if (connectlist[listnum] == 0) {
printf("
Connection accepted: FD=%d; Slot=%d
",
connection,listnum);
connectlist[listnum] = connection;
connection = -1;
}
if (connection != -1) {
/* No room left in the queue! */
printf("
No room left for new client.
");
sock_puts(connection,"Sorry, this server is too busy. "
Try again later!\r
");
close(connection);
}
}
void deal_with_data(
int listnum /* connectlist for */
) {
char buffer[80]; /* socket */
char *cur_char; /* */
if (sock_gets(connectlist[listnum],buffer,80) < 0) {
/* , connectlist */
printf("
Connection lost: FD=%d; Slot=%d
",
connectlist[listnum],listnum);
close(connectlist[listnum]);
connectlist[listnum] = 0;
} else {
/* , */
printf("
Received: %s; ",buffer);
cur_char = buffer;
while (cur_char[0] != 0) {
cur_char[0] = toupper(cur_char[0]);
cur_char++;
}
sock_puts(connectlist[listnum],buffer);
sock_puts(connectlist[listnum],"
");
printf("responded: %s
",buffer);
}
}
void read_socks() {
int listnum; /* connectlist for */
/* socket sock , socket, connectlist socket*/
/* connect() socket,select() socket 。
, socket fd_set , 。*/
if (FD_ISSET(sock,&socks))
handle_new_connection();
/* connectlist */
/* socket, , , */
for (listnum = 0; listnum < 5; listnum++) {
if (FD_ISSET(connectlist[listnum],&socks))
deal_with_data(listnum);
} /*for ( )*/
}
int main (argc, argv)
int argc;
char *argv[];
{
char *ascport; /* ASCII */
int port; /* ACII */
struct sockaddr_in server_address; /* */
int reuse_addr = 1; /* TIME_WAIT */
struct timeval timeout; /* select */
int readsocks; /* socket */
/* */
if (argc < 2) {
printf("Usage: %s PORT\r
",argv[0]);
exit(EXIT_FAILURE);
}
/* socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
/* TIME_WAIT */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
/* sernonblocking socket */
setnonblocking(sock);
/* , socket*/
ascport = argv[1]; /* */
port = atoport(ascport); /* sockhelp int */
memset((char *) &server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = port;
if (bind(sock, (struct sockaddr *) &server_address, sizeof(server_address)) < 0 ) {
perror("bind");
close(sock);
exit(EXIT_FAILURE);
}
/* */
listen(sock,5);
/* socket, socket */
highsock = sock;
memset((char *) &connectlist, 0, sizeof(connectlist));
while (1) { /* */
build_select_list();
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* select() +1, FD_SETSIZE */
/* select() socket fd_set ( socket)*/
/* select() fd_set, , 0 NULL。*/
/* select() OOB ( )sockets, , */
/* select() 。 , NULL*/
readsocks = select(highsock+1, &socks, (fd_set *) 0, (fd_set *) 0, &timeout);
/* select() socket, socket*/
/* select() , fd_set select() 。
:4 fd_set, ,fd_set */
if (readsocks < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (readsocks == 0) {
/* , “.” */
printf(".");
fflush(stdout);
} else
read_socks();
} /* while(1) */
} /* main */
Okay, so maybe that wasn't the best example...
,
Got some suggests? Corrections? Please let me know.
, 。
In the mean time, here's some references to other sources of information about select():
, select()
Socket FAQ Question about select()
Straight from the excellent socket FAQ.
socket FAQ
Unix Programming FAQ Question about select()
Straight from the other excellent FAQ.
socket FAQ
Unix Socket Programming FAQ Examples
The above nbserver.c sample code and more socket stuff.
이상 nbserver. c 소스 코드 및 더 많은 socket 루틴
thttpd - tiny/turbo/throttling HTTP server
작은 단일 스 레 드, 비 fork (), select () 기반 웹 서버.
BOA
Another single-threaded, select() based Web server. , select() Web .
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
React 구성 요소에서 소켓 이벤트 리스너가 여러 번 실행됩니다.기본적이지만 종종 간과되는 사이드 프로젝트를 하면서 배운 것이 있습니다. 이 프로젝트에는 단순히 두 가지 주요 부분이 포함되어 있습니다. 프런트 엔드: 반응 및 재료 UI 백엔드: Express, Typescript...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.