TCP/IP read(), write() timeout 설정

anaud2의 이미지

안녕하세요

TCP/IP 소켓 기반으로 간단한 전문을 날리는 함수를 만들었는데요
처음에 read나 write시에 전송이 한번에 이루어지지 않았을때를 대비해서 반복문을 넣으라는
말을 듣고
int recvMSG(int sock, void *buf, int bufLen)
{
int len = 0;
while((len = read(sock, buf, bufLen)) >= 0){
bufLen -= len;
buf += len;
printf("len [%d]\n",len);
if(!bufLen){
return 0;
}
}
close(sock);
return -1;
}
이렇게 반복이 되게 만들었어요

그런데 문제는 read나 write가 무한정 대기를 막기위해 Timeout을 설정하라는 명령을 듣고
alarm()을써서 막기위해 수정을 했습니다.
==================================
alarm()사용설정
==================================
struct sigaction sigact, oldact;
sigact.sa_handler = sig_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_flags |= SA_INTERRUPT;
// 바로 이부분이 SIGNAL 을 받았을때
// Interrupt 가 발생하도록 설정하는 부분이다.

if(sigaction(SIGALRM, &sigact, &oldact) < 0)
{
perror("sigaction error : ");
exit(0);
}
=========================================
alarm()사용
=========================================
alarm(5);
if (recvMSG(server_sockfd, buf, 80) <= 0)
{
printf("test\n");
if(errno == EINTR)
{
printf("signal Interrupt\n");
return 1;
}
perror("read error : ");
close(server_sockfd);
exit(0);
}
====================================================
"위의 구현을 하는데 있어서 핵심은 SIGALRM 에 대해서 interrupt 가 프로세스로 전달되게 하는 부분이다. 또한 read, write 등의 함수가 Interrupt 를 받아서 리턴되었을경우를 처리하기 위한 코드가 추가된다. 이들 함수는 Interrupt 를 받고 리턴되었을경우 errno 값을 EINTR 로 설정함으로 errno 값을 한번만 검사해주면 문제 없이 처리 가능하다."

제가 찾은 자료에는 위의 글이 써있었구 또한 read를 대기만 하고 있다면 문제 없이 돌아갑니다.
그러나 문제는 만약 저 read()상태에서 서버가 Ctrl+C를 눌러서 접속을 비정상적으로 종료를 한다면..
실험을 해보니까
read 반복 되는 함수에서 계속 전송 0리턴 전송 0리턴으로 무한 루프를 돌고 있더라구요
그다음 믿었던 Timeout은 울리지 않습니다. ㅠ

다됐다라고 오늘 반나절을 투자한부분이 날라갔어요 ㅠㅠ
이걸 어케 해결해야할지 모르겠네요
도움좀 부탁드려요~ㅠ

PS.참고로 UDP가 아니라 TCP로 전송하니까 블록단위 입니다.

ddoman의 이미지

read, write의 timeout을 처리하기 위해서는 select나 poll을 쓰세요.
아니면 asynchronous I/O 를 하시던지

timeout처리를 저렇게 sig_alrm 으로도 처리를 하는군요...처음 알았지만, 그닥 좋은 방법이 아닌거 같네요.
multi-thread를 써서 서버를 만들 때도 저렇게 한다면 시그널은 쓰레드 마다 각각 관리되는게 아니라서
당근 문제가 엄청 많아 질 것이고..

암튼 select나 poll 을 쓰세요.

kewlbear의 이미지

read의 반환값이 0인 경우에도 반복을 중단해야 합니다. 접속이 끊어진 것이니까요.

모지리의 이미지

좀 안전하게 select같은것을 이용하시고 넌블락 모드로 돌리시면
대부분의 모드에서 잘 작동할것입니다. 이때 주의 하실점은

1. 리턴값을 가지고 판단
2. 그리고 에러번호도 판단의 기준이됨.

이것뿐입니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.