서버 프로그램 종료시에

익명 사용자의 이미지

서버 프로그램은 보통 클라이언트의 요구를 항상 기다리고 있습니다.

만약 소켓을 이용해 서버 프로그램을 짠다면, 보통의 경우 클라이언트의 요구를 듣기
위해 항상

accept() 함수가 동작중입니다.

그러나 서버 프로그램을 종료해야할 경우에는 어떻게 해야하나요? accept() 함수가
리턴이 되어야

소켓을 닫고 메모리를 정리한 다음 정상적으로 끝낼 수 있는데, accept()함수는
클라이언트의 요구를

받기 전까지는 리턴을 하지 않으니...

혹시 이런 문제의 그럴 듯한 해법을 알고 계신분 있나요???

익명 사용자의 이미지

accept하기전 select나 poll을 사용하셔서, 뭐가 왔다라는게 판명되면 그때 accept
를 사용하시면 되겠습니다.

while(샤랄라) {
if(서버가 죽어야만 되는 상황인가?==아니오) {
if(poll()쓰는법 자세히 모름) {
if((accept()역시 자세히 모름)) {
접속 처리;
}
}
}
else
서버를 죽이기 시작한다;
}

man poll
man select

익명 사용자의 이미지

서버를 처음 디지인할때, 어떤 모델로 설정하고 코드를 작성하였는지에
따라 구체적인 방법이 나올수가 있겠군요.

먼저 서버를 어떤 모델로 하고자 하는데 이럴땐 어떻게 해야하는가 정도
로는 질문해야 구체적인 실례를 들어가면서 설명해줄수가 있겠네요.

지금 답해드릴수있는것은, 단지 accept ( )때문에 서버를 정상적으로 종
료못시키는 것은 아닙니다. 모델에 따라 어떻게 디자인했냐에 따라 처리
방법도 다양하겠죠.. -_-

익명 사용자의 이미지

몇가지 방법이 있습니다.

1. 논블럭킹 소켓

/*
* do a non-blocking-accept
*
* tested with FreeBSD
*
* Steve Shah (sshah@planetoid.org)
*
*/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]

int main (int argc, char *argv[])
{
struct sockaddr_in incoming_connection;
struct sockaddr_in bound_connection;
int incoming_fd;
int incoming_socket;
unsigned int incoming_connection_len;
struct protoent *tcp;
int port;
int errcode;
int i;
char buf[80];
int buflen;

/*
* Parse command line parameters
*
*/

if (argc < 2) {
printf ("Usage non-blocking-accept \n");
exit(0);
}

port = atoi(argv[1]);
if (port < 1024 || port > 65534) {
printf ("Port number is out of range.\n");
exit(0);
}


/*
* Get TCP's protocol number (needed for the socket() system call)
*
*/

tcp = getprotobyname("tcp");
if (tcp == NULL) {
printf ("Can't get protocol numbers for TCP\n");
exit(0);
}

/*
* Create a new socket
*
*/

incoming_socket = socket(AF_INET, SOCK_STREAM, tcp->p_proto);
if (incoming_socket < 0) {
printf ("Can't create a socket\n");
exit(0);
}

/*
* Bind to a specific port using the new socket
*
*/

bound_connection.sin_family = AF_INET;
bound_connection.sin_addr.s_addr = htonl(INADDR_ANY);
bound_connection.sin_port = htons(port);

/* Note that sockaddr_in is a internet interpretation of sockaddr */

errcode = bind(incoming_socket,
(struct sockaddr *)&bound_connection,
sizeof (struct sockaddr));
if (errcode < 0) {
printf ("Can't bind to port %d", port);
perror("");
exit(0);
}

/*
* Tell us how many incoming connections we can at most queue
*
*/

errcode = listen(incoming_socket, 128);
if (errcode == -1) {
perror ("Can't listen to bound socket");
exit(0);
}

/*
* Make socket non-blocking
*
*/

if (fcntl(incoming_socket, F_SETFL, O_NDELAY) < 0) {
perror("Can't set socket to non-blocking");
exit(0);
}

/*
* Enter the accept loop
*
*/

incoming_connection_len = sizeof(struct sockaddr_in);

do {
incoming_fd = accept(incoming_socket,
(struct sockaddr *)&incoming_connection,
&incoming_connection_len);
if (incoming_fd != -1) {
printf ("Accepted connection from %d.%d.%d.%d%d\n",
NIPQUAD(incoming_connection.sin_addr.s_addr),
ntohs(incoming_connection.sin_port));
for (i=10;i>=1;i--) {
buflen = snprintf (buf, 80, "%d\n", i);
write (incoming_fd, buf, buflen);
sleep(1);
}
close (incoming_fd);
} else {
printf ("Waiting for a connection...\n");
sleep(1);
}
} while (1);

return 0;
}

=========================================================================
2. multiplexing i/o를 사용해서 하는 방법
accept도 결국은 read이벤트에 걸리니까 select리턴 후
ISSET(listen_fd)를 걸었을때 이벤트가 있으면 accept 처리하면 됩니다.
select에서 일정 시간만큼 timeout을 걸어서 종료조건이 되면
서버를 종료 시킬 수 있습니다.

#include
#include
#include
#include
#include
#include
#define TRUE 1

/*
* This program uses select to check that someone is trying to connect
* before calling accept.
*/

main()
{
int sock, length;
struct sockaddr_in server;
int msgsock;
char buf[1024];
int rval;
fd_set ready;
struct timeval to;

/* Create socket. */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Name socket using wildcards. */
server.sin_len = sizeof(server);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = 0;
if (bind(sock, (struct sockaddr *)&server,
sizeof(server)) < 0) {
perror("binding stream socket");
exit(1);
}
/* Find out assigned port number and print it out. */
length = sizeof(server);
if (getsockname(sock, (struct sockaddr *)&server,
&length) < 0) {
perror("getting socket name");
exit(1);
}
printf("Socket port #%d\n", ntohs(server.sin_port));

/* Start accepting connections. */
listen(sock, 5);
do {
FD_ZERO(&ready);
FD_SET(sock, &ready);
to.tv_sec = 5;
if (select(sock + 1, &ready, (fd_set *)0,
(fd_set *)0, &to) < 0) {
perror("select");
continue;
}
if (FD_ISSET(sock, &ready)) {
msgsock = accept(sock, (struct sockaddr *)0,
(int *)0);
if (msgsock == -1)
perror("accept");
else do {
memset(buf, 0, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
} else
printf("Do something else\n");
} while (TRUE);
exit(0);
}

=========================================================================
3. alarm을 사용해서 지정 시간동안 접속이 없으면 accept를
빠져나와서 다른 작업을 하고, 종료 조건이 아니면
다시 알람을 설정하고 잠들면 되겠죠.

/******************************************************************/
/* Include files */
/******************************************************************/
#include
#include
#include
#include
#include
#include
#include

/******************************************************************/
/* Signal catcher routine. This routine will be called when the */
/* signal occurs. */
/******************************************************************/
void catcher(int sig)
{
printf(" Signal catcher called for signal %d\n", sig);
}

/******************************************************************/
/* Main program */
/******************************************************************/
int main(int argc, char *argv[])
{
struct sigaction sact;
struct sockaddr_in addr;
time_t t;
int sd, rc;

/******************************************************************/
/* Create an AF_INET, SOCK_STREAM socket */
/******************************************************************/
printf("Create a TCP socket\n");
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1)
{
perror(" socket failed");
return(-1);
}

/******************************************************************/
/* Bind the socket. A port number was not specified because */
/* we are not going to ever connect to this socket. */
/******************************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
printf("Bind the socket\n");
rc = bind(sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc != 0)
{
perror(" bind failed");
close(sd);
return(-2);
}

/******************************************************************/
/* Perform a listen on the socket. */
/******************************************************************/
printf("Set the listen backlog\n");
rc = listen(sd, 5);
if (rc != 0)
{
perror(" listen failed");
close(sd);
return(-3);
}

/******************************************************************/
/* Set up an alarm that will go off in 5 seconds. */
/******************************************************************/
printf("\nSet an alarm to go off in 5 seconds. This alarm will cause the\n");
printf("blocked accept() to return a -1 and an errno value of EINTR.\n\n");
sigemptyset(&sact.sa_mask);
sact.sa_flags = 0;
sact.sa_handler = catcher;
sigaction(SIGALRM, &sact, NULL);
alarm(5);

/******************************************************************/
/* Display the current time when the alarm was set */
/******************************************************************/
time(&t);
printf("Before accept(), time is %s", ctime(&t));

/******************************************************************/
/* Call accept. This call will normally block indefinitely, */
/* but because we have an alarm set, it will only block for */
/* 5 seconds. When the alarm goes off, the accept call will */
/* complete with -1 and an errno value of EINTR. */
/******************************************************************/
errno = 0;
printf(" Wait for an incoming connection to arrive\n");
rc = accept(sd, NULL, NULL);
printf(" accept() completed. rc = %d, errno = %d\n", rc, errno);
if (rc >= 0)
{
printf(" Incoming connection was recevied\n");
close(rc);
}
else
{
perror(" errno string");
}

/******************************************************************/
/* Show what time it was when the alarm went off */
/******************************************************************/
time(&t);
printf("After accept(), time is %s\n", ctime(&t));
close(sd);
return(0);
}

익명 사용자의 이미지

저도 고민한적이있었는데.. 아파치나 다른 서버프로그램들의
스크립트를 보니 그냥 kill 로 죽이는거 같던데요.. stop 할때..
이건 안좋은건가요?
서버프로그램이 데몬일경우 ..그특징상 따로 어떻게 제어할 인터페이스를
마련하는것도 쉽지는 않을꺼 같은데..

허접의말에 답변좀 부탁드립니다.

익명 사용자의 이미지

킬은 특정 프로세스에게
특정 시그널을 보내는 것입니다.

터미널을 갖고 있지 않는 DAEMON 들은 대부분
HUP 시그널을 사용하여 초기화(?) 되도록 프로그램되어 있습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.