소켓시스템콜소개 TCP 클라이언트 / 서버프로그래밍 signal(), fork() 시스템콜 TCP 클라이언트 / 서버프로그래밍예 talk_client.c, talk_server.c UDP 클라이언트 / 서버프로그래밍 순천향대학교컴퓨터학부이상정 1 소켓시스템콜소개 순천향대학교컴퓨터학부이상정 2
소켓 (socket) 소켓은 TCP/IP 프로토콜을이용하기위한시스템콜인터페이스 1982 년 BSD(Berkeley Software Distribution) 유닉스 4.1 에서처음소개 응용프로그램은소켓을통하여통신망으로 IP 패킷을송수신 소켓을개설하면파일기술자와똑같은기능을하는소켓기술자 ( 소켓번호 ) 가리턴 순천향대학교컴퓨터학부이상정 3 소켓인터페이스 순천향대학교컴퓨터학부이상정 4
인터넷소켓의종류 스트림소켓 SOCK_STREAM 연결형 (Connection-Oriented) 소켓 실제통신하는호스트들간의신뢰성있는연결보장 TCP (Transmission Control Protocol) 사용 데이터그램소켓 SOCK_DGRAM 비연결형 (Connectionless) 소켓 신뢰성보장못함 UDP (User Datagram Protocol) 사용 순천향대학교컴퓨터학부이상정 5 소켓번호 소켓을열면소켓기술자 (Socket Descriptor) 가리턴됨 응용프로그램에서호스트와연결을요구하는패킷을송수신할때해당소켓기술자를사용. 소켓기술자를소켓번호라고부름 파일과소켓을기술자테이블을공유 순천향대학교컴퓨터학부이상정 6
소켓과응용프로그램 소켓번호는응용프로그램내에서순서대로배정 해당프로그램내에서만유일하게구분 포트번호는 TCP/IP,UDP가지원하는상위계층프로세서구분번호 하나의컴퓨터에서동작하는여러응용프로그램은반드시서로다른포트번호사용해야함. 순천향대학교컴퓨터학부이상정 7 소켓의이용 (1) IP 패킷을주고받기위해결정되어야할다섯가지 통신에사용할프로토콜 (TCP/IP,UDP) 자신의 IP 주소, 자신의포트번호 상대방의 IP 주소, 상대방의포트번호 잘알려진포트번호들 ftp : 21 번 telnet : 23 번 mail : 25 번 http : 80 번 순천향대학교컴퓨터학부이상정 8
소켓의이용 (2) 소켓만들기 서버와클라이언트모두필요 socket() 시스템콜호출 성공시정수형의소켓번호리턴 #include <sys/types.h> #include <sys/socket.h> int socket ( int domain, int type, int protocol ) /* domain : 프로토콜체계 */ /* type : 서비스타입 */ /* protocol : 소켓에사용될프로토콜 */ TCP/IP 의경우 Domain : AF_INET Type: SOCK_STREAM Protocol: 0( 시스템자동설정 ) 순천향대학교컴퓨터학부이상정 9 open_socket.c 예 (1) socket() 시스템콜을이용 두개의소켓을만든후소켓번호를출력 두개의파일을열어서각파일의파일기술자를출력 프로그램리스트 파일명 : open_socket.c 기능 : socket() 시스템콜을호출하고, 생성된소켓번호를출력 컴파일 : cc -o open_socket open_socket.c $./open_socket /etc/passwd's file descriptor = 3 stream socket descriptor = 4 datagram socket descriptor = 5 /etc/hosts's file descriptor = 6 순천향대학교컴퓨터학부이상정 10
open_socket.c 예 (2) #include <stdio.h> /* 표준입출력함수 */ #include <sys/types.h> /* 소켓시스템콜에필요한상수선언 */ #include <sys/stat.h> /* 파일의상태에대한데이터선언 */ #include <sys/socket.h> /* 소켓시스템콜선언 */ #include <fcntl.h> /* open 에필요한 flag 선언 */ main() { int fd1, fd2, sd1, sd2; /* 파일및소켓번호 */ fd1 = open("/etc/passwd", O_RDONLY, 0); /* 파일열기 */ printf("/etc/passwd's file descriptor = %d n", fd1); sd1 = socket(af_inet, SOCK_STREAM, 0); /* 스트림형소켓열기 */ printf("stream socket descriptor = %d n", sd1); sd2 = socket(af_inet, SOCK_DGRAM, 0); /* 데이터그램형소켓열기 */ printf("datagram socket descriptor = %d n", sd2); fd2 = open("/etc/hosts", O_RDONLY, 0); /* 또다른파일열기 */ printf("/etc/hosts's file descriptor = %d n", fd2); /* 파일및소켓닫기 */ close(fd2); close(fd1); close(sd2); close(sd1); 순천향대학교컴퓨터학부이상정 11 소켓주소구조체 (1) 소켓주소 (Socket Address) 주소체계 (Address family) IP 주소 포트번호 소켓주소구조체, sockaddr struct sockaddr { u_short sa_family; /* address family */ char sa_data[14]; /* 주소 */ 순천향대학교컴퓨터학부이상정 12
소켓주소구조체 (2) sockaddr_in 구조체 sockaddr 구조체가불편 4바이트의 IP 주소, 2 바이트의포트번호구분지정 in_addr 32비트의 IP 주소저장구조체 struct in_addr { u_long s_addr; /* 32 비트의 IP 주소를저장할구조체 */ struct sockaddr_in { short sin_family; /* address family */ u_short sin_port; /* 16 비트포트번호 */ struct in_addr sin_addr; /* 32 비트 IP 주소 */ char sin_zero[8]; /* 16 바이트크기를맞추기위한 dummy bits */ sin_family AF_INET( 인터넷주소체계 ), AF_UNIX( 유닉스파일주소체계 ), AF_NS( 제록스주소체계 ) 중 AF_INET 사용 순천향대학교컴퓨터학부이상정 13 절차 (1) 클라이언트 / 서버모델 대표적인네트워크프로그래밍모델 서버 socket() 을호출하여소켓을하나개설 개설된소켓번호와자신의소켓주소를 bind() 시스템콜을통하여연결 bind() 는소켓을특정포트에연결시켜주는역할 #include <sys/types.h> #include <sys/socket.h> int bind ( int sockfd, struct sockaddr*myaddr, int addrlen ) /* sockfd : socket() 으로얻은소켓번호 */ /* *myaddr : IP 주소와포트번호를담고있는 struct sockaddr 에대한포인터 */ /* addrlen : sockaddr 구조체의크기 = sizeof(struct sockaddr) 순천향대학교컴퓨터학부이상정 14
절차 (2) 서버 listen() 시스템콜호출하여연결요청대기모드 연결요청이오면 accept() 시스템콜호출 #include <sys/types.h> #include <sys/socket.h> listen( int sockfd, int backlog ) /* sockfd : socket() 으로얻은소켓번호 */ /* backlog : 해당서버에접속할수있는최대연결개수 */ 클라이언트 socket() 을이용소켓을하나개설 connect() 를수행 bind() 는수행하지않음. 클라이언트는자신의 IP나포트번호를알릴필요가없기때문 순천향대학교컴퓨터학부이상정 15 절차 (3) #include <sys/socket.h> accept( int sockfd, void *addr, int *addrlen ) /* sockfd : socket() 으로얻은소켓번호 */ /* *addr : 로컬 struct sockaddr_in의포인터 */ /* *addrlen : sockaddr_in 구조체의크기 = sizeof(struct sockaddr_in) #include <sys/types.h> #include <sys/socket.h> connect( int sockfd, struct sockaddr *serv_addr, int addrlen ) /* sockfd : socket() 으로얻은소켓번호 */ /* *serv_addr : 연결목적지의정보를담고있는 struct sockaddr 구조체포인터 */ /* addrlen : sockaddr 구조체의크기 = sizeof(struct sockaddr) 순천향대학교컴퓨터학부이상정 16
절차도 연결형 (TCP) 비연결형 (UDP) 순천향대학교컴퓨터학부이상정 17 데이터송 / 수신시스템콜 (1) SOCK_STREAM TCP 통신채널이확립되면데이터송 / 수신수행 순천향대학교컴퓨터학부이상정 18
데이터송 / 수신시스템콜 (2) SOCK_DGRAM UDP 통신채널송수신 소켓번호를얻고 bind() 수행하면연결확립없이언제든지송 / 수신가능 순천향대학교컴퓨터학부이상정 19 인터넷주소변환 (1) 각컴퓨터마다데이터를내부에서표현하는방식이다름 데이터전송이전과수신이후바이트순서를맞추는절차필요 인터넷주소표현방식 도메인네임 (Domain Name) 32비트의 IP 주소 십진수표시법 (Dotted Decimal) 순천향대학교컴퓨터학부이상정 20
인터넷주소변환 (2) 바이트순서 (Byte Ordering) 호스트바이트순서 컴퓨터가내부메모리에데이터를저장하는순서 CPU( 중앙처리장치 ) 에따라다름 X86 계열의 CPU가사용하는호스트바이트순서는하위바이트부터메모리에저장 (little endian) MC68000 계열의 CPU에서는상위바이트부터메모리저장 (big endian) 0xC3E2( 십진수 50146) 의호스트바이트순서비교 순천향대학교컴퓨터학부이상정 21 인터넷주소변환 (3) 바이트순서 (Byte Ordering) 네트워크에서바이트단위로데이터가전달되는순서로 big endian 과일치 Little endian인 x86 CPU의호스트바이트순서와네트워크바이트순서는다름 htons() 나 ntohs() 함수를이용해 CPU에맞는호스트바이트순서로변환 unsigned short integer 의변환 (2 바이트체계 ) htons() : host-to-network short 바이트변환 ntohs() : network-to-host short 바이트변환 unsigned long integer 의변환 (4 바이트체계 ) htonl() : host-to-network long 바이트변환 ntohl() : network-to-host long 바이트변환 순천향대학교컴퓨터학부이상정 22
IP 주소변환 (1) 32 비트의 IP 주소는도메임네임또는십진수표시법으로변환하여사용가능 표현방법에따른상호변환함수 순천향대학교컴퓨터학부이상정 23 IP 주소변환 (2) #include <arpa/inet.h> char *inet_ntoa(struct in_addr addr); /* IP 주소 -> dotted decimal */ in_addr inet_addr(const char *host); /* dotted decimal -> IP 주소 */ 순천향대학교컴퓨터학부이상정 24
ascii_ip.c 예 (1) dotted decimal 로표현된주소 ( 예 : 192.203.144.11) 를명령문인자로입력 inet_addr() 을이용하여 4 바이트의 IP 주소 (hexa 로는 c0cb900b 임 ) 로바꾸어화면에출력 이 IP 주소를인자로하여 inet_ntoa() 를호출하여다시 dotted decimal 주소를출력 파일명 : ascii_ip.c 기능 : ASCII (dotted decimal) 로표현된주소를 4바이트 IP 주소로변환 컴파일 : cc -o ascii_ip ascii_ip.c 실행 $./ascii_ip 192.203.144.11 IP Address (hexa) 0xb90cbc0, 192.203.144.11 순천향대학교컴퓨터학부이상정 25 ascii_ip.c 예 (2) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> main(int argc, char *argv[]) { char *haddr; struct in_addr host_ip; /* 32 비트 IP 주소구조체 */ if (argc < 2) { printf(" 사용법 : %s IP 주소 (dotted decimal) n ", argv[0]); exit(0); 순천향대학교컴퓨터학부이상정 26
ascii_ip.c (3) haddr = argv[1]; /* dotted decimal 주소 */ host_ip.s_addr = inet_addr(haddr); /* IP 주소 (hexa 4 바이트 ) 출력 */ printf("ip Address (hexa) 0x%x, ", host_ip.s_addr); /* dotted decimal 로다시변환하여출력 */ printf("%s n", inet_ntoa(host_ip)); 위에서사용한주소변환함수들은단순히계산만하는함수이므로이러한함수는즉시처리가가능하다그러나도메인네임으로부터 IP 주소를얻거나 IP 주소로부터해당호스트의도메인네임을얻으려면 DNS 서버의도움을받아야하며이러한함수는처리가즉시이루어지지않을수도있다. 순천향대학교컴퓨터학부이상정 27 기타주소변환함수 gethostname() 현재사용중인컴퓨터의도메인네임을알아오는함수 #define HOST_NAME_LEN 50 /* 도메인네임의최대길이 */ char domain[host_name_len+1]; /* 도메인네임을저장할버퍼 */ gethostname ( domain, HOST_NAME_LEN); sethostname() 현재사용중인컴퓨터의도메인네임을변경하는함수 sethostname ( new.sch.ac.kr, strlen( new.sch.ac.kr )); 순천향대학교컴퓨터학부이상정 28
TCP 클라이언트 / 서버프로그래밍 순천향대학교컴퓨터학부이상정 29 TCP 클라이언트 / 서버프로그램 TCP 로연결된클라이언트 / 서버프로그램소개 순천향대학교컴퓨터학부이상정 30
TCP 클라이언트프로그램작성절차 순천향대학교컴퓨터학부이상정 31 socket(), 소켓개설 socket(af_inet, SOCK_STREAM, 0) 순천향대학교컴퓨터학부이상정 32
connect(), 서버에연결요구 클라이언트는 connect() 를호출하기전에연결하고자하는서버의주소를지정 4 바이트의 IP 주소와 2 바이트의포트번호를포함하는소켓주소구조체 sockaddr_in 를작성 int connect ( int s, /* 서버와연결시킬소켓번호 */ const struct sockaddr *addr, /* 상대방서버의소켓주소구조체 */ int addrlen /* 구조체 *addr 의크기 */ ); 클라이언트는 bind() 를사용하여자신이사용할포트번호를명시적으로지정할필요가없으며, 연결형클라이언트에서는 connect() 를호출할때에 TCP 가임의의포트번호를지정해준다. 순천향대학교컴퓨터학부이상정 33 connect(), 서버에연결요구 순천향대학교컴퓨터학부이상정 34
메시지송수신 클라이언트와서버가연결되면 send(), recv(), write(), read() 를사용하여서버와메시지를송수신 순천향대학교컴퓨터학부이상정 35 close(), 소켓닫기 close() 는클라이언트나서버중누구나먼저호출할수있다. close() 를호출하기전에 shutdown() 시스템콜을아래와같이사용할수있다. direction 이 1 이면패킷의전송을종료하고 0 이면수신을종료하며 2 이면송수신을모두종료한다. shutdown(s, direction); S: 소켓번호 순천향대학교컴퓨터학부이상정 36
TCP 서버프로그램작성절차 순천향대학교컴퓨터학부이상정 37 소켓의생성및연결 socket(), 소켓의생성 서버도클라이언트와통신을하기위해서는트랜스포트프로토콜을지정하여 socket() 으로소켓을만들어야한다. socket(pf_inet, SOCK_DTREAM, 0) bind(), 소켓번호와소켓주소구조체연결 소켓번호와클라이언트가알고있는서버의소켓주소 (IP 주소 + 포트번호 ) 를연결 임의의클라이언트가서버의특정소켓과연결되기위해서서버는반드시 bind() 를호출 순천향대학교컴퓨터학부이상정 38
bind() 함수 (1) 순천향대학교컴퓨터학부이상정 39 bind() 함수 (2) int bind( int s,/* 소켓번호 */ struct sockaddr *addr,/* 서버자신의소켓주소구조체포인터 */ intlen); /* *addr 구조체의크기 */ bind() 사용예 #define SERV_IP_ADDR "203.252.65.3" #define SERV_PORT 3000 /* 소켓생성 */ s = socket(pf_inet, SOCK_STREAM, 0); struct sockaddr_in server_addr; /* 소켓주소구조체내용 */ server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(serv_ip_addr); server_addr.sin_port = htons(serv_port); /* 소켓번호와소켓주소를 bind */ bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr)); 순천향대학교컴퓨터학부이상정 40
bind() 함수 (3) 사용중인컴퓨터의 IP 주소를자동으로가져다쓰려면 INADDR_ANY 라는변수를사용 server_addr.sin_addr.s_addr = htonl(inaddr_any); INADDR_ANY에서 ANY의의미는서버가두개이상의 IP 주소를가지고있을때 ( 즉, multihomed host), 임의의서버 IP 주소를목적지로하여들어오는패킷을모두받아들이겠다는것을나타낸다. 순천향대학교컴퓨터학부이상정 41 listen(), 연결요청을기다리기 listen(), 클라이언트로부터의연결요청을기다리기 서버는클라이언트로부터의연결요청을받아들이기위하여 listen() 을호출 int listen ( int s,/* 소켓번호 */ int log/* 연결을기다리는클라이언트의최대수 */ ); 순천향대학교컴퓨터학부이상정 42
accept(), 연결요청수락 accept(), 클라이언트로부터의연결요청수락 클라이언트에서 connect() 로연결요청을보내면이를처리하기위해서서버는 accept() 를호출해두어야한다. accept() 의수행이성공하면접속된클라이언트와의통신에사용할새로운소켓이만들어지고이소켓번호가리턴되며, 실패시에는 -1이리턴된다. 서버는이클라이언트와통신하기위하여 accept() 가리턴한소켓번호를사용하여야한다. accept() 는또한연결된클라이언트의소켓주소구조체와구조체의길이의포인터를함수인자로리턴해준다. int accept ( int s,/* 소켓번호 */ struct sockaddr *addr,/* 연결요청을한클라이언트의소켓주소구조체 */ int *addrlen /* *addr 구조체크기의포인터 */ ); 순천향대학교컴퓨터학부이상정 43 accept(), 연결요청수락 순천향대학교컴퓨터학부이상정 44
signal(), fork() 시스템콜 순천향대학교컴퓨터학부이상정 45 소켓관련 UNIX 시스템콜 소켓프로그램작성시많이사용되는유닉스시스템콜을소개 signal() fork() 순천향대학교컴퓨터학부이상정 46
signal() 시스템콜 (1) 리눅스시스템에서어떤이벤트 (event) 가발생하면이것을프로세스사이에알리는수단으로시그널이사용된다. 순천향대학교컴퓨터학부이상정 47 signal() 시스템콜 (2) 시그널이발생하였을때리눅스커널이제공하는디폴트처리내용대 신다른동작을수행하도록하려면 signal() 시스템콜을사용 signal(sigio, sigio_func) 호출 후 SIGIO 시그널이 발생하면 sigio_func() 함수가수행 #include <signal.h> int sigio_func(); /* 사용자정의함수선언 */ main() { signal(sigio, sigio_func); /* 시그널처리함수지정 */ : int sigio_func() { /* SIGIO 시그널발생시처리내용 */ 순천향대학교컴퓨터학부이상정 48
signal() 시스템콜 (3) 어떤시그널이발생하였을때이를단순히무시하려면다음과같이무시할시그널의종류 ( 예를들면 SIGIO) 를지정하고옵션으로시그널무시 (SIG_IGN) 를선택한다. signal(sigio, SIG_IGN); 순천향대학교컴퓨터학부이상정 49 signal_test.c 예 (1) 카운터프로그램이실행되는도중에사용자가 Ctrl-C 를입력하면시그널 SIGINT 가발생하는데, 이때프로그램이종료되는것이아니라 my_signal() 이라는함수가호출된다. 실행예 $./signal_test 0 1 ^C Ctrl-C pressed. 2 3 ^C Ctrl-C pressed. 4 ^C Ctrl-C pressed. 순천향대학교컴퓨터학부이상정 50
signal_test.c 예 (2) 파일명 : signal_test.c 기능 : signal() 시스템콜사용예 컴파일 : cc -o signal_test signal_test.c #include <sys/types.h> #include <signal.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> int my_signal(); /* 새로운시그널처리함수선언 */ int count = 0; /* Ctrl-C 입력횟수카운터 */ 순천향대학교컴퓨터학부이상정 51 signal_test.c 예 (3) int main() { int i = 0; if (signal(sigint, my_signal) == SIG_ERR) { printf("singal() error"); exit(0); while(count < 3) { sleep(1);/* 1 초간기다림 */ printf("%d n", i++); /* 시그널처리함수정의 */ int my_signal() { printf(" nctrl-c pressed. n"); count++; signal(sigint, my_signal); return 0; 순천향대학교컴퓨터학부이상정 52
fork() 시스템콜 (1) 유닉스에서프로세스는 fork() 를이용해서자신과똑같은기능을수행하는프로세스를하나복제할수있다. 두프로세스는프로그램코드, 스택, 파일기술자, 소켓번호등은공유하나, 변수들은공유하지않는다. fork() 가불리면그순간에하나의프로세스가두개의프로세스로되는데, 두프로세스는수행할일을구분하기위하여두프로세스의 fork() 리턴문이서로다르다는것을이용 부모프로세스에게는 fork() 의리턴값으로새로만들어진자식프로세스의 PID 가리턴 자식프로세스의 fork() 의리턴값으로 0 이반환 -1 이반환되면자식프로세스가생성되지않은경우 순천향대학교컴퓨터학부이상정 53 fork() 시스템콜 (2) 순천향대학교컴퓨터학부이상정 54
fork() 시스템콜 (3) int PID; PID = fork(); if(pid == 0) child_work(); /* 자식프로세스용코드 */ else parent_work();/* 부모프로세스용코드 */ 순천향대학교컴퓨터학부이상정 55 fork_test.c 예 (1) 부모와자식프로세스가같은이름의변수를각각증가시키고자식프로세스와부모프로세스가변수를공유하지않음을확인한다. 파일명 : fork_test.c 기능 : fork() 시스템콜사용예 컴파일 : cc -o fork_test fork_test.c $./fork_test CHILD - my pid is 19447 and parent's pid is 19446 global var : 1 local var : 1 PARENT - my pid is 19446, child's pid is 19447 global var : 5 local var : 5 순천향대학교컴퓨터학부이상정 56
fork_test.c 예 (2) #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int global_var = 0; /* 전역변수선언 */ int main(void) { pid_t pid; int local_var = 0;/* 지역변수선언 */ if ((pid = fork()) < 0) { printf("fork error n"); exit(0); /* 자식프로세스 */ else if (pid == 0) { global_var++; local_var++; printf("child - my pid is %d and parent's pid is %d n", getpid(), getppid()); 순천향대학교컴퓨터학부이상정 57 fork_test.c 예 (3) else { /* 부모프로세스 */ sleep(2);/* 2초쉰다 */ global_var += 5; local_var += 5; printf("parent - my pid is %d, child's pid is %d n", getpid(), pid); printf("global var : %d n", global_var); printf("local var : %d n", local_var); 순천향대학교컴퓨터학부이상정 58
TCP 클라이언트 / 서버프로그래밍예 talk_client.c, talk_server.c 순천향대학교컴퓨터학부이상정 59 토크클라이언트 / 서버프로그램 토크서버 (talk_server.c) 와클라이언트 (talk_client.c) 가 1:1 통신을하는프로그램 < 서버측 > $ talk_server 3000 Server started. Waiting for client.. R: Hello, Server! Hi, Client R: This is the test messages. I got your messages. R: Ok, bye exit Good bye. < 클라이언트측 > $ talk_client 192.168.13.130 3000 Hello, Server! R: Hi, Client This is the test messages. R: I got your messages. Ok, bye exit Good bye. 순천향대학교컴퓨터학부이상정 60
토크클라이언트프로그램, talk_client 사용자의키보드입력처리그리고서버와의통신두가지일을동시에수행하기위해 fork() 시스템콜을사용하여두개의프로세스를생성 부모프로세스는사용자가입력한메시지를읽어서버로전송 자식프로세스는서버가전송한메시지를소켓에서읽어화면에출력 파일명 : talk_client.c 기능 : 토크서버와 1:1 통신을하는클라이언트프로그램 컴파일 : cc -o talk_client talk_client.c 사용법 : talk_client 192.168.13.130 3000 순천향대학교컴퓨터학부이상정 61 talk_client.c 예 (1) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <signal.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 1024 char *escapechar = "exit";/* 종료문자정의 */ int main(int argc, char *argv[]) { char line[maxline], sendline[maxline], recvline[maxline+1]; int n, size, comp; pid_t pid; static int s; static struct sockaddr_in server_addr; /* 명령문입력인자처리 */ if (argc!= 3) { printf(" 사용법 : %s server_ip port n", argv[0]); exit(0); 순천향대학교컴퓨터학부이상정 62
talk_client.c 예 (2) /* 소켓생성 */ if ((s = socket(af_inet, SOCK_STREAM, 0)) < 0) { printf("client: Can't open stream socket. n"); exit(0); /* server_addr 을 '0' 으로초기화 */ bzero((char *)&server_addr, sizeof(server_addr)); /* server_addr 세팅 */ server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(argv[1]); server_addr.sin_port = htons(atoi (argv[2])); /* 서버에연결요청 */ if (connect(s,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) { printf("client: can't connect to server. n"); exit(0); 순천향대학교컴퓨터학부이상정 63 talk_client.c 예 (3) if (( pid = fork()) > 0) { /* 부모프로세스는키보드입력을서버로전송 */ while (fgets(sendline, MAXLINE, stdin)!= NULL) { size = strlen(sendline); if (write(s, sendline, strlen(sendline))!= size) printf("error in write n"); /* 종료문자열입력처리 */ if (strstr(sendline, escapechar)!= NULL ) { printf("good bye. n"); close(s); exit(0); /* while */ /* if */ 순천향대학교컴퓨터학부이상정 64
talk_client.c 예 (4) else if (pid == 0) { /* 자식프로세스는소켓으로부터들어오는메시지를화면에출력 */ while (1) { if ((size = read(s, recvline, MAXLINE)) < 0) { printf("error if read"); close(s); exit(0); recvline[size] = ' 0'; /* 종료문자열수신시종료 */ if (strstr(recvline, escapechar)!= NULL ) break; /* 화면출력 */ printf("r: %s", recvline); /* while */ /* else if */ close(s); 순천향대학교컴퓨터학부이상정 65 토크서버프로그램 서버에서도사용자키보드입력과메시지송수신두가지기능을동시에수행하기위해 fork() 시스템콜을이용 파일명 : talk_server.c 기능 : 토크클라이언트와 1:1 통신을한다. 컴파일 : cc -o talk_server talk_server.c 사용법 : talk_server 3000 순천향대학교컴퓨터학부이상정 66
talk_server.c 예 (1) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <signal.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 512 char *escapechar = "exit";/* 종료문자 */ int main(int argc, char *argv[]) { int server_fd, client_fd;/* 소켓번호 */ int clilen, num; char sendline[maxline], recvline[maxline]; int size; pid_t pid; struct sockaddr_in client_addr, server_addr; if (argc!= 2) { printf(" 사용법 : %s port n", argv[0]); exit(0); 순천향대학교컴퓨터학부이상정 67 talk_server.c 예 (2) /* 소켓생성 */ if ((server_fd=socket(af_inet, SOCK_STREAM, 0)) < 0) { printf("server: Can't open stream socket n"); exit(0); /* 서버의소켓주소구조체 server_addr 을 '0' 으로초기화 */ bzero((char *)&server_addr, sizeof(server_addr)); /* server_addr 을세팅 */ server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(inaddr_any); server_addr.sin_port = htons(atoi( argv[1])); /* bind() 호출 */ if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { printf("server: Can't bind local address n"); exit(0); 순천향대학교컴퓨터학부이상정 68
talk_server.c 예 (3) printf("server started. nwaiting for client.. n"); listen(server_fd, 1); /* 클라이언트연결요청수락 */ clilen = sizeof(client_addr); if ((client_fd = accept(server_fd,(struct sockaddr *)&client_addr, &clilen)) < 0) { printf("server: failed in accepting."); exit(0); if (( pid = fork()) > 0) { /* 부모프로세스는키보드입력을클라이언트로전송 */ while (fgets(sendline, MAXLINE, stdin)!= NULL) { size = strlen(sendline); if (write(client_fd, sendline, strlen(sendline))!= size) printf("error in write n" ); /* 종료문자열입력처리 */ if (strstr(sendline, escapechar)!= NULL ) { printf("good bye. n"); close(client_fd); exit(0); /* while */ /* if */ 순천향대학교컴퓨터학부이상정 69 talk_server.c 예 (4) else if (pid == 0) { /* 자식프로세스는소켓으로부터들어오는메시지를화면에출력 */ while(1) { if((size = read(client_fd, recvline, MAXLINE)) < 0) { printf("error if read n"); close(client_fd); exit(0); recvline[size] = 0'; /* 종료문자열수신시종료 */ if (strstr(recvline, escapechar)!= NULL ) break; /* 화면출력 */ printf("r: %s", recvline); /* while */ /* else if */ close(server_fd); close(client_fd); 순천향대학교컴퓨터학부이상정 70
UDP 클라이언트 / 서버프로그래밍 순천향대학교컴퓨터학부이상정 71 UDP 클라이언트프로그램작성절차 순천향대학교컴퓨터학부이상정 72
UDP 클라이언트프로그램 비연결형 (UDP) 통신에서사용할소켓을개설할때에는프로토콜로 SOCK_DGRAM 을지정 비연결형소켓은특정호스트와의통신에만사용되는것이아니며이소켓을이용하여임의의호스트로 IP 패킷을보낼수있다. 비연결형서비스이므로연결설정을위한 connect() 시스템콜을사용할필요가없고소켓개설후바로서버와메시지를송수신할수있다. 비연결형소켓을통하여메시지를송수신할때에는각패킷마다목적지의 IP 주소와포트번호 ( 즉소켓주소 ) 를항상함수인자로주어야한다. 순천향대학교컴퓨터학부이상정 73 메시지송수신 순천향대학교컴퓨터학부이상정 74