유닉스네트워크프로그래밍 Unix Network Programming, 2nd Ed., W. Richard Stevens, Prentice Hall PTR, 1999. 한국어판 Unix Network Programming, 2nd Ed., W. Richard Stevens 저, 김치하, 이재용편역, 교보문고, 1999. 컴퓨터네트워크프로그래밍, 개정판, 김화종, 홍릉과학출판사, 2000. 예제로쉽게작성하는 LINUX 네트워크베스트프로그래밍, 雪田修一저, 권용진역, 도서출판인터비젼, 2000.
파이프 프로세스간상호통신메카니즘 단방향통신을제공 일반적으로, 유틸리티표준출력을다른유틸리티의표준입력과 연결하기위해셸내에서사용 파이프종류 명명되지않은파이프 (unnamed pipe) 명명된파이프 (named pipe) 시스템프로그래밍 2
파이프 명명되지않은파이프 : pipe( ) 4K(BSD) 혹은 40K( 시스템 V) 정도의크기 단방향통신링크 (unidirectional communication link) read(), write(), close() 를사용하여파이프의읽기, 쓰기, 종료가수행 양방향통신을위해서는 2 개의파이프를사용 동작 System call: int pipe pp ( int fd [])» 명명되지않은파이프생성후, 2개의파일기술자반환» fd [0] - 파이프의 읽기 끝과연관된기술자저장» fd [1] - 파이프의 쓰기 끝과연관된기술자저장» 커널이새로운파이프에충분한공간을할당할수없으면 -1 반환하고, 그렇지않으면 0반환» 소스프로그램 : P514 시스템프로그래밍 3
파이프» 파이프를생성한프로세스와그의자손프로세스만이그파이프를사용 파이프를호출 프로세스 A 파이프를이용할수없음 프로세스 B 프로세스 C 프로세스 D 프로세스 E 파이프를공용 시스템프로그래밍 4
파이프 명명된파이프 or FIFO(First In First Out) 대략 40K의큰버퍼용량을가짐 명명되지않은파이프보다는덜제한적 네트워크를통과해동작하지않음 이점» 파일시스템에존재하는 UNIX 파일이름을가짐» 관련없는프로세스들에의해서사용될수있음 ( 소유자, 크기, 접근허가등이지정 )» 명시적으로삭제될때까지존재 소스프로그램 : P585» 명명된파이프생성» 유닉스유틸리티 mknod를사용» 시스템호출 mknod( ) 를사용 (1) mknod사용하여파이프생성 $ mknod mypipe p. 파이프생성 mypipe : FIFO 의이름 p : mknod 가 FIFO 를생성하도록지정 시스템프로그래밍 $ chmod ug+rw mypipe. 허가권갱신 5
파이프 (2) mknod() 사용하여파이프생성» 프로그램상에서 FIFO 생성시사용» 생성한 FIFO 는 UNIX 의 rm 명령이나 unlink() 시스템호출로제거» 처리가정상종료 : 0 반환» 비정상종료시 : -1 반환 int mknod(const char *path, mode_t mode, dev_t dev);» path로지정된경로명으로새로운파일을생성» 새로운파일의화일형및허가는 mode에지정» mode가블록형특수장치또는문자형특수파일을표시하면 dev에는그시스템구성에의존 시스템프로그래밍 6
소켓 프로세스간상호양방향통신방식 네트워크를통한통신가능 소켓을통한프로세스통신은클라이언트- 서버모델 (client-server model) 에기초 활용 한기계에존재하는파일을다른기계에서프린트 한기계에서다른기계로파일을전송 유닉스네트워크프로그래밍 7
OSI 7 Layers & Internet t protocol suite Layer 7 Application Layer 6 Presentation Application Layer 5 Layer 4 Session Transport TCP UDP sockets XTI Layer 3 Network IPv4, IPv6 Layer 2 Data Link Device Driver and Layer 1 Physical Hardware OSI 7 Layers Model * OSI : Open System Interconnection Internet protocol suite 유닉스네트워크프로그래밍 8
인터넷에서의데이터흐름 Application Transport Network Link 중간주소를 local network 주소로변환 도착주소 (IP) 전달 세그먼트분할+ 포장+ 도착주소 중간주소붙여포장 ( 도착주소 or라우터주소 ) 포장벗겨도착주소확인후아니면다시포장 + 새중간주소 ( 옆의다른라우터주소 ) Network Link 포장벗겨위로전달 Network Link Application 메시지재구성 Transport 포장벗겨도착주소확인맞으면위로전달 Network 포장벗겨위로전달 Link 유닉스네트워크프로그래밍 9
연결형시스템호출 연결형소켓 (connection oriented protocol : TCP(Transmission Control Protocol)) [ 참고 P535] 서버 (server) socket( ) bind( ) 클라이언트 (client) socket( ) listen( ) accept( ) 클라이언트로부터연결이올때까지대기 연결설정 Data 요청 connect( ) write( ) read( ) read( ) Data 응답 프로세스에요청 write( ) 유닉스네트워크프로그래밍 10
비연결형소켓시스템호출 비연결형소켓 (connectionless protocol : UDP(User Datagram Protocol)) 서버 (server) socket() bind() 클라이언트 (client) recvfrom() socket() blocks until data received from a client bind() data(request) sendto() process request data(reply) write() read() 유닉스네트워크프로그래밍 11
소켓 소켓연결과정 서버가명명된소켓을생성 서버 이름 클라이언트가명명되지않은소켓을생성하고, 연결을요청 서버 이름 클라이언트 클라이언트가연결됨. 서버는원래명명된소켓을유지 서버 이름 클라이언트 완결된연결 유닉스네트워크프로그래밍 12
소켓 여러종류의소켓 다음의속성에따라분류 도메인 (domain) 유형 (type)» 서버와클라이언트소켓이존재하는장소를지칭» 클라이언트와서버사이에존재할수있는통신의유형을결정 프로토콜 (protocol)» 소켓유형을구현하는저급의수단을명시 도메인 : 서버와클라이언트소켓이존재하는장소를지칭 AF : Address Family AF_UNIX AF_INET AF_NS» 클라이언트와서버는동일한기계에존재해야함» 클라이언트와서버는인터네트어느곳에서든지존재할수있음» 클라이언트와서버는 XEROX 네트워크시스템에존재할수있음 유닉스네트워크프로그래밍 13
소켓 유형 : 클라이언트와서버와의통신의유형결정 SOCK_STREAM SOCK_DGRAM» 일련번호가붙은, 신뢰적, 양방향연결에기초한바이트의가변길이의스트림» 전보와비슷한, 무연결, 비신뢰적고정길이의메시지 SOCK_SEQPACKET SOCK_RAW» 일련번호가붙은, 신뢰적, 양방향연결에기초한바이트의고정길이패킷» 내부네트워크프로토콜과인터페이스에대한접근제공 유닉스네트워크프로그래밍 14
소켓 [ 참고 ] 도메인과소켓유형간의모든조합이허용되지는않음 AF_UNIX AF_INET AF_NS SOCK_STREAM Yes TCP SPP SOCK_DGRAM Yes UDP IDP SOCK_RAW IP Yes SOCK_SEQPACKET SPP» Yes 라표시된부분은채울약어가없으며,» 빈부분은구현되지않은부분이다. 유닉스네트워크프로그래밍 15
소켓 소켓프로그램작성 소켓사용시아래의파일포함» /usr/include/sys/types.h» /usr/include/sys/socket.h 포함 소켓도메인에따라헤더파일포함 도메인 AF_UNIX AF_INET 추가할헤더파일 /usr/include/sys/un.h /usr/include/netinet/in.h /usr/include/arpa/inet.h /usr/include/netdb.h 소스프로그램 : P525 유닉스네트워크프로그래밍 16
소켓 서버 명명된소켓을생성하고, 생성한소켓으로의 연결을수용하는것을책임지는프로세스 다음의순서대로시스템호출을사용 명칭의미 socket bind listen accept 명명되지않은소켓을생성 소켓에이름을부여 대기중인연결의최대수를명시 클라이언트로부터의소켓연결을수용 유닉스네트워크프로그래밍 17
소켓 소켓의생성 : socket( ) socket( ) 을사용하여소켓생성 동작 System call: int socket ( int domain, int type, int protocol )» 명시된 domain, type, protocol 의명명되지않은소켓을생성» 소켓생성성공시 : 새로생성된소켓에연관된파일기술자 (serverfd) 를 반환» 소켓생성실패시 : 파일기술자 (serverfd) 에 -1 반환 serverfd = socket(af_unix, SOCK_STREAM, STREAM DEFAULT_PROTOCOL); 유닉스네트워크프로그래밍 18
소켓 소켓에이름부여 : bind( ) 서버가명명되지않은소켓생성시, bind( ) 를사용하여이름부여 성공시 0 을반환, 실패시 -1 을반환 동작 System call: int bind (intfd fd, struct sockaddr* address, int addresslen )» address에저장된소켓주소를가지는파일기술자 fd를명명되지않은소켓에연관시킴» addresslen는주소구조체의길이를포함» 입력될주소의유형과값은소켓도메인에의함 유닉스네트워크프로그래밍 19
소켓 도메인에따른구조체항목 AF_UNIX 도메인» sockaddr_un 구조체의항목 항목값부여 sun_family AF_UNIX sun_path 소켓의완전한경로이름으로, 최대길이는 180 문자 AF_INET 도메인» sockaddr_in 구조체의항목 항목값부여 sin_family AF_INET sin_port 인터네트소켓의포트번호 sin_addr in_addr 유형의구조체 sin_zero 공백상태로남겨둔다 유닉스네트워크프로그래밍 20
소켓구조 /* Definitions for UNIX IPC domain /usr/include/sys/un.h s/ n */ struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[108]; /* path name (gag) */ }; /* Socket address, internet style /usr/include/netinet/in.h */ struct sockaddr_in { sa_family_t sin_family; in_port_t t sin_port; struct in_addr sin_addr; #if!defined(_xpg4_2) defined( EXTENSIONS ) char sin_zero[8]; #else unsigned char sin_zero[8]; #endif /*!defined(_xpg4_2) defined( EXTENSIONS ) */ }; struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ #define h_addr h_addr_list[0] /* address, for backward compatiblity */ }; 유닉스네트워크프로그래밍 21
소켓구조 /* Internet address /usr/include/netinet/in.h * This sdefinition to contains sobsoete obsolete fields edsfor compatibility patb ty * with SunOS 3.x and 4.2bsd. The presence of subnets renders * divisions into fixed fields misleading at best. New code * should use only the s_addr field. */ #if!defined(_xpg4_2) defined( EXTENSIONS ) #define _S_un_b S_un_b #define _S_un_w S_un_w #define _S_addr S_addr #define _S_un S_un #endif /*!defined(_xpg4_2) defined( EXTENSIONS ) */ typedef uint32_t in_addr_t; typedef unsigned int uint32_t; t struct in_addr { union { struct { uchar_t s_b1, s_b2, s_b3, s_b4; } _S_un_b; struct { ushort_t t s_w1, s_w2; } _S_un_w; #if!defined(_xpg4_2) defined( EXTENSIONS ) uint32_t _S_addr; #else in_addr_t _S_addr; #endif /*!defined(_xpg4_2) defined( EXTENSIONS ) */ } _S_un; #define s_addr _S_un._S_addr /* should be used for all code */ #define s_host _S_un._S_un_b.s_b2 /* OBSOLETE: host on imp */ #define s_ net _ S_ un. _ S_ un_ b.s_ b1 /* OBSOLETE: network */ #define s_imp _S_un._S_un_w.s_w2 /* OBSOLETE: imp */ #define s_impno _S_un._S_un_b.s_b4 /* OBSOLETE: imp # */ #define s_lh _S_un._S_un_b.s_b3 /* OBSOLETE: logical host */; 유닉스네트워크프로그래밍 22
소켓 소켓큐생성 : listen( ) 대기중인소켓연결의최대수를명시 만일, 클라이언트가가득차있는큐를소켓에연결하려고한다면, 그연결은거부됨 동작 System call: int listen ( int fd, int queuelength ) 예 ) listen (serverfd, 5); /* 대기중인연결의최대길이 */ 유닉스네트워크프로그래밍 23
소켓 클라이언트수용 : accept( ) 클라이언트의연결요구수용 기술자를반환하며, 실패시에는 -1 반환 accept( ) 가성공시통신에사용될수있는새로운파일 동작 System call: int accept ( int fd, struct sockaddr* address, int addresslen )» address 구조체 : 클라이언트의주소, 보통인터넷연결과관련되어서만사용» addresslen : address에의해서지정되는구조체의크기를포함하는정수 유닉스네트워크프로그래밍 24
소켓 클라이언트 명명되지않은소켓을생성하고, 생성한소켓을명명된서버소켓으로의접속을책임지는프로세스 다음의순서대로시스템호출을사용 명칭 socket( ) connect( ) 명명되지않은소켓을생성 의미 명명되지않은클라이언트소켓을명명된서버소켓에접속 유닉스네트워크프로그래밍 25
소켓 연결하기 : connect( ) 서버의소켓에연결 connect( ) 성공시 0 반환하고, 서버소켓이존재하지않거나, 대기큐 가가득차있으면 -1 반환 동작 System call:int connect( int fd, struct sockaddr* address, int addresslen )» address 구조체내에주소가저장되어있는서버소켓에연결을시도» 연결성공시, fd는서버의소켓과통신하기위해사용» addresslen은주소구조체의크기와동일 유닉스네트워크프로그래밍 26
소켓 유닉스도메인 (AF_UNIX) 소켓 : 명명된소켓생성 Chef/Cook 소스프로그램 $ gcc chef.c o chef lsocket $ gcc chef.c o chef lsocketl k t $ chef & $ cook 인터네트도메인 (AF_INET) 소켓 :IP 주소와 PORT 주소에의해명시 32bit IP 주소와 16bit port 번호필요 인터네트주소종류» s 는지역호스트를의미» 숫자로시작 : A.B.C.D 형식의 IP 주소로가정 소프트웨어에의해서 32bit 의 IP 주소로변환» 문자열입력 : 기호적호스트이름으로가정 소프트웨어에의해 32bit IP 주소로변환 inettime 소스프로그램 : p605 ~ p608 (debugging) $ inettimenew eecs.berkeley.edu edu 유닉스네트워크프로그래밍 27
Chef.c #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> /* AF_UNIX 소켓용 */ #define DEFAULT_PROTOCOL 0 main() { int serverfd, clientfd, serverlen, clientlen; struct sockaddr_un serverunixaddress; /* 서버주소 */ struct sockaddr_un clientunixaddress; /* 클라이언트주소 */ struct sockaddr* serversockaddrptr; /* 서버주소에대한포인터 */ struct sockaddr* clientsockaddrptr; /* 클라이언트주소에대한포인터 */ /* 좀비를방지하기위해자식 - 죽음시그널은무시 */ signal(sigchld, SIG_IGN); serversockaddrptr kaddpt = (struct (t tsockaddr*) dd*)& &serverunixaddress; serverlen = sizeof(serverunixaddress); clientsockaddrptr = (struct sockaddr*) &clientunixaddress; clientlen = sizeof(clientunixaddress); 유닉스네트워크프로그래밍 28
Chef.c (cont) /* 양방향, 디폴트프로토콜의유닉스소켓생성 */ serverfd = socket(af_unix, SOCK_STREAM, DEFAULT_PROTOCOL); serverunixaddress.sun_family = AF_UNIX; /* 도메인유형설정 */ strcpy (serverunixaddress.sun_path, "recipe"); /* 이름설정 */ unlink( "recipe"); /* 이미존재한다면, 파일제거 */ bind(serverfd, serversockaddrptr, serverlen); /* 파일생성 */ listen(serverfd, 5); /* 대기중인연결의최대길이 */ while(1) /* 무한루프 */ { /* 클라이언트연결받기 */ clientfd = accept(serverfd, clientsockaddrptr, &clientlen); printf(" Server called! "); if (fork() == 0) /* 조리법을전송할자식생성 */ { writerecipe(clientfd); /* 조리법전송 */ close(clientfd); /* 소켓닫기 */ exit(/* EXIT_SUCCESS */ 0); /* 종료 */ } else close(clientfd); /* 클라이언트기술자닫기 */ } } writerecipe (int fd) { static char* line1 = "spam, spam, spam, spam, spam,"; static char* line2 = "spam, and spam."; write (fd, line1, strlen(line1) + 1); /* 첫째줄쓰기 */ write (fd, line2, strlen(line2) + 1); /* 두번째줄쓰기 */ } 유닉스네트워크프로그래밍 29
Cook.c #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define DEFAULT_PROTOCOL 0 main() { int clientfd, serverlen, result; struct sockaddr_un serverunixaddress; struct sockaddr* serversockaddrptr; serversockaddrptr = (struct sockaddr*) &serverunixaddress; serverlen = sizeof(serverunixaddress); /* 양방향, 디폴트프로토콜의유닉스소켓생성 */ clientfd = socket(af_unix, SOCK_STREAM, STREAM DEFAULT_PROTOCOL); serverunixaddress.sun_family = AF_UNIX; /* 서버도메인 */ strcpy( serverunixaddress.sun_path, "recipe"); /* 서버이름 */ do { /* 서버와연결되기까지루프 */ result = connect (clientfd, serversockaddrptr, serverlen); if(result == -1) sleep(1); /* 대기후다시시도 */ } while(result == -1); 유닉스네트워크프로그래밍 30
Cook.c (cont) readrecipe(clientfd); /* 조리법읽기 */ close(clientfd); /* 소켓닫기 */ exit(/* EXIT_SUCCESS */ 0); /* 수행끝 */ } readrecipe(int fd) { char str[200]; } while(readline(fd, str)) /* 입력끝까지줄읽기 */ printf("%s\n", str); /* 소켓으로부터줄출력 */ /*********************************************/ readline(int fd, char* str) { int n; } do { n = read(fd,str,1); } while(n > 0 && *str++!= NULL); return (n > 0); 유닉스네트워크프로그래밍 31
inettime.c: 인터네트시간청취 #include <stdio.h> #include <signal.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> /* For AFINET sockets */ #include <arpa/inet.h> #include <netdb.h> #define DAYTIME_PORT 13 /* Standard port o */ #define DEFAULT_PROTOCOL 0 unsigned long promptforinetaddress (); unsigned long nametoaddr (); main () { int clientfd; /* Client socket file descriptor */ int serverlen; /* Length of server address structure */ int result; /* From connect () call */ struct sockaddr_in serverinetaddress; /* Server address */ struct sockaddr* serversockaddrptr; /* Pointer to address */ unsigned long inetaddress; /* 32-bit IP address */ /* Set the two server variables */ serversockaddrptr = (struct sockaddr*) &serverinetaddress; 유닉스네트워크프로그래밍 32
inettime.c: 인터네트시간청취 (cont.) serverlen = sizeof (serverinetaddress); /* Length of address */ while (1) /* Loop until break */ { inetaddress = promptforinetaddress (); /* Get 32-bit IP */ if (inetaddress == 0) break; /* Done */ /* Start by zeroing out the entire address structure */ bzero ((char*)&serverinetaddress,sizeof(serverinetaddress)); serverinetaddress.sin_family = AF_INET; /* Use Internet */ serverinetaddress.sin_addr.s_addr sin s = inetaddress; /* IP */ serverinetaddress.sin_port = htons (DAYTIME_PORT); /* Now create the client socket */ clientfd = socket (AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL); do /* Loop until a connection is made with the server */ { result = connect (clientfd,serversockaddrptr,serverlen); if (result == -1) sleep (1); /* Try again in 1 second */ } while (result == -1); readtime (clientfd); /* Read the time from the server */ close (clientfd); /* Close the socket */ } exit (/* EXIT_SUCCESS */ 0); } 유닉스네트워크프로그래밍 33
inettime.c: 인터네트시간청취 (cont.) unsigned long promptforinetaddress () { char hostname [100]; /* Name from user: numeric or symbolic */ unsigned long inetaddress; /* 32-bit IP format */ /* Loop until quit or a legal name is entered */ /* If quit, return 0 else return host's IP address */ do { printf ("Host name (q = quit, s = self): "); scanf ("%s", hostname); /* Get name from keyboard */ if (strcmp (hostname, "q") == 0) return (0); /* Quit */ inetaddress = nametoaddr (hostname); /* Convert to IP */ if (inetaddress == 0) printf ("Host name not found\n"); } while (inetaddress == 0); } unsigned long nametoaddr (name) char* name; { char hostname [100]; struct hostent* hoststruct; struct in_addr* hostnode; /* Convert name into a 32-bit IP address */ /* If name begins with a digit, assume it's a valid numeric */ /* Internet address of the form A.B.C.D and convert directly */ if (isdigit (name[0])) return (inet_addr (name)); 유닉스네트워크프로그래밍 34
inettime.c: 인터네트시간청취 (cont.) if (strcmp (name, "s") s) ==0)/* Get host name from database */ { gethostname (hostname,100); printf ("Self host name is %s\n", hostname); } else /* Assume name is a valid symbolic host name */ strcpy (hostname, name); /* Now obtain address information from database */ hoststruct = gethostbyname (hostname); if (hoststruct == NULL) return (0); /* Not Found */ /* Extract the IP Address from the hostent structure */ hostnode = (struct in_addr*) hoststruct->h_addr; /* Display a readable version for fun */ printf ("Internet Address = %s\n", inet_ntoa (*hostnode)); return (hostnode->s >s_addr); /* Return IP address */ } readtime (fd) int fd; { char str [200]; /* Line buffer */ printf ("The time on the target port is "); while (readline (fd, str)) /* Read lines until end-of-input */ printf ("%s\n", str); /* Echo line from server to user */ } 유닉스네트워크프로그래밍 35
inettime.c: 인터네트시간청취 (cont.) readline (fd, str) int fd; char* str; /* Read a single NEWLINE-terminated line */ { int n; do /* Read characters until NULL or end-of-input */ { } n=read(fd (fd, str, 1);/* Read one character */ } while (n > 0 && *str++!= '\n'); return (n > 0); /* Return false if end-of-input */ 유닉스네트워크프로그래밍 36
소켓 인터네트클라이언트 소켓도메인 : AF_INET 소켓주소구조체 (sockaddr_in) 의 4항목 인터네트서버 sin_family : 소켓의도메인으로, AF_INET 로설정 sin_port : 포트번호지정 sin_addr : 클라이언트 / 서버의 32bit IP 주소 sin_zero : 삽입구로, 공백상태로남겨둠 소켓주소구조체의항목은클라이언트항목과같게 sin_port 항목은 INADDR_ANYANY 로설정, 이것은 어떠한입력클라이언트요구들 도받아들인다 는것을의미 struct sockaddr_in serverinetaddress; /* 서버인터네트주소 */ serverinetaddress.sin_family il = AF_INET; /* 인터네트도메인 */ serverinetaddress.sin_addr.s_addr = htonl(inaddr_any); serverinetaddress.sin_port = htons(port); /* 서버포트번호 */ /* 모두받아들임 */ 유닉스네트워크프로그래밍 37
소켓 Library call: unsigned long inet_addr(char* string) A.B.C.D 형식의 string 에해당하는 32bit 주소로변환 system call: int gethostname(char* name, int namelen) 길이가 namelen 인 name 이가리키는문자배열은지역호스트이름과동일한 NULL로끝나는문자열로설정 Library call: struct t hostent* t* gethostbyname(char* tb h name) /etc/hosts 파일탐색하여, 문자열 name과연관된파일엔트리로묘사하는구조체 hostent 를가리키는포인터로반환 만일, name이 /etc/hosts 파일에서발견되지않으면 NULL반환 유닉스네트워크프로그래밍 38
소켓 Library call: char* *inet_ntoa(struct t t tin_addr address) 인수로 in_addr형의구조체를취하고, A.B.C.D 형식으로주소를묘사하는문자열에대한포인터를반환 Library call: void bzero(char* buffer, int length) 크기가 length 인 buffer 를 0(ASCII NULL) 로채움 Library call: unsigned long htonl(unsigned long hostlong) 호스트형식인 unsigned long 유형의 hostlong 과동등한네트워크형식을반환 Library call: unsigned short ntohs(unsigned long hostlong) 네트워크형식인 unsigned short 유형의 networkshort와동등한호스트형식을반환 유닉스네트워크프로그래밍 39
소켓 인터네트서버 소켓주소구조체의항목은클라이언트항목과같게 sin_port 항목은 INADDR_ANYANY 로설정, 이것은 어떠한입력클라이언트 요구들도받아들인다 는것을의미 struct sockaddr_in serverinetaddress; /* 서버인터네트주소 */ serverinetaddress.sin_family = AF_INET; /* 인터네트도메인 */ serverinetaddress.sin e ess.s addr.s_addr = htonl(inaddr _ ANY); /* 모두받아들임 */ serverinetaddress.sin_port = htons(port); /* 서버포트번호 */ 유닉스네트워크프로그래밍 40
IP 주소변환의세가지방법및변환함수 aaa.bbb.ccc.ddd: 11000011 11001011 10010000 00001011 :192.203.144.11203 144 11 csblade.incheon.ac.kr: :211.119.245.149 도메인네임 : IP 주소 (binary) : dotted decimal gethostbyname( ) inet_addr( ) gethostbyaddr( ) inet_ntoa( ) 유닉스네트워크프로그래밍 41
파일기술자와소켓기술자 ( 소켓번호 ) 기술자테이블 파일또는정보구조체 ( 파일 ) 파일기술자또는 3 pointer 소켓기술자 4 pointer ( 파일 ) 5 ( 소켓 ) pointer family:pf_inet service :SOCK_STREAM STREAM local IP: local lport: remote IP: remote port: : : 유닉스네트워크프로그래밍 42
응용프로그램과소켓,TCP/IP 의관계 연결형서비스 비연결형서비스 응용 1 응용 2 응용 3 응용 4 fd=3 sd=4 sd=3 sd=3 sd=3 응용프로그램 ( 소켓번호 ) 소켓 층 TCP UDP ( 포트번호 ) 트랜스포트계 TCP/IP I P 인터넷계층 (IP 주소 ) 네트워크 fd :File Descriptor IP:Internet Protocol sd:socket Descriptor TCP:Transmission Control Protocol UDP:User Datagram Protocol 유닉스네트워크프로그래밍 43
포트번호 (Port Number) 16- 비트포트번호 하나이상의프로세스가한꺼번에 TCP나 UDP를사용할수있기위해각사용자프로세스와관련된데이터구분필요 32- 비트 Internet t 주소로는호스트만접촉가능, 특정프로세스가리키는방법필요 1~255 : 미리할당된포트번호 /usr/include/netinet/in.h 에서표준포트 (well-known ports) 확인 ( 예 ) FTP 제공 TCP/IP 포트번호 : 21 4.3BSD : 1~1023 수퍼유저프로세스위해예약 1023 < TCP 의포트번호 < 5000 인터넷한벌 (TCP/IP 또는 UDP/IP) 에서연결을정의하는 5 쌍 규약 (TCP 또는 UDP) 지역호스트의 Internet 주소 (32-비트) 지역포트번호 (16-비트) 상대호스트의 Internet 주소 (32-비트) 상대포트번호 (16-비트) ( 예 ) {tcp, 128.10.0.3, 1500, 128.10.0.7, 21} 유닉스네트워크프로그래밍 44
inetserver.c : 인터네트서버 /* compile : gcc -o client client.c -lsocket -lnsl */ /* execute ecute : server e */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define PORTNUM 3000 main(int argc, char *argv[]) { int serverfd, clientfd, clilen, childpid; struct sockaddr_in cli_addr, serv_addr; if((serverfd = socket(af_inet, SOCK_STREAM, 0)) < 0){ printf("server: can't open stream socket"); return -1; } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr sin s = htonl(inaddr_any); ANY); /* 어떤호스트의클라이언트도다받아들임 */ serv_addr.sin_port = htons(portnum); /* 서버포트번호 */ if(bind(serverfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) printf("server: can't bind local address"); printf("server is binded\n"); listen(serverfd, 5); 유닉스네트워크프로그래밍 45
inetserver.c : 인터네트서버 (cont.) for( ; ; ){ /* Wait for a connection from a client process. * This is an example of a concurrent server. */ clilen = sizeof(cli_addr); clientfd = accept(serverfd, (struct sockaddr *) &cli_addr, &clilen); printf("server called\n"); if((childpid = fork()) < 0){ printf("server: fork error"); exit(0); } else if(childpid == 0){ /* child process */ printf("serverfd = %d, clientfd = %d\n", serverfd, clientfd); /* process the request */ write(clientfd,"hello!",7); close(clientfd); /* close original socket */ return -1; } close(clientfd); /* parent process */ } } 유닉스네트워크프로그래밍 46
inetclient.c t : 인터네트클라이언트 /* compile : gcc -o client client.c -lsocket -lnsl */ /* execute : inetclient hostname(or server IP) */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define PORTNUM 3000 main(int argc, char *argv[]) { int clientfd; char str[10]; char* hostaddress; struct sockaddr_in serv_addr; struct hostent* hoststruct; struct in_addr* hostnode; if(argv[1] == NULL){ } printf("usage: inetclient hostname(or server IP)\n"); printf(" (Ex) inetclient isis.inchon.ac.kr(or 210.126.35.99)\n"); exit(0); 유닉스네트워크프로그래밍 47
inetclient.c t : 인터네트클라이언트 (cont.) hoststruct = gethostbyname(argv[1]); if(hoststruct == NULL) return(0); hostnode = (struct in_addr*) hoststruct->h_addr; hostaddress = inet_ntoa(*hostnode); /* Fill in the structure "serv_addr" with the address of the * server that we want to connect with. */ bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(hostaddress); serv_addr.sin_port = htons(portnum); /*Open a TCP socket (an Internet stream soskcet). */ if((clientfd = socket(af_inet, SOCK_STREAM, 0)) < 0) printf("client: t can't open stream socket"); /* Connect to the server */ if(connect(clientfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) printf("client: can't connect to server"); printf("clientfd = %d\n", clientfd); read(clientfd, str, 10); printf("%s\n", str); close(clientfd); exit(0); 유닉스네트워크프로그래밍 48
인터네트셸 설계 파이프와후면처리기능제공 표준유닉스셸과유사하면서, 인터네트- 명시적기능추가 셸의기능을적합한크기로구성하기위해제한 모든토큰 (token) 은공란 (tab 또는 space) 에의해서분리 파일이름대치는지원되지않음 유닉스네트워크프로그래밍 49
인터네트셸 명령구문 : 표준유닉스셸의명령어구문과유사 <internetshellcommand> = <sequence> [ & ] <sequence> = <pipeline> { ; <pipeline> }* <pipeline> = <simple> { <simple> } <simple> = { <token> }* { <redirection> }* <redirection> = <fileredirection> <socketredirection> <fileredirection> = \> <file> >> <file> \< <file> <socketredirection> = <clientredirection> <serverredirection> <clientredirection> = @\>c <socket> @\<c <socket> <serverredirection> = @\>s <socket> @\<s <socket> <token> = a string of chracters <file> = a valid UNIX pathname <socket> = either a UNIX pathname ( UNIX domain socket ) or an Internet socket name of the form hostname.port# 유닉스네트워크프로그래밍 50
인터네트셸 인터네트셸시작하기 내장명령어 인터네트셸실행파일이름 : ish 인터네트셸프롬프트 : 의문부호 (?) ish 시작시자신을호출한셸에서 $PATH 환경변수를상속받음» $PATH 값은내장명령어 setenv 를사용해변경가능» 인터네트셸종료시 : control-d 내장명령어 echo { <token> }* cd path getenv name setenv name value 기능터미널에 token을에코 (echo) 셸의작업디렉토리를 path 로변경환경변수 name의값을표시환경변수 name의값을 value로설정 소스프로그램 : P624~648 유닉스네트워크프로그래밍 51
소켓응용프로그램 인터넷토크프로그램 netprog의 talk_server.c talk_client.c 소스코드참조 실행 % talk_server 포트번호 % talk_client 서버호스트IP주소포트번호 인터넷채팅프로그램 하나의프로세스가채팅참가신청처리와클라이언트들의통신처리를다할수있도록 accept() 또는 read() 에서계속기다리는동기 (synchronous, blocking) 모드대신 select() 시스템호출을이용하여소켓을비동기 (asynchronous, non-blocking) 모드로이용 netprog의 chat_server.c chat_client.c 소스코드참조 실행 % chat_server 포트번호 % chat_client 서버호스트IP주소포트번호 유닉스네트워크프로그래밍 52
select() select() 소켓에서발생하는 I/O 변화를기다리다가지정된 /O 변화가발생하면리턴됨 초기소켓 s 와참가한클라이언트들의소켓의 I/O 변화감지 select() 시스템호출형식 int select ( int maxfdp1, /* chleo 파일 ( 및소켓 ) 번호크기 +1 */ fd_set *readfds, /* 읽기상태변화를감지할소켓지정 */ fd_set *writefds, /* 쓰기상태변화를감지할소켓지정 */ fd_set *exceptfds, /* 예외상태변화를감지할소켓지정 */ struct timeval *tvptr); /*select() 시스템호출이기다리는시간 */ FD_ZERO(fd_set _ *fdset) 매크로로모든비트지움 FD_SET(int fd, fd_set *fdset) 매크로로소켓 fd의 fdset 변화를감지하기위해 fdset 중 fd에해당하는비트를 1로지정 FD_ISSET(int fd, fd_set *fdset) 매크로는 fdset 의해당 fd 비트가 1 로지정되어있으면양수값리턴하므로 fd에게 fdset 변화가발생했는지판단 유닉스네트워크프로그래밍 53
과제 12 월 7 일까지 문제 1과문제 2 중택일 문제 1: 개선된인터넷채팅스레드버전 채팅서버가임의의클라이언트가채팅에참가하는요청을하면이를채팅참가자리스트에추가하며채팅에참가하고있는클라이언트들이보내오는메시지를모든채팅참가자에게다시방송하는기능을수행해주는 chat_server와 chat_client 인터넷채팅프로그램을스레드버전으로수정하되 chat_server의자식스레드로하여금메시지방송 (broadcast) 기능을수행하게하고, chat_client의두개의자식스레드로하여금메시지송신기능과수신기능을각각수행하게하고, 이채팅프로그램에채팅참가자목록을보여주는?who 명령을추가하라. 문제 2 : 교재 p579 가위, 바위, 보게임 : 제2부 ( 인터넷버전 ) 두명의경기자들이서로다른인터네트기계에서게임을할수있는가위, 바위보게임을작성하라. 이명령을호스트 xx 에서실행 지역포트 5000 사용 $ refree 5000 이명령을호스트 yy에서실행 $ player xx 5000 이명령을호스트 zz에서실행 $ player xx 5000 네트워크프로그램실행시주의사항 포트번호수정해서서버실행 : 5500 < 포트번호 < 5900 실습끝난후반드시서버프로세스종료 : kill -9 프로세스번호 (ps 명령으로알아냄 ) 제출방법 1. Electrical Version 1 csmail.incheon.ac.kr (117.16.244.56) 의 /home/2009hw/2009ula 또는 2009ulb에자기학번으로숙제방 ( 디렉토리 ) 만들고그안에복사 자신의디렉토리보호권장 : chmod 1700 directoryname 2. Electrical l Version 2 multi.incheon.ac.kr (117.16.244.57의 /export/home/2009hw/2009ula 또는 2009ulb에자신의학번으로숙제방 ( 디렉토리 ) 만들고그안에복사 자신의디렉토리보호권장 : chmod 1700 directoryname 유닉스네트워크프로그래밍 54
X 윈도우프로그램과시스템관리 X 윈도우프로그래밍 /usr/x/demo 실행해보기 puzzle spider xeyes xsol 등 X manager : http://www.netsarang.co.kr 에서 30 일버전다운로드 Http://marvel.inchon.ac.kr/~mysung ac Lecture Notes X Window Program 참조 Anonymous ftp multi cd pub/xprog 참조 시스템관리 Http://marvel.inchon.ac.kr/~mysung Lecture Notes System Administration 참조 유닉스네트워크프로그래밍 55
오! 유닉스 유닉스는재미있다. 유닉스는사용하기는쉽지만배우기는어렵다. 유닉스의모든것을배우는것은불가능하다. 필요한것과재미있을것같다고생각되는부분에관심을쏟는것이좋다. 유닉스는세련되고영리한사람들을위한도구의집합이다. 수고많이하셨습니다!