태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
블로그 이미지
하늘을 헤엄치다. revoman

카테고리

분류 전체보기 (176)
Eye (13)
Programming (82)
Unix & Linux (52)
Android (3)
Tool and Tip (13)
시스템 관리 (7)
OPEN SOURCE (2)
XML (1)
WEB (0)
MY PROGRAM (1)
정보관리기술사 기출.. (1)
IT 동향 (1)
Total56,866
Today6
Yesterday34
1. The C10K problem : 대용량 연결 처리와 관련된 다양한 I/O 전략과 메카니즘에 대한 소개
     : http://www.kegel.com/c10k.html

2. libevent : OS에 독립적으로 최적화된 I/O 메카니즘을 제공하는 이벤트 통지 기반의 라이브러리
     : http://www.monkey.org/~provos/libevent/

3. epoll 관련 웹페이지들
     : http://kldp.org/node/50110 - [번역] epoll : level triggered patch 를 내놓으면서.
     : http://www.xevious7.com/52 - epoll 서버 샘플 프로그래밍
Posted by revoman
TAG C, libevent
원문 : http://www.wangafu.net/~nickm/libevent-book/TOC.html

libevent에 대한 사용법과 네트워크 프로그래밍에 대한 쉬운 예제와 설명이 기술되어 있다.
Posted by revoman
TAG C

const 변수

Programming/C++ / 2010/04/26 09:14
const 변수는 변수를 상수화 시킨 것을 의미한다.

const int : 변수의 값을 변경시킬 수 없다.
  const int a = 10;
  a = 20; /* 허용 안됨 */

const int * : 포인터가 가리키는 곳의 값을 변경시킬 수 없다.
  const int *a = &b;
  *a = 10; /* 허용 안됨 */

int * const : 포인터가 기리키는 곳을 변경시킬 수 없다.
  int * const a = &b;
 a = &c; /* 허용 안됨 */

const int * const : 포인터가 가리키는 곳과 값을 변경시킬 수 없다.
 const int * const a = &b;
 a = &c; /* 허용 안됨 */
 *a = 10; /* 허용 안됨 */
Posted by revoman
TAG C, C++

원문 정보

1. 데브코아 (http://cafe.naver.com/devcore/243, http://cafe.naver.com/devcore/244)

2. http://superkkt.com/229

3. http://en.wikipedia.org/wiki/Memory_alignment

4. http://en.wikipedia.org/wiki/Bus_error


인용

특정 CPU에서는 정렬되지 않은 메모리 주소에 접근(read or write)하려고 하면 BUS error가 발생한다.

여기서 특정 CPU라고 언급을 했는데 일반적으로 SPARC 같은 RISC 계열 CPU는 정렬되지 않은 메모리 주소에 접근 할 수 없고, x86 같은 CISC 계열은 접근이 가능하다. 그리고 정렬되지 않은 주소란 뜻은 CPU's memory-alignment rules의 배수에 해당하지 않는 메모리 주소를 뜻한다.

 

우리가 일반적으로 사용하는 x86 CPU는 프로그램이 정렬되지 않은 메모리 주소에 접근할 경우 정렬된메모리 주소를 사용해서 앞 ,뒤 메모리를 두 번 읽고, mask와 shift 과정을 거쳐서 프로그램이 요청한 메모리의 값을 돌려준다. 반면에 SPARC CPU는 바로 BUS error를 발생시켜서 프로그램이 종료된다.

 

하지만 CPU가 정렬되지 않은 메모리 주소에 접근 할 수 없다고 해서 메모리를 바이트 단위로접근 할 수 없다는 뜻은 아니다. 대 부분의 CPU(x86, SPARC, 기타 등등)는 메모리 주소에 바이트단위 접근을 허용한다. 하지만 위에서 x86 CPU가 정렬되지 않은 메모리에 주소에 접근하는 방법과 마찬가지로 데이터 버스 사이즈만큼 메모리를 읽어 들여서 mask, shift 과정을 거쳐서 바이트 단위로 메모리 값을 참조 할 수 있다. 하지만 이 방법은 비효율적이다. 그러나 문자열을 다루는 프로그램처럼 바이트 단위 처리가 꼭 필요한 경우에는 어쩔 수 없이 메모리에 바이트 단위로 접근을 해야 한다.

 

그럼 바이트 단위로 메모리에 접근이 가능한데 언제 BUS error가 발생하는 걸까? 한마디로 요약하면

아래와 같다.

"정렬되지 않은 메모리 주소에 바이트 단위로 접근하는 것은 허용되지만, 그 이상의 사이즈를 가지는타입으로 접근하면 BUS error가 발생한다."



There are two main causes of bus errors:

non-existent address 
The CPU is instructed by software to read or write a specific physical memory address. Accordingly, the CPU sets this physical address on its address bus and requests all other hardware connected to the CPU to respond with the results, if they answer for this specific address. If no other hardware responds, the CPU raises an exception, stating that the requested physical address is unrecognised by the whole computer system. Note that this only covers physical memory addresses. When software tries to access an undefined virtual memory address, that is generally considered to be a segmentation fault rather than a bus error, though if the MMU is separate, the processor can't tell the difference.
unaligned access 
Most CPUs are byte-addressable, where each unique memory address refers to an 8-bit byte. Most CPUs can access individual bytes from each memory address, but they generally cannot access larger units (16 bits, 32 bits, 64 bits and so on) without these units being "aligned" to a specific boundary, such as 16 bits (addresses 0, 2, 4 can be accessed, addresses from 1, 3, 5, are unaligned) or 32 bits (0, 4, 8, 12 are aligned, all addresses in-between are unaligned). Attempting to access a value larger than a byte at an unaligned address can cause a bus error.



Posted by revoman
[MSG Q]
1. LINUX
   msgctl() () 인자에 MSG_INFO, MSG_STAT flag를 사용한다.
2. HP-UX
   pstat_getipc() 함수 사용
3. SOLARIS
    msgids() 함수를 사용해서, ipc queue id 리스트를 읽은 후, loop를 돌면서 msgctl(..,IPC_STAT,…)을 호출한다.

[SHM]
1. LINUX
   shmctl() () 인자에 SHM_INFO, SHM_STAT flag를 사용한다.
2. HP-UX
   pstat_getshm() 함수 사용
3. SOLARIS
    shmids() 함수를 사용해서, shm id 리스트를 읽은 후, loop를 돌면서 shmctl(..,IPC_STAT,…)을 호출한다.
Posted by revoman
TAG C, unix

Preprocessor

  • 소스 코드의 헤더 파일은 항상 inclusion guard를 포함해야 한다.

Compliant Solution
#ifndef _HEADER_H_
#define _HEADER_H_
/* ... contents of the header */
#endif /* _HEADER_H_ */


  • 소스 코드 및 주석에서 반복되는 ? 를 사용하지 말아야 한다.

Noncompliant Code Example Compliant Solution
size_t i = /* some initial value */;
if (i > 9000) {
   if (puts("Over 9000!??!") == EOF) {
     /* Handle Error */
   }
}
size_t i = /* some initial value */;
/* assignment of i */
if (i > 9000) {
   if (puts("Over 9000!?""?!") == EOF) {
     /* Handle Error */
   }
}

Declarations and Initialization

  • 함수에 의하여 변경되지 않는 parameter를 위한 pointer는 const로 선언한다.

Noncompliant Code Example Compliant Solution
void foo(int * x) {
  if (x != NULL) {
    printf("Value is %d\n", *x);
  }
  /* ... */
}
void foo(const int * x) {
  if (x != NULL) {
    printf("Value is %d\n", *x);
  }
  /* ... */
}


  • 내부에서만 사용되는 함수는 항상 static으로 선언한다.

Noncompliant Code Example Compliant Solution
enum { MAX = 100 };

int helper(int i) {
  /* perform some computation based on i */
}

int main(void) {
  size_t i;
  int out[MAX];

  for (i = 0; i < MAX; i++) {
    out[i] = helper(i);
  }

  /* ... */

}
enum {MAX = 100};

static int helper(int i) {
  /* perform some computation based on i */
}

int main(void) {
  size_t i;
  int out[MAX];

  for (i = 0; i < MAX; i++) {
    out[i] = helper(i);
  }

  /* ... */

}


  • source buff 와 destination buff는 같은 메모리 공간이 되지 않도록 설계한다.

Noncompliant Code Example
char str[]= "test string";
char *ptr1=str;
char *ptr2;

ptr2 = ptr1 + 3;
memcpy(ptr2, ptr1, 6);

Expression

  • 두 structure를 비교할때는 memcmp() 함수를 사용하지 않고 직접 비교한다.

Noncompliant Code Example Compliant Solution
struct my_buf {
  char buff_type;
  size_t size;
  char buffer[50];
};

unsigned int buf_compare(
  const struct my_buf *s1, 
  const struct my_buf *s2) 
{
  if (!memcmp(s1, s2, sizeof(struct my_buf))) {
    return 1;
  }
  return 0;
}

struct my_buf {
  char buff_type;
  size_t size;
  char buffer[50];
};

unsigned int buf_compare(
  const struct my_buf *s1, 
  const struct my_buf *s2) 
{
  if (s1->buff_type != s2->buff_type) return 0;
  if (s1->size != s2->size) return 0;
  if (strcmp(s1->buffer, s2->buffer) != 0) return 0;
  return 1;
}

Integer, Float, Array, String

  • 배열의 길이를 나타내는 parameter는 int 형대신 size_t, ssize_t 형을 사용한다.
    • 32bit 머신과 64bit 머신간의 호환성을 위함

Noncompliant Code Example Compliant Solution
char str = "abc";
int len;

len = strlen(str);
  ...
}
char str = "abc";
size_t len;

len = strlen(str);
  ...


  • atoi() 함수류 대신에 strtol() 함수류를 사용한다.
    • atoi() 함수류는 error를 detect할수 없다.
 atoi: (int)strtol(nptr, (char **)NULL, 10)
 atol: strtol(nptr, (char **)NULL, 10)
 atoll: strtoll(nptr, (char **)NULL, 10)

Noncompliant Code Example Compliant Solution
int si;

if (argc > 1) {
  si = atoi(argv[1]);
}
long sl;
int si;
char *end_ptr;

if (argc > 1) {
  errno = 0;

  sl = strtol(argv[1], &end_ptr, 10);

  if ((sl == LONG_MIN || sl == LONG_MAX) && errno != 0) {
    perror("strtol error");
  }
  else if (end_ptr == argv[1]) {
    if (puts("error encountered during conversion") == EOF) {
      /* Handle error */
    }
  }
  else if (sl > INT_MAX) {
    printf("%ld too large!\n", sl);
  }
  else if (sl < INT_MIN) {
    printf("%ld too small!\n", sl);
  }
  else if ('\0' != *end_ptr) {
    if (puts("extra characters on input line\n") == EOF) {
      /* Handle error */
    }
  }
  else {
    si = (int)sl;
  }
}


  • array의 길이 또는 위치를 입력 받는 함수는 항상 입력받은 값이 valid한지 check 해야 한다.

Noncompliant Code Example Compliant Solution
void func(size_t s) {
  int vla[s];
  /* ... */
}
/* ... */
func(size);
/* ... */
enum { MAX_ARRAY = 1024 };

void func(size_t s) {
  if (s < MAX_ARRAY && s != 0) {
    int vla[s];
    /* ... */
  } else {
    /* Handle error */
  }
}

/* ... */
func(size);
/* ... */
Noncompliant Code Example Compliant Solution
enum { WORKSPACE_SIZE = 256 };

void func(const int src[], size_t len) {
  int dest[WORKSPACE_SIZE];
  memcpy(dest, src, len * sizeof(int));
  /* ... */
}
enum { WORKSPACE_SIZE = 256 };

void func(const int src[], size_t len) {
  int dest[WORKSPACE_SIZE];
  if (len > WORKSPACE_SIZE/sizeof(int)) {
      /* Handle error */
  }
  memcpy(dest, src, sizeof(int)*len);
  /* ... */
}


  • strcpy(), strcat(), sprintf(), .. 등 destination buff의 크기를 검사하지 않는 문자열 함수는 사용하지 않는다.

Noncompliant Code Example Compliant Solution
#define FILE_PATH_MAX 100

char config_path[FILE_PATH_MAX];
char *env_home;

env_home = getenv("HOME");
if (env_home == NULL) {
    return -1;
}

sprintf(config_path, "%s/etc/config.ut", env_home);
#define FILE_PATH_MAX 100

char config_path[FILE_PATH_MAX];
char *env_home;

env_home = getenv("HOME");
if (env_home == NULL) {
    return -1;
}

snprintf(config_path, sizeof(config_path), "%s/etc/config.ut", env_home);


  • strncat(), strncpy() 함수들은 dest buff가 부족할경우 null-terminated 되지 않은 불완전한 문자열을 만들수 있으므로 strlcat(), strlcpy() 함수를 사용한다
    • strlcat(), strlcpy() 함수는 Solaris 8 이상에서만 지원되며, 다른 운영체제에서는 MPF에서 지원한다.

Noncompliant Code Example Compliant Solution
#define STR_MAX 5

char str[STR_MAX];

strncat(str, "0123456789", sizeof(str));
#define STR_MAX 5

char str[STR_MAX];

strlcat(str, "0123456789", sizeof(str));


  • isalpha(), islower(), isupper(), .. 등 isxxx() 류의 함수사용시 입력문자 c는 항상 unsigned char 형으로 cast하여 사용한다.
 int isalnum(int c);
 int isalpha(int c);
 int isascii(int c);
 int isblank(int c);
 int iscntrl(int c);
 int isdigit(int c);
 int isgraph(int c);
 int islower(int c);
 int isprint(int c);
 int ispunct(int c);
 int isspace(int c);
 int isupper(int c);
 int isxdigit(int c);

Noncompliant Code Example Compliant Solution
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;

  /* possibly *t < 0 */
  while (isspace(*t) && (t - s < length)) {
    ++t;
  }
  return t - s;
}
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;

  while (isspace((unsigned char)*t) && (t - s < length)) {
    ++t;
  }
  return t - s;
}


  • strtok() 함수는 token을 분리하기 위하여 입력 buff의 손상을 가져오기 때문에 항상 복사본으로 작업한다.

Noncompliant Code Example Compliant Solution
char *token;
char *path = getenv("PATH");

token = strtok(path, ":");
puts(token);

while (token = strtok(0, ":")) {
  puts(token);
}

printf("PATH: %s\n", path);
/* PATH is now just "/usr/bin" */
char *token;
const char *path = getenv("PATH");
/* PATH is something like "/usr/bin:/bin:/usr/sbin:/sbin" */

char *copy = (char *)malloc(strlen(path) + 1);
if (copy == NULL) {
  /* handle error */
}
strcpy(copy, path);
token = strtok(copy, ":");
puts(token);

while (token = strtok(0, ":")) {
  puts(token);
}

free(copy);
copy = NULL;

printf("PATH: %s\n", path);
/* PATH is still "/usr/bin:/bin:/usr/sbin:/sbin" */


  • strlen() 함수는 결과 값에 null-terminating 문자를 포함하지 않기때문에 주의해서 사용해야 한다.

Noncompliant Code Example Compliant Solution
int main(int argc, char *argv[]) {
  /* ... */
  char prog_name[128];
  strcpy(prog_name, argv[0]);
  /* ... */
}
int main(int argc, char *argv[]) {
  /* ... */
  char * prog_name;
  size_t prog_size;

  prog_size = strlen(argv[0])+1;
  prog_name = (char *)malloc(prog_size);

  if (prog_name != NULL) {
    if (strlcpy(prog_name, argv[0]), prog_size) {
      /* Handle strcpy_s() error */
    }
  }
  else {

    /* Couldn't get the memory - recover */
  }
  /* ... */
}

Memory Management

  • 최대한 동적할당된 메모리는 같은 모듈에서 해제시켜준다.

Noncompliant Code Example Compliant Solution
enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(char *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    free(list);
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);
  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}
enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(const char *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);

  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}


  • 자원을 사용한 후의 변수는 즉시 초기화 시킨다. (free(), close(), fclose() ...)

Noncompliant Code Example Compliant Solution
char *message;
int message_type;

/* Initialize message and message_type */

if (message_type == value_1) {
  /* Process message type 1 */
  free(message);
}
/* ...*/
if (message_type == value_2) {
   /* Process message type 2 */
  free(message);
}
char *message;
int message_type;

/* initialize message and message_type */

if (message_type == value_1) {
  /* Process message type 1 */
  free(message);
  message = NULL;
}
/* ...*/
if (message_type == value_2) {
  /* Process message type 2 */
  free(message);
  message = NULL;
}


  • malloc(), calloc(), realloc() 함수 사용시 입력 size가 0이 되지 않도록 보장해야 한다.
    • size가 0 일경우 함수의 행동은 정해져 있지 않으며, 구현에 따라 다르다.

Noncompliant Code Example Compliant Solution
size_t size;

/* initialize size, possibly by user-controlled input */

int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
/* Continue processing list */
}
size_t size;

/* initialize size, possibly by user-controlled input */

if (size == 0) {
  /* Handle error */
}
int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
/* Continue processing list */


  • rewind() 함수는 에러를 리턴하지 않으므로, fseek() 함수를 사용한다.

Noncompliant Code Example Compliant Solution
char *file_name;
FILE *fp;

/* initialize file_name */

fp = fopen(file_name, "r");
if (fp == NULL) {
  /* Handle open error */
}

/* read data */

rewind(fp);

/* continue */
char *file_name;
FILE *fp;

/* initialize file_name */

fp = fopen(file_name, "r");
if (fp == NULL) {
  /* Handle open error */
}

/* read data */

if (fseek(fp, 0L, SEEK_SET) != 0) {
  /* Handle repositioning error */
}

/* continue */


Signal

  • signal 함수를 등록하기 위해 signal() 함수 대신 sigaction() 함수를 사용한다.
    • signal() 함수는 persistant하게 signal handler를 운용하기 위해서는 signal handler안에서 signal을 재등록해야한다.
    • sigaction() 함수는 struct sigaction 구조체 값을 이용하여 다양한 signal 처리가 가능하다.
    • MPF에서는 mpsignal() 함수가 sigaction() 함수를 이용해 구현되었으므로, 이 함수를 사용한다.


  • signal handler안에서는 asynchronous-safe 함수만을 사용한다.

Image:Asynchronous-signal-safe functions.jpg

Error

  • 리턴 값을 가지는 모든 함수는 error 처리를 해야 한다.


Log Format

  • 32bit/64bit 호환성을 위하여 pid_t, pthread_t, thread_t, size_t, ssize_t, socklen_t 형을 로그에 쓸경우 long type으로 변환한다.
    • pid_t, pthread_t, size_t, socklen_t: (unsigned long int)
    • ssize_t: (long int)
    • 예) LOG_SVC("%s:: ccm_forward_thr exit, TID=%lu\n", __func__, (unsigned long int)pthread_self());
Posted by revoman
1. 2차원 배열
a[IMAX][JMAX]
b[IMAX*JMAX]
b[i*JMAX+j] = a[i][j]

2. 3차원 배열
a[IMAX][JMAX][KMAX]
b[IMAX*JMAX*KMAX]
b[i*JMAX*KMAX+j*KMAX+k]=a[i][j][k]
Posted by revoman
TAG C

/usr/proc/bin/pstack

  • SUN , 관련 Unix, Linux
  • Running 중인 Process의 Call Stack을 볼수있음
 %> pstack [pid]

gdb

  • Running Process
 %> gdb $BIN_FULL_PATH <pid>
gdb> info threads
gdb> thread apply all bt (모든 thread의 stack정보를 볼수 있음)
gdb> t 1 (thread 1번으로 스위칭함)
gdb> bt
gdb> quit

dbx

  • Running Process
 %> dbx $BIN_FULL_PATH <pid>
dbx> threas
dbx> thread t@1 (thread 1번으로 스위칭함)
dbx> where
  • Core File
 %> dbx $BIN_FULL_PATH <core_xxx>
dbx> threads
dbx> thread t@1 (thread 1번으로 스위칭함)
dbx> where
  • Zombie Thread
 %> threads -all          (모든 thread 정보를 볼수 있음)

dbx At AIX

  • Running Process
 %> dbx -a <pid> $BIN_FULL_PATH
dbx> thread
dbx> thread current 1
dbx> where
dbx> quit (반드시 수행하여야함. 프로제스가 종료될수있음)

이 글은 스프링노트에서 작성되었습니다.

Posted by revoman
TAG C, unix

유닉스 시그널에 대한 개념과, async-signal-safe 함수들에 대한 소개

 

원문 : 원http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html

 

다음은 시그널 핸들러에서 사용할 수 있는 안전한 함수들이다. 그 이외에 함수들은 안전하지 않다고 가정해야 한다.

 


_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execle()
execve()
fchmod()
fchown()
fcntl()
fdatasync()
fork()


fpathconf()
fstat()
fsync()
ftruncate()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
kill()
link()
listen()
lseek()
lstat()
mkdir()
mkfifo()
open()
pathconf()
pause()
pipe()
poll()
posix_trace_event()
pselect()
raise()


read()
readlink()
recv()
recvfrom()
recvmsg()
rename()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
sleep()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()


sigset()
sigsuspend()
sockatmark()
socket()
socketpair()
stat()
symlink()
sysconf()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
utime()
wait()
waitpid()
write()

 

이 글은 스프링노트에서 작성되었습니다.

Posted by revoman
TAG C, unix

참고 : Advanced Programming in the UNIX® Environment by Richard Stevens, Stephen A. Rago

 

* safe recv

  1. static ssize_t readn(int fd, void *vptr, int n)
    {
        size_t     nleft   = 0;
        ssize_t    nread   = 0;
        char     *  ptr    = NULL;

        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nread = recv(fd, ptr, nleft, 0)) < 0) {
                tclog("nread=%d\n", nread);
                if (errno == EINTR)
                    nread = 0;      /* and call read() again */
                else
                    return (-1);
            } else if (nread == 0)
                break;              /* EOF */

            nleft -= nread;
            ptr += nread;
        }
        return (n - nleft);         /* return >= 0 */
    }

 

* safe send

  1. static ssize_t writen(int fd, const void *vptr, int n)
    {
        size_t     nleft       = 0;
        ssize_t     nwritten    = 0;
        const char *ptr     = NULL;

        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwritten = send(fd, ptr, nleft, 0)) <= 0) {
                if (nwritten < 0 && errno == EINTR)
                    nwritten = 0;   /* and call write() again */
                else
                    return (-1);    /* error */
            }

            nleft -= nwritten;
            ptr += nwritten;
        }
        return (n);
    }

 

* timeout check which select

  1. static int rfd_check_timeout(int fd, int sec)
    {
        fd_set  rset;
        struct  timeval tv;
        int     ret;

        FD_ZERO(&rset);
        FD_SET(fd, &rset);

        tv.tv_sec = sec;
        tv.tv_usec = 0;

        ret = select(fd + 1, &rset, NULL, NULL, &tv);
        /* > 0 if descriptor is readable */

        if(ret>0)
            return 0;
        else {
            if(ret==0)
                tmlog("time out(%d) !! \n", sec);
            else
                tmlog("select() fail\n");
            return -1;
        }
    }

이 글은 스프링노트에서 작성되었습니다.

Posted by revoman
TAG C, unix

최근에 달린 댓글

최근에 받은 트랙백

글 보관함