소켓프로그래밍활용 IT CookBook, 유닉스시스템프로그래밍
학습목표 소켓인터페이스를활용한다양한프로그램을작성할수있다. 2/23
목차 TCP 기반프로그래밍 반복서버 동시동작서버 동시동작서버-exec함수사용하기 동시동작서버-명령행인자로소켓기술자전달하기 UDP 프로그래밍 3/23
TCP 기반프로그래밍 반복서버 데몬프로세스가직접모든클라이언트의요청을차례로처리 동시동작서버 데몬프로세스가직접서비스를제공하지않고, 서비스와관련있는다른프로세스를 fork 함수로생성해클라이언트와연결시켜준다. 4/23
[ 예제 12-1] (1) 반복서버 ( 서버 ) ex12_1s.c... 10 #define PORTNUM 9001 11 12 int main(void) { 13 char buf[256]; 14 struct sockaddr_in sin, cli; 15 int sd, ns, clientlen = sizeof(cli); 16 17 memset((char *)&sin, '\0', sizeof(sin)); 18 sin.sin_family = AF_INET; 19 sin.sin_port = htons(portnum); 20 sin.sin_addr.s_addr = inet_addr("192.168.162.133"); 21 22 if ((sd = socket(af_inet, SOCK_STREAM, 0)) == -1) { 23 perror("socket"); 24 exit(1); 25 } 26 27 if (bind(sd, (struct sockaddr *)&sin, sizeof(sin))) { 28 perror("bind"); 29 exit(1); 30 } 31 32 if (listen(sd, 5)) { 33 perror("listen"); 34 exit(1); 35 } 소켓생성 클라이언트접속대기 소켓주소구조체생성 5/23
[ 예제 12-1] (1) 반복서버 ( 서버 ) ex12_1s.c 37 while (1) { 38 if ((ns = accept(sd, (struct sockaddr *)&cli, &clientlen)) == -1) { 39 perror("accept"); 40 exit(1); 41 } 42 sprintf(buf, "%s", inet_ntoa(cli.sin_addr)); 43 printf("*** Send a Message to Client(%s)\n", buf); 44 45 strcpy(buf, "Welcome to Network Server!!!"); 46 if (send(ns, buf, strlen(buf) + 1, 0) == -1) { 47 perror("send"); 48 exit(1); 49 } 클라이언트에정보전송 50 51 if (recv(ns, buf, strlen(buf), 0) == -1) { 52 perror("recv"); 53 exit(1); 54 } 55 printf("** From Client : %s\n", buf); 56 close(ns); 57 } 58 close(sd); 59 60 return 0; 61 } 클라이언트접속 클라이언트의데이터수신 6/23
[ 예제 12-1] (2) 반복서버 ( 클라이언트 ) ex12_1c.c... 11 #define PORTNUM 9001 12 13 int main(void) { 14 int sd; 15 char buf[256]; 16 struct sockaddr_in sin; 17 18 memset((char *)&sin, '\0', sizeof(sin)); 19 sin.sin_family = AF_INET; 20 sin.sin_port = htons(portnum); 21 sin.sin_addr.s_addr = inet_addr("192.168.162.133"); 22 23 if ((sd = socket(af_inet, SOCK_STREAM, 0)) == -1) { 24 perror("socket"); 25 exit(1); 26 } 27 28 if (connect(sd, (struct sockaddr *)&sin, sizeof(sin))) { 29 perror("connect"); 30 exit(1); 31 } 소켓생성 서버에연결요청 소켓주소구조체생성 7/23
[ 예제 12-1] (2) 반복서버 ( 클라이언트 ) ex12_1c.c 33 if (recv(sd, buf, sizeof(buf), 0) == -1) { 34 perror("recv"); 35 exit(1); 서버의데이터수신 36 } 37 38 printf("** From Server : %s\n", buf); 39 40 strcpy(buf, "I want a HTTP Service."); 41 if (send(sd, buf, sizeof(buf) + 1, 0) == -1) { 42 perror("send"); 43 exit(1); 44 } 45 46 close(sd); 47 48 return 0; 49 } # ex12_1s.out 서버에데이터송신 # ex12_1c.out ** From Server : Welcome to Network Server!!! # ex12_1s.out *** Send a Message to Client(192.168.162.133) ** From Client : I want a HTTP Service. # ex12_1s.out *** Send a Message to Client(192.168.162.131) ** From Client : I want a FTP Service. 서버클라이언트서버클라이언트 8/23
[ 예제 12-2] (1) 동시동작서버 ( 서버 ) ex12_2s.c... 10 #define PORTNUM 9002 11 12 int main(void) { 13 char buf[256]; 14 struct sockaddr_in sin, cli; 15 int sd, ns, clientlen = sizeof(cli); 16 17 if ((sd = socket(af_inet, SOCK_STREAM, 0)) == -1) { 18 perror("socket"); 19 exit(1); 20 } 21 22 memset((char *)&sin, '\0', sizeof(sin)); 23 sin.sin_family = AF_INET; 24 sin.sin_port = htons(portnum); 25 sin.sin_addr.s_addr = inet_addr("192.168.162.133"); 26 27 if (bind(sd, (struct sockaddr *)&sin, sizeof(sin))) { 28 perror("bind"); 29 exit(1); 30 } 31 32 if (listen(sd, 5)) { 33 perror("listen"); 34 exit(1); 35 } 9/23
[ 예제 12-2] (1) 동시동작서버 ( 서버 ) ex12_2s.c 37 while (1) { 38 if ((ns = accept(sd, (struct sockaddr *)&cli, &clientlen)) == -1) { 39 perror("accept"); 40 exit(1); 41 } 42 switch (fork()) { 43 case 0: 44 close(sd); 45 strcpy(buf, "Welcome to Server"); fork 로자식프로세스생성 46 if (send(ns, buf, strlen(buf) + 1, 0) == -1) { 47 perror("send"); 48 exit(1); 49 } 50 51 if (recv(ns, buf, strlen(buf), 0) == -1) { 52 perror("recv"); 53 exit(1); 54 } 55 printf("** From Client: %s\n", buf); 56 sleep(5); 57 exit(0); 58 } 59 close(ns); 60 } 61 62 return 0; 63 } 자식프로세스가클라이언트로메시지보내고데이터수신 10/23
[ 예제 12-2] 실행결과 # ex12_2s.out *** Send a Message to Client(192.168.162.133) ** From Client : I want a HTTP Service. 클라이언트는 ex12_1c.c 를포트번호만바꾸고그대로사용 클라이언트가접속했을때서버의실행상태 # ps -ef grep pts/2 root 1571 1568 0 2월 08 pts/2 0:03 _ksh root 7175 7172 0 09:55:32 pts/2 0:00 ex12_2s.out root 7172 1571 0 09:55:18 pts/2 0:00 ex12_2s.out 서버프로세스가 2 개임을알수있다. 7172 는부모프로세스, 7175 는자식프로세스 11/23
[ 예제 12-3] (1) 동시동작서버 exec 함수사용하기 ( 서버 ) ex12_3s.c... 40 while (1) { 41 if ((ns = accept(sd, (struct sockaddr *)&cli, &clientlen)) == -1) { 42 perror("accept"); 43 exit(1); 44 } 45 printf("** Accept Client\n"); 46 47 switch (fork()) { 48 case 0: 49 printf("** Fork Client\n"); 50 close(sd); 51 dup2(ns, STDIN_FILENO); 클라이언트의요청처리를위한 52 dup2(ns, STDOUT_FILENO); 별도의프로그램 (han) 실행 53 close(ns); 54 execl("./han", "han", (char *)0); 55 } 56 close(ns); 57 } 58 59 return 0; 60 } 12/23
[ 예제 12-3] (2) 동시동작서버 han 프로그램 han.c 01 #include <unistd.h> 02 #include <stdio.h> 03 04 int main(void) { 05 printf("welcome to Server, from Han!"); 06 sleep(5); 07 간단한환영메시지출력 08 return 0; 09 } 13/23
[ 예제 12-3] (3) 동시동작서버 exec 함수사용 ( 클라이언트 ) ex12_3c.c... 28 printf("==> Create Socket\n"); 29 if (connect(sd, (struct sockaddr *)&sin, sizeof(sin))) { 30 perror("connect"); 31 exit(1); 32 } 33 34 printf("==> Connect Server\n"); 35 if ((len = recv(sd, buf, sizeof(buf), 0)) == -1) { 36 perror("recv"); 37 exit(1); 메시지수신 38 } 39 buf[len] = '\0'; 40 41 printf("==> From Server : %s\n", buf); 42 43 close(sd); 44 45 return 0; 46 } 연결요청 # ex12_3c.out 클라이언트 ==> Create Socket ==> Connect Server ==> From Server : Welcome to Server, from Han! # ps PID TTY TIME CMD 676 pts/2 0:00 ksh 760 pts/2 0:00 ex12_3s.out 763 pts/2 0:00 han han 실행 14/23
[ 예제 12-4] (1) 명령행인자로소켓기술자전달하기 ( 서버 ) ex12_4s.c... 40 while (1) { 41 if ((ns = accept(sd, (struct sockaddr *)&cli, &clientlen)) == -1) { 42 perror("accept"); 43 exit(1); 44 } 45 printf("** Accept Client\n"); 46 47 switch (fork()) { 48 case 0: 49 printf("** Fork Client\n"); 50 close(sd); 51 sprintf(buf, "%d", ns); 클라이언트접속수용 bit 프로그램실행명령행인자로소켓전달 52 execlp("./bit", "bit", buf, (char *)0); 53 close(ns); 54 } 55 close(ns); 56 } 57 58 return 0; 59 } 15/23
[ 예제 12-4] (2) 명령행인자로소켓기술자전달하기 (bit) bit.c... 08 int main(int argc, char *argv[]) { 09 char buf[256]; 10 int len, ns; 11 12 ns = atoi(argv[1]); 13 14 strcpy(buf, "Welcome to Server, from Bit"); 15 if ((send(ns, buf, strlen(buf) + 1, 0)) == -1) { 16 perror("send"); 17 exit(1); 18 } 19 명령행인자로받은소켓을숫자로변환 클라이언트에메시지전달 20 if ((len=recv(ns, buf, strlen(buf), 0)) == -1) { 21 perror("recv"); 22 exit(1); 23 } 클라이언트의응답받기 24 printf("@@ [Bit] From Client: %s\n", buf); 25 close(ns); 26 27 return 0; 28 } 16/23
[ 예제 12-4] (3) 명령행인자로소켓기술자전달 ( 클라이언트 ) ex12_4c.c... 34 printf("==> Connect Server\n"); 35 if ((len = recv(sd, buf, sizeof(buf), 0)) == -1) { 36 perror("recv"); 37 exit(1); 서버의메시지수신 38 } 39 buf[len] = '\0'; 40 41 printf("==> From Server : %s\n", buf); 42 43 strcpy(buf, "I want a TELNET Service."); 44 if (send(sd, buf, sizeof(buf) + 1, 0) == -1) { 45 perror("send"); 46 exit(1); 47 } 48 49 close(sd); 50 51 return 0; 52 } 서버에메시지전송 17/23
[ 예제 12-4] 실행결과 # ex12_4s.out ** Create Socket ** Bind Socket ** Listen Socket ** Accept Client ** Fork Client @@ [Bit] From Client: I want a TELNET Service. 서버 # ex12_4c.out ==> Create Socket ==> Connect Server ==> From Server : Welcome to Server, from Bit 클라이언트 18/23
[ 예제 12-5] (1) UDP 프로그래밍 ( 서버 ) ex12_5s.c... 09 #define PORTNUM 9005 10 11 int main(void) { 12 char buf[256]; 13 struct sockaddr_in sin, cli; 14 int sd, clientlen = sizeof(cli); 15 16 if ((sd = socket(af_inet, SOCK_DGRAM, 0)) == -1) { 17 perror("socket"); 18 exit(1); 19 } 20 21 memset((char *)&sin, '\0', sizeof(sin)); 22 sin.sin_family = AF_INET; 23 sin.sin_port = htons(portnum); 24 sin.sin_addr.s_addr = inet_addr("192.168.162.133"); 25 26 if (bind(sd, (struct sockaddr *)&sin, sizeof(sin))) { 27 perror("bind"); 28 exit(1); 29 } 포트번호 소켓생성 ( 데이터그램 ) 소켓기술자와소켓주소구조체연결 소켓주소구조체생성 19/23
[ 예제 12-5] (1) UDP 프로그래밍 ( 서버 ) ex12_5s.c 31 while (1) { 32 if ((recvfrom(sd, buf, 255, 0, 33 (struct sockaddr *)&cli, &clientlen)) == -1) { 34 perror("recvfrom"); 35 exit(1); 36 } 37 printf("** From Client : %s\n", buf); 38 strcpy(buf, "Hello Client"); 39 if ((sendto(sd, buf, strlen(buf)+1, 0, 40 (struct sockaddr *)&cli, sizeof(cli))) == -1) { 41 perror("sendto"); 42 exit(1); 43 } 44 } 45 46 return 0; 47 } 클라이언트의메시지수신 클라이언트로데이터보내기 20/23
[ 예제 12-5] (2) UDP 프로그래밍 ( 클라이언트 ) ex12_5c.c... 09 #define PORTNUM 9005 포트번호 10 11 int main(void) { 12 int sd, n; 13 char buf[256]; 14 struct sockaddr_in sin; 15 16 if ((sd = socket(af_inet, SOCK_DGRAM, 0)) == -1) { 17 perror("socket"); 18 exit(1); 소켓생성 19 } 20 21 memset((char *)&sin, '\0', sizeof(sin)); 22 sin.sin_family = AF_INET; 23 sin.sin_port = htons(portnum); 24 sin.sin_addr.s_addr = inet_addr("192.168.162.133"); 25 26 strcpy(buf, "I am a client."); 27 if (sendto(sd, buf, strlen(buf)+1, 0, 28 (struct sockaddr *)&sin, sizeof(sin)) == -1) { 29 perror("sendto"); 30 exit(1); 31 } 서버에메시지전송 소켓주소구조체생성 21/23
[ 예제 12-5] (2) UDP 프로그래밍 ( 클라이언트 ) ex12_5c.c 33 n = recvfrom(sd, buf, 255, 0, NULL, NULL); 34 buf[n] = '\0'; 35 printf("** From Server : %s\n", buf); 서버가보낸데이터읽기 36 37 return 0; 38 } # ex12_5s.out ** From Client : I am a client. 서버 # ex12_5c.out ** From Server : Hello Client 클라이언트 22/23
IT CookBook, 유닉스시스템프로그래밍