10. Unix Domain Socket 105/113 10. Unix Domain Socket 본절에서는 Unix Domain Socket(UDS) 에대한개념과이에대한실습을수행하고, 이와동시에비신뢰적인통신시스템의문제점에대해서분석하도록한다. 이번실습의목표는다음과같다. 1. Unix Domain Socket의사용법을익히고, IPC에대해서실습 2. TCP/IP의응용계층과전달계층의동작을구현및실습 3. Fragmentation 과 Header를구성하는실습 4. UDP 소켓통신의비신뢰성에대해서실습 10.1 Unix Domain Socket Unix Domain Socket(UDS) 는 socket API를수정없이이용하며, Port 기반의 Internet Domain Socket에비해서로컬시스템의파일시스템을이용해서내부프로세스간의통신을위해사용한다는점이다르다고할수있으며, 일반적으로한호스트에서 IPC와같이사용하였을때 2배이상의효율을가진다. 일반적으로, 약간복잡한내부프로세스간통신을해야된다고했을때 UDS을많이사용한다. 인터넷소켓통신이 TCP/IP 4계층을모두거치는것과는다르게, UDS는어플리케이션계층에서 TCP 계층까지만메시지가전달되고, 다시곧바로어플리케이션계층으로메시지가올라가게된다. 위에서 INET 소켓보다 2배이상의효율을가진다고했는데, 4계층의계층을모두거쳐야하는 INET 소켓에비해서단지 2개의레이어만사용한다는점도그이유중하나로작용한다. 10.2 An Example of Unix Domain Socket 다음예제는서버에서파일을하나읽어온후 256바이트씩조각을내어서 IPC (Inter Process Communication) 를수행한다. 두번째시간에다루었던 filecopy() 를사용해서한호스트내에서 IPC의수행의모습을구현하였으며, 클라이언트에서는 256바이트씩전송되는데이터를화면에출력한다. 일반적으로 UDS에서는 sockaddr_un의구조체를사용하며, 구조체의형태는아래의소스에나타나있다. 일반적으로 sum_family에는 AF_UNIX를대입하고, sun_path에는 IPC를위한파일맵을구성한다. Network Programming
10. Unix Domain Socket 106/113 기존의 INET 버젼의프로그램과비교해보면고작 3줄정도만수정되었음을알수있을것이다. 단지소켓구조체가 sockaddr_un 으로바뀌고, AF_INET 대신 AF_UNIX 를그 Network Programming
10. Unix Domain Socket 107/113 리고 port 번호대신에파일명을사용했음을알수있다. 나머지의모든코드는 INET 코드와완전히같다. 그러므로 Unix Domain Socket 를사용하면 Inet Domain Socket 와코드일관성을유지할수있으며, 동일한기술을사용해서프로그래밍을할수있다. 동작의모습은다음과같다. 1. Server 의동작 2. Client 의동작 Network Programming
10. Unix Domain Socket 108/113 10.4 Unreliable Communications App Layer Transport Layer 본실습에서는위의 UDS를기반으로수행되는 Unreliable Communications에대해서실습하도록한다. 위의그림과같이 2개의호스트가 UDP 소켓통신을수행하며, 각각의호스트에는 2개의프로세스가소켓통신을위해서각각의역할을수행한다. 각각의동작은다음과같이구분하도록한다. 1. 좌측의응용계층의프로세스는기본적으로파일을디스크로부터읽어서원하는사이즈만큼아래의프로세스로전송한다. 2. 좌측의전달계층의프로세스는 Fragmentation된파일의정보에 Header 정보를추가하고, 이를 Sendto() 함수를통해 UDP 소켓통신을수행한다. 3. 우측의전달계층의프로세스는 Recvfrom() 함수를통해 UDP 소켓을수신하고, Header의정보를가지고, Loss Rate를분석하도록하며, Header를파기하고, 실제데이터만응용계층의프로세스에전달한다. 4. 우측의응용계층의프로세스는 IPC로받은메시지를수합하여서디스크에저장한다. 다음과같이비신뢰적인소켓통신의분석을위해서는다음과같은헤더를정의하여서조각난파일정보에추가하여야한다. Network Programming
10. Unix Domain Socket 109/113 10.4.1 Header Information 일반적으로비신뢰적통신을 TCP와같이신뢰적인통신으로수행하기위해서는기본적으로다음과같은최소한의요구사항을만족해야한다. 1. 헤더를이용하여서손실된세그멘테이션의정보를얻을수있어야한다. 2. 시간에따른이벤트를정의해서이에따라능동적으로통신이수행되어야한다. 이번실습에서는 1 의요구사항을만족하기위해간단한헤더를정의하도록한다. Type Name Size Behavior Unsigned int Sequence 4 bytes 순서번호 Unsigned int Size 4 bytes 세그멘테이션크기 char message 256 bytes 실제메시지 다음과같이정의하도록하여서수신한후순서번호에따라서손실률을판단하도록한다. Network Programming
10. Unix Domain Socket 110/113 10.5 Implementation 구현은아래의그림과같이 4개의파일로구현이되며, 소스는다음페이지부터확인할수있다. 10.5.1 Result Network Programming
Y:\Projects\Unreliable\packetinfo.h 00001: #ifndef _PACKETINFO_H 00002: #define _PAKCETINFO_H 00003: 00004: #define NAME "unix.socket" 00005: #define BUFF_SIZE 256 00006: 00007: 00008: typedef struct nppacket 00009: { 00010: unsigned int sequence; 00011: unsigned int size; 00012: char message[256]; 00013: }np_header; 00014: 00015: #endif Page 1
Y:\Projects\Unreliable\appServer.c 00001: #include "etcp.h" 00002: #include "packetinfo.h" 00003: #include <sys/ un.h> 00004: 00005: 00006: void sig_chld sig_chld (int signo); 00007: void filecopy(int, int); 00008: 00009: int main(int argc, char ** argv) 00010: { 00011: setdebug(&argc, argv); 00012: 00013: int status; 00014: int servfd, clifd; 00015: int len; 00016: int rval; 00017: int filedesc; 00018: pid_t chldpid; 00019: / * Unix Domain Socket uses "sockaddr_un" Structure */ 00020: struct sockaddr_un un; 00021: char buf[buff_size] = {0}; 00022: 00023: / * Signal Register */ 00024: signal(sigchld, sig_chld); 00025: 00026: if(argc!= 2){ 00027: printf("usage : %s <file name>\n", argv[0]); 00028: exit(1); 00029: } 00030: / * file open */ 00031: if((filedesc = open(argv[1], O_RDONLY))<0) 00032: error(1, errno, "File open error()"); 00033: 00034: / * Unix Domain Socket */ 00035: / * 1st argument : AF_UNIX */ 00036: if((servfd=socket(af_unix,sock_stream,0)) < 0) 00037: error(1, errno, "Unix Domain Socket Error()"); 00038: 00039: unlink(name); 00040: 00041: / * structure Setting */ 00042: memset(&un,0,sizeof(un)); 00043: un.sun_family = AF_UNIX; 00044: strcpy(un.sun_path, NAME); 00045: 00046: len = sizeof(un.sun_family)+strlen(name); 00047: 00048: if(bind(servfd,(struct sockaddr*)&un,len)<0) 00049: error(1, errno, "Binding() error"); 00050: 00051: if(listen(servfd, 5)<0) 00052: error(1, errno, "Listening() error"); 00053: 00054: / * Child Section */ 00055: if((chldpid = fork()) == 0){ 00056: execl("./ transserver", "./ transserver", NULL); 00057: _exit(0); 00058: } 00059: 00060: / * Parent Section */ 00061: else{ 00062: if((clifd = accept(servfd, (struct sockaddr *)&un, &len))<0) 00063: error(1, errno, "Accept() error"); 00064: 00065: debug("================================\n"); 00066: debug("descriptor : file :%d\tserver :%d\tclient :%d\n", filedesc, servfd, clifd); 00067: 00068: filecopy(filedesc, clifd); 00069: } 00070: 00071: close(filedesc); 00072: close(clifd); 00073: close(servfd); 0? end main? 0074: } 00075: Page 1
Y:\Projects\Unreliable\appServer.c 00076: void filecopy(int from, int to) 00077: { 00078: char buf[buff_size]; 00079: int len; 00080: 00081: while(( len = read(from, buf, sizeof(buf)))!= 0){ 00082: write(to, buf, len); 00083: } 00084: } 00085: 00086: void sig_chld(int signo) 00087: { 00088: pid_t pid; 00089: int stat; 00090: 00091: while((pid = waitpid(- 1, &stat, WNOHANG)) > 0) 00092: debug("child %d Terminated\n", pid); 00093: } Page 2
Y:\Projects\Unreliable\transServer.c 00001: / * 00002: * NP 2010 - Unix Domain Socket 00003: */ 00004: #include "etcp.h" 00005: #include "packetinfo.h" 00006: #include <sys/ un.h> 00007: 00008: np_header* attachheader(char*, int); 00009: 00010: int sequencenum =0; 00011: 00012: int main(int argc, char ** argv) 00013: { 00014: setdebug(&argc, argv); 00015: 00016: 00017: char* hname = "np2.hufs.ac.kr"; 00018: 00019: / * for Unix Domain Socket */ 00020: int clifd; 00021: int len; 00022: char buf[buff_size] = {0,}; 00023: struct sockaddr_un un; 00024: 00025: / * for Internet Socket (UDP) */ 00026: int udpserverfd; 00027: socklen_t lenrc; 00028: int size; 00029: char bufudp[buff_size] = {0,}; 00030: struct sockaddr_in servaddr; 00031: 00032: np_header * Np; 00033: 00034: / * for Unix Domain Socket */ 00035: if((clifd = socket(af_unix, SOCK_STREAM, 0)) < 0) 00036: error(1, errno, "Unix Domain Socket () error"); 00037: 00038: memset(&un,0,sizeof(un)); 00039: un.sun_family = AF_UNIX; 00040: strcpy(un.sun_path,name); 00041: len = sizeof(un.sun_family)+strlen(name); 00042: 00043: / * for Internet Socket (UDP) */ 00044: udpserverfd = udp_client(hname, "9000", &servaddr); 00045: lenrc = sizeof(servaddr); 00046: 00047: if(connect(clifd,(struct sockaddr*)&un,len)<0) 00048: error(1, errno, "connection () error"); 00049: 00050: while((len = read(clifd, buf, sizeof(buf))) > 0) 00051: { 00052: buf[len] ='\0'; 00053: 00054: Np = attachheader(buf, len); 00055: 00056: size = sendto(udpserverfd, Np, ntohs(np->size)+8, 0, &servaddr, lenrc); 00057: debug("%d\t%d\t%d\n",size, ntohs(np->size), ntohs(np- >sequence)); 00058: debug("%s\n",np- >message); 00059: } 00060: 00061: / * Send the End- of- File for UDP Socket */ 00062: size = sendto(udpserverfd, NULL, 0, 0, &servaddr, lenrc); 00063: close(clifd); 00064: 00065: return 0; 0? end main? 0066: } 00067: 00068: np_header * attachheader(char* buf, int len) 00069: { 00070: np_header * attacher; 00071: 00072: attacher- >sequence = htons(sequencenum++); 00073: attacher->size = htons(len); 00074: strcpy(attacher- >message, buf); 00075: 00076: return attacher; 00077: } Page 1
X:\Projects\UnreliableClient\appClient.c 00001: #include "etcp.h" 00002: #include <sys/ un.h> 00003: #include "packetinfo.h" 00004: 00005: void sig_chld sig_chld (int signo); 00006: void filecopy(int, int); 00007: 00008: int main(int argc, char ** argv) 00009: { 00010: setdebug(&argc, argv); 00011: 00012: int status; 00013: int servfd, clifd; 00014: int len; 00015: int rval; 00016: int filedesc; 00017: pid_t chldpid; 00018: 00019: / * Unix Domain Socket uses "sockaddr_un" Structure */ 00020: struct sockaddr_un un; 00021: char buf[buff_size] = {0}; 00022: 00023: / * Signal Register */ 00024: signal(sigchld, sig_chld); 00025: 00026: if(argc!= 2){ 00027: printf("usage : %s <file name>\n", argv[0]); 00028: exit(1); 00029: } 00030: / * file open */ 00031: if((filedesc = open(argv[1], O_WRONLY O_CREAT O_TRUNC, S_IRUSR S_IWUSR))<0) 00032: error(1, errno, "File open error()"); 00033: 00034: / * Unix Domain Socket */ 00035: / * 1st argument : AF_UNIX */ 00036: if((servfd=socket(af_unix,sock_stream,0)) < 0) 00037: error(1, errno, "Unix Domain Socket Error()"); 00038: 00039: unlink(name); 00040: 00041: / * structure Setting */ 00042: memset(&un,0,sizeof(un)); 00043: un.sun_family = AF_UNIX; 00044: strcpy(un.sun_path, NAME); 00045: 00046: len = sizeof(un.sun_family)+strlen(name); 00047: 00048: if(bind(servfd,(struct sockaddr*)&un,len)<0) 00049: error(1, errno, "Binding() error"); 00050: 00051: if(listen(servfd,10)<0) 00052: error(1, errno, "Listening() error"); 00053: 00054: / * Child Section */ 00055: if((chldpid = fork()) == 0){ 00056: execl("./ transclient", "./ transclient", NULL); 00057: _exit(0); 00058: } 00059: 00060: / * Parent Section */ 00061: else{ 00062: if((clifd = accept(servfd, (struct sockaddr *)&un, &len))<0) 00063: error(1, errno, "Accept() error"); 00064: 00065: debug("================================\n"); 00066: debug("descriptor : file :%d\tserver :%d\tclient :%d\n", filedesc, servfd, clifd); 00067: 00068: filecopy(clifd, filedesc); 00069: 00070: waitpid(chldpid, &status, 0); 00071: } 00072: 00073: close(filedesc); 00074: close(clifd); 00075: close(servfd); 0? end main? 0076: } 00077: Page 1
X:\Projects\UnreliableClient\appClient.c 00078: void filecopy(int from, int to) 00079: { 00080: char buf[buff_size]; 00081: int len; 00082: 00083: while(( len = read(from, buf, sizeof(buf)))!= 0){ 00084: write(to, buf, len); 00085: } 00086: } 00087: void sig_chld(int signo) 00088: { 00089: pid_t pid; 00090: int stat; 00091: 00092: while((pid = waitpid(- 1, &stat, WNOHANG)) > 0) 00093: debug("child %d Terminated\n", pid); 00094: } 00095: Page 2
X:\Projects\UnreliableClient\transClient.c 00001: #include "etcp.h" 00002: #include <sys/ un.h> 00003: #include "packetinfo.h" 00004: 00005: int main(int argc, char **argv) 00006: { 00007: setdebug(&argc, argv); 00008: 00009: / * for Unix Domain Socket */ 00010: int udsclifd; 00011: int len; 00012: struct sockaddr_un un; 00013: 00014: / * for Internet Socket UDP */ 00015: int servfd; 00016: int size; 00017: char buf[sizeof(np_header)] = {0,}; 00018: char sendmsg[buff_size] = {0,}; 00019: np_header * pip; 00020: 00021: / * for Statical Information */ 00022: int nextsequence = 0; 00023: int lossnum = 0; 00024: int totalpacket = 0; 00025: int lossgap; 00026: double lossrate; 00027: 00028: / * for Unix Domain Socket */ 00029: if((udsclifd = socket(af_unix, SOCK_STREAM, 0)) < 0) 00030: error(1, errno, "Unix Domain Socket error"); 00031: 00032: memset(&un, 0, sizeof(un)); 00033: un.sun_family = AF_UNIX; 00034: strcpy(un.sun_path, NAME); 00035: len = sizeof(un.sun_family)+strlen(name); 00036: 00037: / * for internet socket */ 00038: servfd = udp_server(null, "9000"); 00039: 00040: if(connect(udsclifd, (struct sockaddr*)&un, len)<0) 00041: error(1, errno, "Connection() error"); 00042: 00043: while(size = recvfrom(servfd, (void*)&buf, sizeof(buf), 0, NULL, NULL)!=0){ 00044: if(size < 0) 00045: errro(1, errno, "recvfrom Error"); 00046: / * Casting the received segmentation */ 00047: pip = (np_header*)buf; 00048: 00049: debug("%d\n",ntohs(pip- >sequence)); 00050: debug("%d\n",ntohs(pip->size)); 00051: 00052: / * Calculate Some Loss Rate */ 00053: if(ntohs(pip- >sequence) == nextsequence){ 00054: totalpacket++; 00055: nextsequence++; 00056: } 00057: else{ 00058: lossgap = ntohs(pip- >sequence)- nextsequence; 00059: lossnum += lossgap; 00060: nextsequence = ntohs(pip- >sequence)+1; 00061: totalpacket++; 00062: } 00063: 00064: 00065: strncpy(sendmsg, pip- >message, ntohs(pip->size)); 00066: debug("%s\n", pip- >message); 00067: write(udsclifd, sendmsg, ntohs(pip->size)); 000? end while size=recvfrom(servfd,...? 68: } 00069: 00070: printf("\n\n\=========statical Information===========\n"); 00071: printf("total Packets : %d\n", (ntohs(pip- >sequence))+1); 00072: printf("total Received Packets : %d\n", totalpacket); 00073: printf("total Loss Packets : %d\n", lossnum); 00074: printf("total Loss Rate : %f %%\n", (double)lossnum/ (double)(ntohs(pip- >sequence)+1)*100); 00075: printf("====================================\n\n"); 00076: return 0; 0? end main? 0077: } Page 1