스트림 소켓에서 부분 읽기와 부분 쓰기
부분 읽기
부분 읽기는 read() 호출에서 요청한 바이트 수가 실제 소켓에서 이용 할 수 있는 바이트 수 보다 많은 상황에서 발생.
이러한 상황에서 read는 단순하게 가용 바이트 수를 리턴 한다.
부분 쓰기
요청한 바이트를 모두 전송 할 만큼 충분한 버퍼 공간이 없는 가운데 다음의 하나를 충족 하는 경우에 부분 쓰기 발생
- write() 호출이 이미 몇바이트 전송 한 뒤 시그널 핸들러가 인터럽트 발생
- 소켓이 비블로킹모드 로 동작하는 상황에서 요청한 바이트 중 일부만 전송 할 수 있는 경우
- 요청한 바이트 중 일부를 전송한 상황에서 비동기 에러 발생
for ( int totalRead = 0; totalRead < n; ) { numRead = read( fd, buf, n - totalRead ); if ( 0 == totalRead ) // EOF return totalRead; // 처음 읽기를 시도하는 경우 0 일수 있다. if ( -1 == totalRead ) { if ( errno == EINTR ) continue; // 인터럽트 발생 read()를 재시작 else return -1; } totalRead += numRead; buf += numRead; } return totalRead; // 이때 totalRead값은 반드시 n바이트여야 한다. const char* buf = buffer; int totalWriten; for ( totalWriten = 0; totalWriten < n; ) { totalWriten = write( fd, buf, n - totalWriten ); if ( totalWriten <= 0 ) { if ( totalWriten == -1 && errno == EINTR ) continue; else return -1; } totalWriten += numWritten; buf += numWritten; } return totalWriten; // 이 행을 실행 할 경우 totalWriten 는 n과 같아야함..
shutdown() 시스템 호출
소켓에 close()를 호출하면 양방향 통신 채널 전체를 닫는다.
shutdown() 은 통신 채널을 반만 닫는다.
옵션
SHUT_RD : 읽기 채널 닫는다.
SHUT_WR : 쓰기 채널을 닫는다.
SHUT_RDWR : 읽기와 쓰기 모두 닫는다.
소켓 전용 I/O 시스템 호출 : recv() 와 send()
#include "SYS/socket.h" // 수신된 바이트 수를 리턴한다. EOF인 경우에는 0을, 에러가 발생하면 -1을 리턴한다. ssize_t recv( int sockfd, void* buffer, size_t length, int flags ); // 전송한 바이트 수를 리턴한다. 에러가 발생하면 -1을 리턴한다. ssize_t send( int sockfd, const void* buffer, size_t length, int flags );
send, recv에서 리턴값과 첫 3개 인자는 read, write와 같다.
마지막 인자인 flags 는 I/O 오퍼레이션을 조절 할 때 쓰는 비트마스크다.
recv
MSG_DONWAIT : 비블로킹 recv 호출을 수행. 이용 할 수 있는 데이터가 없는 경우 바로 EAGAIN 에러를 발생 시키며 즉시 리턴.
MSG_OOB : 소켓의 대역폭을 벗어난 데이터를 받는다.
MSG_PEEK : 소켓 버퍼에서 요청한 바이트의 복사본을 가져온다. (가져온 데이터를 버퍼에서 삭제하진 않음.. )
MSG_WAITALL : 요청한 바이트 수만큼 받을 때까지 시스템 호출을 블록 한다.
그러나 시그널을 감지하거나, 상대편 스트림 소켓이 종료되거나, 대역폭을 벗어난 데이터 바이트가 발생하거나, 데이터그램 소켓으로 받은 메시지가 length바이트보다 작은 경우, 소켓 에러가 발생한 경우에는 요청한 바이트 수보다 적은 수를 리턴한다.
send
MSG_DONTWAIT : 비블로킹 send를 수행. 데이터를 바로 전송 할 수 없는 상황에는 블록하지 않고 EAGAIN에러를 발생 시킨다.
MSG_MORE : TCP 소켓 옵션 TCP_CORK와 동일한 효과를 나타낸다. UDP에 이 플래그를 사용 할 경우에는 데이터를 모아뒀다가 MSG_MORE 지정하지 않은 전송 시도가 있을때 한꺼번에 전송 한다.
MSG_NOSIGNAL : 연결된 스트림 소켓에 데이터를 전송 할 때 상대편 연결이 닫힌 경우에도 SIGPIPE 시그널을 발생 시키지 않는다. 대신 EPIPE 에러가 발생하면서 send 호출이 실패한다.
MSG_OOB : 스트림 소켓에 대역폭을 벗어난 데이터를 전송 한다.