1580, 74/79 회원가입  로그인  
   부러진분필
   http://minihp.cyworld.com/pims/main/pims_main.asp?tid=60039153
   리눅스 강좌 리눅스/유닉스 네트워크 프로그래밍

http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=1703 [복사]


바야흐로 인터넷/통신을 모르면 컴맹이라는 소릴 듣는 시대가 왔다. 컴퓨터의 주요 기능 또한 네트웍으로 되어 가고 있다. 네트웍이 강점인 유닉스/리눅스가 기승을 부릴 때이다. 유닉스의 꽃이라 할 수 있는 네트웍 프로그래밍을 공부함으로써 진정한 유닉스 프로그래머가 되어 보자.



Connection-oriented socket 이란?

유닉스의 모든 것은 파일이라는 말이 있다. 이 말은  유닉스 프로그래밍을 해 보면 모든 I/O작업이 파일에 쓰고 읽음으로써 이루어 진다는 말이다. 네트웍의 작동 또한 마찬가지이다. 양쪽의 컴퓨터가 각각 파일, 즉 socket 을 열어서 그 파일을 연결시켜 통신이 이루어지는 것이다.
주로 쓰이는 socket의 타입은 2종류이다. 하나는 stream socket 이고 다른 하나는 datagram socket 이다.


Stream socket은 안정적인 양방향의 연결을 만들 때 필요한 소켓이다. 이 연결은 양방향으로 통신이 가능하며, 데이터들의 순서가 정확하다. 또한 이 연결은 tcp 프로토콜을 사용하므로 에러 체킹이 되어 안정적인 데이터 전송이 가능하다. telnet 이나 http.ftp 등과 같이 상호 작용이 필요하고 안정적인 연결이 요구될 때 바로 이 소켓을 사용한다. 이 소켓을 다른 말로 connection-oriented socket 이라고도 한다.


출저 http://www.lug.or.kr/docs/LINUX/others/1997-1.htm
반면 datagram socket은 단방향 일회성이라 할 수 있다. 하나의 packet(데이터 덩어리)에 주소를 집어넣어 보내면 그 패킷이 혼자서 목적지로 찾아가는 방식이다. 이렇기 때문에 연결을 시켜놓을 필요가 없어 일회성이며, 이 패팃이 전송 도중 분실될 수도 있다. tftp나 bootp같은 프로그램이 이러한 소켓을 사용한다.


이 강좌에서 우리는 몇 가지 예제를 통하여 connection-oriented socket에 대해 심도있게 공부를 하게 될 것이다.



소켓 관련 시스템 호출

connection-oriented socket을 만들어 연결을 하기 위해서는 다음과 같은 과정이 필요하다.

Server: socket() -> bind() ->listen() -> accept()
Client: socket() -> connect()


이 시스템 호출들은 대부분 sockaddr 구조체를 인수로 필요로 한다. sockaddr 구조체는 다음과 같다.

#include <sys/socket.h>
struct sockaddr
{
    unsigned short sa_family;   /* addressmfamily, AF_xxx     */
    char             sa_data[14]; /*14bytes of protocol address */
};

여러 종류의 소켓이 같은 시스템 콜을 이용하기 때문에 sockaddr 구조체에서 소켓 종류에 의존적인 부분은 sa_data[]와 같이 배열로 남겨 두었다. Sa_family는 프로토콜의 종류를 결정하는 것으로, 우리가 사용할 것은 AF_inet(Internetfamily) 이다. family의 종류로는 af_INET 외에 AF_UNIX, AF_NS등이 있다.  
AF_INET family를 위해 다음과 같은 구조체가 sockaddr구조체를 지정하기 위해 정의되어 있다.

#include <netinet/in.h>
struct sockaddr_in
{
     short int               sin_family;       /Address family          */
     unsigned short int sin_port;          /* Port number          */
     struct in_addr       sin_addr;         /*internet address      */
     unsigned char      sin \_zero[8]; /*Same size as struct sockaddr*/
};
struct in_addr
{
     unsigned long s_addr;
}


sin_family는 AF_INET로 지정될 것이며, sin_port는 포트번호, sin_addr은 인터넷 주소를 지정한다. Sin_zero[]는 sockaddr과 크기를 맞추기 위한 배열이기 때문에 sockaddr_in을 사용하기 전에 bzero()나 memset()을 이용해서 0으로 초기화한다.

Byte Ordering Routine


컴퓨터 마다 byte들을 변수에 저장하는 순서가 다르다. 그래서 다른 컴퓨터끼리 통신이 이루어 지려면 이러한 순서를 맞춰 주어야 한다. 네트웍 상에서의 데이터의 byte order를 Network byte order라고 하며, 컴퓨터 내부에서 사용되는 byte order를 host byte order라고 한다. 그러므로 sin_addr에 들어갈 숫자는 network byte order 이다. 우리가 sin_port와 sin_addr에 값을 지정하려면 컴퓨터의 host byte order인 변수 값을 network byte order 로 바꾸어서 저장해야 한다. 이러한 순서 변환 함수는 4가지가 있다.

htons()-"Host to Network Short"
htonl()-"Host to Network Long"
ntohs()-"Network to Host Short"
ntohl()-"Network to Host Long"

이름 그대로 htons() 는 short 형의 변수를 host byte order에서 network byteorder로 바꿔준다. 나머지도 마찬가지이다.
Sa라는 sockaddr_in 구조체에서 sin_port에 4000 이라는 번호를 지정하려면 sa.sin_port = htons(4000); 이렇게 하면 된다. sin_port는 short형 이므로 htons()를 사용하였다.

Address Conversion Routine

IP 어드레스의 지정을 위해서는 sin_addr.s_addr에 주소를 지정해야 한다. sa라는 sockaddr-in 구조체가 있다고 하자. 여기에 "127.0.0.1"라는 주소를 지정하고 싶을 때에는 다음과 같이 한다.

sa.sin_addr.s_addr =inet_addr("127.0.0.1") ;

inet_addr()함수는 숫자와 점으로 이루어진 주소 값을 unsigned long의 형태로 바꾸어 준다. 이 함수는 미리 Network byte order로 반환을 하므로 htonl()과 같ㅇ느 함수를 사용할 필요가 없다.
이와 반대의 역할을 하는 함수는 inet_ntoa()이다. 이 함수는 unsigned long의 주소값을 도트로 이루어진 주소값으로 바꾸어 준다.

printf("%s",inet_ntoa(sa.sin_addr));

과 같이 하면 127.0.0.1이 찍힐 것이다.
아직은 home.monac.org과 같이 문자로 이루어진 주소값은 다루지를 못한다. 이것에 대해서는 나중에 살펴보기로 하겠다.

socket()
#include <sys/types.h>
#include <sys/socket.h>

int socket(int family, int type, int protocol);

family는 소켓 가족을 지정하는 부분이다. 우리는 AF_INET만을 사용한다.
type은 stream socket이라는 것을 말하는 SOCK_STREAM으로 지정을 한다.
ptocol은 0을 지정한다.
이 시스템 호출은 파일 지정번호(file descriptor)를 반환한다.
우리는 이 함수 호출을 다음처럼만 쓰게 될 것이다.


sckfd =socket(AF_INET,SOCK_STREAM,0);

bind()
#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, int addrlen);

myaddr은 자기 자신의 주소이다.
Addrlen은 myaddr의 크기를 말한다. Sizeof(myaddr)과 같이 쓰면 될 것이다. 이 시스템 호출은 소켓에 자신의 주소를 지정한다. 서버는 클라이언트로부터 연결 요구를 받기 전에 자신의 주소를 지정해 줌으로써 이 주소로 오는 신호는 모두 이 소켓으로 들어오라고 말해 주는 것이다.

lsten()

int listen(int sockfd, int baklog);

backlog는 accept() 한수 실행 시에 얼마나 많은 연결이 누적될 수 있는가를 말한다. 동시에 2개의 연결 요구가 발생할 때 accept()에서 하나의 연결을 받아들이는 도중에는 다른 하나는 누적(pending)될 것이다. 이러한 누적되는 연결의 개수를 의미한다. 보통 최대값이 5개이다.

Accept()
#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr * peer,int *addrlen);
peer는 연결이 성립되었을 때 연결된 상대방의 주소를 저장할 공간이다. 이 시스템 호출은 실제적인 연결을 기다리는 함수이다. 연결 요청이 있을 경우 accept()는  새로운 소켓을 생성하고 연결하여, 이 파일 지정번호를 반환한다. 연결 요청이 없으면 non-blocking 소켓이 아닌한 연결을 기다린다. Non-blocking소켓에 대해서는 다음에 살펴보기로 한다.

connect()
#include <sys/types.h>
#include < sys/socket.h>

int connect(int sockfd, struct sockaddr *servaddr, int addrlen);

servaddr은 연결을 할 상대방의 주소이다.
이 시스템 호출은 자신의 시스템과 서버의 실제적인 연결을 시도한다.
클라이언트 프로그램은 socket() 시스템 호출 후 이 시스템 호출로 서버에 연결을 시도 할 것이다.

socket을 통한 read/write

소켓은 하나의 파일이므로 모든 파일 I/O 함수들을 사용할 수 있다. 여기서 우리는 read(), write() 시스템 호출을 이용하게 될 것이다.
소켓을 통하여 read()/write()를 시도하였을 경우 리턴값(실제로 읽혀진 또는 쓰여진 byte 수)이 우리가 지정한 byte수 보다 작을 수도 있다. 이럴 경우에는 다 쓰여질 때 까지 반복해서 시도해야 할 것이다.
소켓 연결이 끊겨질 경우는 다음과 같이 알 수 있다.

1. 상대방이 닫혀진 소켓에 read()를 실행하면 0을 리턴한다.
2. 상대방이 닫혀진 소켓이 write()를 실행하면 SIGPIPE시그널이 발생한다.


이 시그널이 무시되거나 이 시그널을 위한 시그널 핸들러가 설치되었을 경우에는 에러가 발생하고(-1을 리턴), errno가 EPIPE로 세팅된다.
socket을 위한 입출력 버퍼의 크기는 PIPE_BUF상수값이다. 효율적인 입출력을 위해서 PIPE_BUF 크기만큼을 쓰거나 읽는 것도 좋을 것이다. 이 버퍼 크기는 여러 가지 방법으로 바꿀 수 있다.

echo 서버 프로그램

이 서버 프로그램은 포트 4000번으로부터 연결을 받아들여서, 데이터를 읽고 그것을 도로 반송하는 작업을 반복한다.

/*echo server*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

#define ECHO_PORT4000

int newsock:
void quit(int)
void main()
{
     int sock, clilen;
     struct sockaddr_in cli_addr,serv_addr;
     char buf[100];
     int n;
     /* internet 가족의 stream socket을 할당받는다. */
     if((sock = socket(AF_INET,SOCK_STREAM,0)) <0)
     {
         perror("socket");
         exit(1);
     }
     /*인터럽트(CNTL-C)시에 종료작업을 할 수 있게 핸들러를 설치한다.*/
     signal(SIGINT,quit);
     /*sockaddr_in 구조체를 사용하기 전엔 0으로 초기화 해주어야 한다. */
     bzero((char*) &serv_addr,sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     /* INADDR_ANY: 0의 값 -> 자신의 주소를 컴퓨터가 찾아준다. */
     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     serv_addr.sin_port = htons(ECHO_PORT);
     /*bind local address */
     if(bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) <
     0)
     {
          perror("bind");
          close(sock);
          exit(1);
     }
     listen(sock, 0);
     clilen = sizeof(cli_addr);
     printf("accepting...\n");
     /* 여기서 연결요청이 올 때까지 block 된다. */
     newsock = accept(sock, (struct sockaddr*) & cli_addr, &clilen);
     close(sock);
     if(newsock<0)
     {
          perror("accept");
          exit(1);
     }
     printf("Connected from %s.\n", inet_ntoa(cli_addr.sin_addr));
     while((n = read(newsock, buf, 100)) ! = 0)
     {
          if(n < 0)
         {
                perror("read");
                close(newsock);
                exit(1);
          }
          write(newsock, buf, n);
          write(1, buf, n);
     }
     close(newsock);
     printf("Connection closed by the peer.\n");
}
void quit(int signum)
{
     close(newsock);
     printf("interrupted\n");
     exit(1);
}

프로그램의 흐름은 소켓을 만들고, sock=socket(AF_INET, SOCK_STREAM, 0);
자신의 주소를 소켓에 할당,
bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
연결을 받아들이겠다는 의지로 listen()을 호출하고,
backlog를 0으로 지정, listen(sock, 0);
실제 연결을 받아들인다.
Newsock=accept(sock, (struct sockaddr*) &cli_addr, &clilen);
끝낼 때 close()로 소켓을 닫는다.
Serv_addr.sin_addr.s_addr에는 자기 자신의 주소가 들어 가야 된다. 그러나 이것을 INADDR_ANY로 지정하면, 자신의 주소를 자동으로 찾아준다.
ECHO_PORT를 4000으로 지정하여 우리는 4000번의 포트로 접속을 받는다는 것을 명시하였다. 포트번호 1-1023까지는 예약된 포트이다. 즉 1-1023까지의 포트는 시스템이 사용하는 포트이기 때문에 사용자 임의의 포트로 사용할 수 가 없다. 그래서 우리가 사용 할 프로그램은 1024-65535까지의 포트를 사용할 수 있다.
Listen() 시스템 호출에서 backlog값으로 0을 지정하였다. 이 프로그램은 연결을 하나만 받아들이므로 backlog의 값은 현재 무의미하다.
이 프로그램은 연결된 클라이언트로부터 데이터를 읽어서 그 데이터를 되돌려 보내주며 동시에 standard output(파일지정번호 1)으로 출력한다. Read()시에 리턴값이 0이면 클라이언트가 접속을 끊었다는 것을 뜻한다.
Socket()으로 소켓을 생성한 뒤에는 프로그램을 끝내기 전에 close()를 한 뒤에는 소켓을 다시 사용할 수는 없지만 그렇다고 소켓이 곧바로 없어지는 것은 아니다. 소켓은 커널 내부에서 잠시동안 살아 있으면서 상대편과의 통신으로 소켓을 완전히 닫는다. 서버 소켓은 이 과정에서 다소 시간이 걸릴 수 있다. 그래서 서버를 직접 종료 시킨 뒤에 곧바로 다시 실행시키면 "address already in use"와 같이 전에 쓰이던 소켓이 완전히 닫혀지지 않아 에러가 날 수 있다. (보통 몇 분 이상은 안 걸린다.).

이제 이 프로그램을 테스트 해보자.
이 프로그램은 현제 포트번호 4000으로 접속을 받고 있다. 우리는 telnet같은 프로그램으로 포트 4000에 접속을 할 수 있다.
한 콘솔에서 이 프로그램을 실행시킨 뒤에 다른 콘솔에서 telnet localhost 4000과 같이 접속을 시도해라.

주소변환하기

www.linux-kr.org과 같이 문자로 이루어진 주소는 127.0.0.1과 같이 숫자로 이루어진 주소로 변환되어서 처리되어야 한다. 이러한 작업은 DNS(Domain Name Service)에 의해 시스템에서 이루어진다. 프로그램에서 이를 이용하기 위해서는 gethostbyname() 이라는 함수를 사용한다.

#include <netdb.h>
struct hostent *gethostbyname(const char *name);
struct hostent
{
     char  *h_name;
     char  **h_aliases;
     int  h_addrtype;
     int  h_length;
     char  **h_addr_list;
};
#define h_addr h_addr_list[0]

gethostbyname()은 문자로 이루어진 주소를 인수로 받아서 hostent 구조체를 리턴한다. 이 구조체의 이용 예를 통해 사용법을 살펴보자.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
     struct hostent *h;
     if (argc ! =2)
     {
          fprintf(stderr,"usage: %s address\n" ,argv[0]);
          exit(!);
     }
     if ((h=gethostbyname(argv[1])) == NULL
     {
          herror("gethostbyname");
          exit(1);
     }
     printf("Host name : %s\n" , h->h_name);
     printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));

     return 0;
}

여기서 볼 수 있듯이 h_name은 문자로 이루어진 호스트의 이름을, h_addr은 in_addr현 구조체에 들어갈 Network byte order인 숫자를 저장한다. h_addr은 실제적으론 h_Addr_list[0]의 매크로이다.
h_addr을 sa라는 sockaddr_in구조체에 적용시키려면, bcopy(h->h_addr,(char*)&sa.sin_addr, host->h_length);과 같이 하면 된다.

여기서 genthostbyname()에 에러가 발생하여 NULL을 반환할 때 perror()가 아닌 herror()함수를 사용하였다. 이는 gethostbyname()은 에러 시에 errno가 아닌 h_errno에 에러를 세팅하므로, perror() 대신 herror()함수를 사용하여 에러 내용을 확인한다.

<주소변환 알고리즘>



--------------------------------------------------------------------------------
| struct sockaddr_in [ struct in_addr sin_addr] |

--------------------------------------------------------------------------------
        ^^^                                          ^^^
       |                                              |  
       | gethostbyname() ->h_addr       | inet_addr()
       |                                              |
www.linux-kr.org----------------> 127.0.0.1
                              inet_ntoa()

echo 클라이언트 프로그램

클라이언트 프로그램은 소켓 연결 후 fork()를 실행시킨다. fork()가 실행되면 자식과 부모는 하나의 소켓을 동시에 열어 놓을 수 있으므로, 하나의 소켓에 읽기와 쓰기를 동시에 수행할 수 있다. 자식 프로세서는 서버로부터 데이터를 읽어서 출력하는 작업을 반복한다. 부모 프로세서는 터미널을 cbreak 모드로 전환한 뒤 입력된 문자를 곧바로 서버에 전송하는 작업을 반복한다. cbreak모드에서는 자신이 친 문자를 화면에 표시하지 않고, 한번에 한 문자씩 읽어 들인다(echo off, noncanonical input).
이 프로그램에서 인터넷 주소를 변환하는 과정에 유의하여라.

/* echo client*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <termios.h>

#define ECHO_PORT 4000

int tty_cbreak(int fd, int set);
void main(int argc, char *argv[])
{
     int sock,child_paid;
     struct hostent *host;
     struct sochaddr_in serv_addr;
     int port;
     char addr[50];
     char hostname[50];
     char buf[100];
     if(argc ! = 2)
     {
          fprintf(stderr,"usage: %s<address>\n",argv[0]);
          exit(1);
     }
     strcpy(addr,argv[1]);
     port = ECHO_PORT;
     bzero((char*)&serv_addr,sizeof(serv_addr));
     serv_addr.sin_family=AF_INET;
     serv_addr.sin_port = htons(port);
     /*숫자와 점으로 이루어진 주소인지 체크한다.*/
     if ((serv_addr.sin_addr.s_addr=inet_addr(addr))!=INADDR_NON
     E)
     {
          strcpy(hostname,addr);
     }
     else
     {/*문자로 이루어진 주소값 이므로, 데이터베이스에서 주소를 찾는다.*/
          if ((host=gethostbyanme(addr))==NULL)
          {
               herror("host name error");
               exit(1);
          }
     bcopy(host->h_addr,(char *)&serv_addr.sin_addr,
     host->h_length);
     strcpy(hostname, host->h_name);
}
/*소켓 생성*/
if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
{
     perror("socket");
     exit(1);
}
printf("Trying %s...\n",inet_ntoa(serv_addr.sin_addr));
/*서버로 연결을 시도한다. */
if(connet(scok,(struct sockaddr*) &serv_addr, sizeof(serv_addr))
<0)
{
     close(sock);
     perror("connect");
     exit(1);
}
printf("Connected to %s.\, honstname);
if((child_pid = fork()) ==0)
{/*this is the child process*
     int n;
     while((n = read(sock, buf, 100)) !=0)
          write(1,buf,n);
     if(kill(getppid(), SIGKILL)<0)
          perror("kill");
}
else
{
     /*this is the parent process*/
     int n;
     /* cbreak-mode로 만든다.*/
     tty_cbreak(fileno(stdin),1);
     while((n = read(fileno(stdin),buf,1)) == 1
     {
          if((n = write(sock, buf, 1)) <0)
               break;
     }
     if(n<0)
          fprintf(stderr, "error!\n");
     /*terminal mode 복귀시킨다.*/
     tty_cbreak(fileno(stdin),0);
     kill(child_pid, SIGKILL);
}
close(sock);
     printf("Connection closed.\n");
}
/*cbreak mode*/
int tty_cbreak(int fd, int set)
{
     static struct termios save_termios;
     struct termios buf;
     /*set이 1이면 cbreak mode로 전환, 0이면 이전의 모드로 되돌림*/
     if(!set)
     {
          if(tcsetattr(fd, TCSAFLUSH, &save_termios)<0)
               return -1;
          return 0;
     }
     if(tcgetattr(fd, &save_termios)<0)
          return -1;
     buf = save_termios;
     buf.c_lflag &=~(ECHO | ICANON);
     buf.c_cc[VMIN] = 1;
     buf.c_cc[VTIME] = 0;
     if(tcsetattr(fd, TCSAFLUSH, &buf)<0)
          return -1;
     return 0;
}

주소를 변환하는 과정을 살펴보자.


If((serv_addr.sin_addr.s_addr=inet_addr(addr))!=INADDR_NONE)
{
     strcpy(hostname,addr);
}


만약 addr이 "127.0.0.1"과 같이 숫자로 이루어진 주소값이라면 inet_addr()함수는 정상적으로 작동한다. 그렇지 않을 경우는 INADDR_NONE(-1)라는 값이 리턴된다. 에러나 났으면 문자로 이루어진 주소인지를 체크한다.

else
{
     if((host=gethostbyname(addr))==NULL)
     {
          herror("host name error");
          exit(1);
     }
     bcopy(host->h_addr,(char *) &serv_addr.sin_addr,host-
     >h_length);
     strcpy(hostname, host->h_name);
}

gethostbyname()함수가 성공을 하면 우리는 host->h_addr을 serv_addr.sin_addr에 복사하여 serv_addr 구조체를 완성시킬 수 있다. Hostname은 문자로 이루어진 주소의 완전한 값을 가진다.(매크로 같은 이름이 아닌...)
자식과 부모 프로세서 두개를 동시에 끝내기 위해 서로에게 KILL시그널을 보낸다. 어느것이 언제 어떻게 종료 될지 알 수가 없기 때문이다.
프로그램을 실행시켜 보자.
echo서버 프로그램을 먼저 한쪽 콘솔에서 실행을 하고 이 프로그램으로 다른 콘솔에서 연결시켜 보자. 연결이 정상적으로 되었다면, 클라이언트에서 문자를 치는 순간마다 문자가 전송되고 되돌려 보내질 것이다. 클라이언트의 화면에 나타나는 문자는 클라이언트에서 직접 찍는 것이 아니라 서버에서 되돌려 보내진 문자이다.
이상으로 소켓관련 시스템 호출을 살펴보면서, 간단하게 이해가 되었길 바란다. 다음편에서는 간단한 telnet client 프로그램을 만들면서 실제적인 어플리케이션 작성을 해본다.

전영준
한국항공대학교 컴퓨터공학과 96학번
하이텔: MonaC
email: monac@ee.korea.ac.kr



<네트웍 프로그래밍의 시작을 위한 안내>


네트웍 프로그래밍은 기본적인 유닉스 프로그래밍 주제가 아니다. 유닉스 시스템 프로그래밍에 대한 기본적인 지식이 없이는 네트웍 프로그래밍을 제대로 배워나가기가 어려울 것 이다. 수많은 파일 콘트롤 기법들을 다루게 될 것이고, 유닉스 시스템의 내부적인 동작을 기본지식으로 필요로 할 것이다. 아직 유닉스 시스템 프로그래밍에 익숙치 않은 분은 유닉스 시스템 프로그래밍 관련 전문 서적을 일독하기를 권한다.


Stevens씨가 지은 Unix Network Programming이란 책은 유닉스 네트웍 프로그래밍의 바이블이라 할 만한 책이다. Stevens씨는 이 책 외에도 Advanced Programming in the UNIX Environment라는 유명한 책도 지었다. 그의 이 네트웍 서적은 네트웍 프로그래밍에 관련된 거의 모든 것이 망라되어 있어 필수적이라 할 만한 책이지만 초보자가 혼자서 읽기에는 다소 힘든 점이 많다.  


잠시 이 책에 관한 안내를 하겠다.


이 책의 앞부분에는 유닉스 시스템과 네트웍의 기본 지식으로 250페이지에 걸쳐 많은 설명을 해 놓았다. 그러나 이 설명은 "유닉스 시스템에 익숙치 않은 사람에겐 다른 좋은 책을 읽는 것이 더 낫고, 유닉스 시스템에 익숙한 프로그래머는 이 부분이 필요가 없기" 때문에 저자가 책의 완결성을 높이기 위해서 넣은 부분이라고 생각하면 될 것이다. 다만 4장과 5장부분의 네트웍 배경지식에 대해서는 간단히 훑어 보는 것도 좋을 것이다.


네트웍 프로그래밍의 핵심은 6장과 8장에 모두 다 있다. 6장과 8장에 있는 부분만 모두 이해를 하고 있다면 일반적인 소켓 프로그래밍시 전혀 어려운 점이 없을 것이다. 유닉스 시스템과 네트웍에 관해 깊은 지식을 얻고자 하시는 분은 14장 또는 15장에 있는 부분을 공부하면 상당한 도움이 되리라 생각된다.


(이 책의 한글판을 읽으면 용어에 대한 심각한 혼동이 생길 것이다. 영어에 부담이 없으신 분은 영어로 된 원서를 구입하길 추천한다.)


유닉스 소켓 프로그래밍에 관련 의문사항이 생기면 우선 socket FAQ를 살펴보기 바란다. 소켓 프로그래밍을 처음 공부하시는 분이 가질 수 있는 모든 질문과 답이 여기에 적혀있다. 다음의 site에서 구할 수 있다.



  Hit : 8702     Date : 2011/03/25 10:34



    
120   왠만한사람들은다알지도모르겠지만[6]     백룡출해
03/17 12109
119   c언어[1]     백민준천재
08/31 4556
118   c언어[1]     백민준천재
08/31 4586
117   2[1]     백민준천재
08/31 4524
116   1[1]     백민준천재
08/31 4496
115   유닉스 v1 편집없음...편집해서보세요~~[1]     미미123
06/01 7217
114   유닉스 v2 편집없음~[1]     미미123
06/01 7694
113   편집없음 v3 유닉스특징[1]     미미123
06/01 8533
112   편집없음 v4 유닉스 명령어     미미123
06/01 7820
111   편집없음 v5 유닉스명령어 file system[4]     미미123
06/01 7749
110   이제막처음시작한 초보입니다[3]     미스터리
02/02 7768
109   ㅋ 컴터 빠르게 하는방법?[1]     무소유
12/17 8844
108   도대체가.. 이해가 안가는군요..[10]     봉춘삼
05/04 7098
107   리눅스 강좌 (리눅스란무엇인가)     부러진분필
03/25 7855
106   리눅스 강좌 (레드햇 리눅스)[1]     부러진분필
03/25 10739
105   리눅스강좌 sparc 리눅스 설치     부러진분필
03/25 8052
  리눅스 강좌 리눅스/유닉스 네트워크 프로그래밍     부러진분필
03/25 8701
103   리눅스 강좌 디스크관리를 위한 Quota 사용하기     부러진분필
03/25 7459
102   초간단 리눅스 명령어, 기본적으로 꼭꼭 알아야 할 것[14]     빈대
01/04 9948
101   커널 업그레이드 방법[2]     빈대
01/04 8274
[1]..[71][72][73] 74 [75][76][77][78][79]

Copyright 1999-2023 Zeroboard / skin by Hackerschool.org / Secure Patch by Hackerschool.org & Wowhacker.com