주요 콘텐츠로 건너뛰기
네트워크 응용 프로그램을 작성할 때 차단 되지 않는 모드 또는 차단 모드를 사용할 수 있습니다. 비 차단 모드는 응용 프로그램이 여러 소켓을 서비스하는 것과 같은 여러 작업을 수행해야 할 때 보다 유연하며 필요합니다. 그러나 응용 프로그램이 소켓에서 읽고 파일 이나 큐에 데이터를 작성하는 경우 차단 모드를 사용하면 응용 프로그램의 복잡성을 크게 줄일 수 있습니다. 응용 프로그램이 모를 수 있는 연결에 문제가 있는 경우 차단 모드에 작은 문제가 있습니다. 그것은 도착하지 않습니다 데이터를 영원히 기다릴 것입니다.

 

어떻게 그런 일이 일어날 수 있습니까? 응용 프로그램이 recv를 호출하고 클라이언트의 데이터를 기다리고 있다고 가정해 보십시오. 클라이언트의 네트워크 연결은 신뢰할 수 없으며 클라이언트 응용 프로그램에서 여러 재전송이 발생합니다. 어떤 시점에서 클라이언트의 TCP 스택은 연결을 종료해야 한다고 결정합니다. 클라이언트 응용 프로그램에 통보하고 소켓을 정리합니다. 응용 프로그램은 클라이언트가 닫혀 있는 연결의 데이터를 기다리는 상태로 남아 있습니다. 문제를 제거하는 유일한 방법은 수동으로 응용 프로그램을 종료하고 다시 시작하는 것입니다. 응용 프로그램을 종료하면 연결된 소켓이 "TIME_WAIT" 상태로 남게 되며, reUSEADDR 소켓 옵션을 설정하지 않으면 응용 프로그램을 즉시 다시 시작하고 수신 소켓에 바인딩하는 것을 방지할 수 있습니다.

 

그러나 OpenVOS에 recv 호출 중에 데이터를 기다리는 기간에 대한 시간 제한을 설정하도록 지시할 수 있습니다. 그 결과 시간 제한이 만료되면 호출이 -1로 반환되고 errno는 e$timeout(1081)으로 설정됩니다. 그런 다음 응용 프로그램을 진행 하는 방법에 대 한 결정을 내릴 수 있습니다. 연결을 종료하거나 클라이언트에게 다른 기회를 제공하거나, 클라이언트에 연결을 테스트하기 위해 무언가를 보내거나, 다른 응용 프로그램에 적절한 응답을 보낼 수 있습니다. 요점은 상황의 진단과 응답이 통제하에 있다는 것입니다.
그림 2의 프로그램 timeout_recv.c는 이 작업을 수행하는 방법의 예입니다. 2개의 인수, 청취할 포트 번호, 1/1024 초 단위로 시간 시간이 걸립니다. 도 1은 예제 실행을 나타내며,명령줄(굵게 표시되고 밑줄이 밑줄)은모든 인수가 대화형 프로그램에 의해 반향되어야 한다고 굳게 믿기 때문에 에코된다. 참고 10 초 (10240 / 1024) 시간 아웃을 설정했습니다. 프로그램은 수락을 호출할 때 보고하고 수락하면 시간 아웃을 반환합니다. 나는 이전 단락에서 그것을 언급하지 않았지만 시간 제뿐만 아니라 수락 전화에 작동하고 프로그램은 그것을 보여줍니다. 연결이 이루어진 후에는 recv를 호출할 때 보고되고 recv가 시간 외 또는 문자로 반환된 시간을 보고합니다. 나는 모든 시간 중지 메시지를 강조했다.

 

시간 제한을 설정하는 호출은 OpenVOS(및 VOS)에 특정합니다. 이 방법은 다른 운영 체제에서 작동하지 않습니다.

 

timeout_recv 5647 10240
command line was: timeout_recv 5647 10240
timeout_recv: 12:14:27 calling accept
timeout_recv: 12:14:37 accept returned a timeout
timeout_recv: 12:14:37 calling accept
timeout_recv: 12:14:47 accept returned a timeout
timeout_recv: 12:14:47 calling accept
timeout_recv: 12:14:48 calling recv
timeout_recv: 12:14:58 recv returned a timeout
timeout_recv: 12:14:58 calling recv
timeout_recv: 12:15:00 recv return 1 characters
timeout_recv: 12:15:00 calling recv
timeout_recv: 12:15:10 recv returned a timeout
timeout_recv: 12:15:10 calling recv
timeout_recv: 12:15:16 recv return 1 characters
timeout_recv: 12:15:16 calling recv
timeout_recv: 12:15:23 recv return 1 characters
timeout_recv: 12:15:23 calling recv
timeout_recv: 12:15:30 recv return 1 characters
timeout_recv: 12:15:30 calling recv
timeout_recv: 12:15:38 recv return 1 characters
timeout_recv: 12:15:38 calling recv
timeout_recv: 12:15:46 recv return 1 characters
timeout_recv: 12:15:46 calling recv
timeout_recv: 12:15:56 recv returned a timeout
timeout_recv: 12:15:56 calling recv
timeout_recv: client terminated connection at 12:16:00
ready 12:16:00

 

그림 1 - timeout_recv 예제 실행
/* *****************************************************************
timeout_recv written by NSDavids Stratus CAC
10-04-23 version 1.0 initial release
This is a demonstration of timing out blocking accept and recv calls
and returning control to the program.
***************************************************************** */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define bzero(s, len)             memset((char *)(s), 0, len)
int errno;
void s$set_io_time_limit(short int *, long int *, short int *);
int s$c_get_portid_from_fildes(int file_des);
/* this routine returns the current time as a string */
char * GetCurrentTime (char * szT)
{
time_t tTime;
struct tm *tmLT;
tTime = time ((time_t *) 0);
tmLT = localtime (&tTime);
sprintf (szT, "%02ld:%02ld:%02ld",
tmLT -> tm_hour,
tmLT -> tm_min,
tmLT -> tm_sec);
return (szT);
}
/* this routine sets the time out value on the port associated
with the socket. These calls are VOS specific, this program
is not portable to other environments. i.e. Windows or Linux */
int SetTimeOut (int iSocket, int iTimeLimit, char * szType)
{
long lPortID;
short sPortID;
long lTimeLimit;
short sError;
if ((lPortID = s$c_get_portid_from_fildes(iSocket)) == -1)
{
printf ("timeout_recv: Error getting port ID of %s socketn", szType);
exit (-1);
}
sPortID = (short)lPortID;
if (iTimeLimit > 0)
{
lTimeLimit = iTimeLimit;
s$set_io_time_limit (&sPortID, &lTimeLimit, &sError);
if (sError != 0)
{
printf ("timeout_recv: Error %d setting time out of %s socketn",
szType, sError);
exit (sError);
}
}
return (0);
}
main (argc, argv)
int    argc;
char   *argv [];
{
int    iCliLen;
struct sockaddr_in sockCliAddr, sockServAddr;
short sPortNo;
int    iBytes;
int    iTimeLimit;
char   szT [32];
int    iListenSock, iAcceptedSock;
#define BUFFERLEN 100
char   szBuffer [BUFFERLEN];
/* process the arguments */
if (argc == 3)
{
sPortNo = atoi (argv [1]);
iTimeLimit = atoi (argv [2]);
printf ("command line was: timeout_recv %d %dnn", sPortNo, iTimeLimit);
}
else
{
printf
("nUsage: timeout_recv <port_number> <time_limit in 1/1024s of a sec)n");
exit (-1);
}
/* set up a listening socket */
if ((iListenSock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
printf ("timeout_recv: Error %d can't open stream socket", errno);
bzero ( (char *) &sockServAddr, sizeof (sockServAddr));
sockServAddr.sin_family        = AF_INET;
sockServAddr.sin_addr.s_addr   = htonl (INADDR_ANY);
sockServAddr.sin_port          = htons (sPortNo);
if (bind (iListenSock,
(struct sockaddr *) &sockServAddr, sizeof (sockServAddr)) < 0)
{
printf ("timeout_recv: Error %d can't bind local addressn", errno);
exit (errno);
}
listen (iListenSock, 5);
SetTimeOut (iListenSock, iTimeLimit, "Listening");
/* In most cases I expect that an application will just block waiting for
a connection. However, I wanted to show that you can also timeout the
call to accept */
iAcceptedSock = 0;
while (iAcceptedSock < 1)
{
printf ("timeout_recv: %s calling acceptn", GetCurrentTime (szT));
iAcceptedSock = accept (iListenSock,
(struct sockaddr *) &sockCliAddr, &iCliLen);
if (iAcceptedSock < 0)
{
if (errno == 1081)
printf ("timeout_recv: %s accept returned a timeoutn",
GetCurrentTime (szT));
else
{
printf ("timeout_recv: %s accept returned the unexpected error %dn",
GetCurrentTime (szT), errno);
exit (errno);
}
iAcceptedSock = 0;
}
}
/* set the timeout on the newly accepted socket */
SetTimeOut (iAcceptedSock, iTimeLimit, "Accepted");
/* main loop, call recv and process the return value. If the return value is
-1 then it is an error. An errno of 1081 (e$timeout) is expected, report
it and continue. Any other error is unexpected and fatal. If the return
value is 0 it means the client terminated the connection, report it
and exit. If the return value is > 0 it indicates the number of
characters received, report it and continue the loop. */
while (1)
{
printf ("timeout_recv: %s calling recvn", GetCurrentTime (szT));
iBytes = recv (iAcceptedSock, szBuffer, BUFFERLEN, 0);
if (iBytes == -1)
{
if (errno == 1081)
printf ("timeout_recv: %s recv returned a timeoutn",
GetCurrentTime (szT));
else
{
printf ("timeout_recv: %s recv returned the unexpected error %dn",
GetCurrentTime (szT), errno);
exit (errno);
}
}
else
if (iBytes == 0)
{
printf ("timeout_recv: client terminated connection at %sn",
GetCurrentTime (szT));
exit (0);
}
else
printf ("timeout_recv: %s recv return %d charactersn",
GetCurrentTime (szT), iBytes);
}
}

 

그림 2 – timeout_recv.c

© 2024 스트라투스 테크놀로지스.