13 장소켓을이용한통신 (2) 소켓을이용한통신 (2) 함수 - recvfrom - sendto - uname - gethostname - gethostbyname - gethostbyaddr 1
1. 서론 소켓을사용하여비연결형모델로통신을하기위한함수와그외의함수 함수 의미 recvfrom 비연결형모델에서소켓을통해메시지를수신한다. sendto 비연결형모델에서소켓을통해메시지를송신한다. uname 호스트의이름을포함한시스템의정보를알아온다. gethostname 호스트의이름을알아온다. gethostbyname 이름으로지정한호스트의네트워크정보를알아온다. gethostbyaddr 인터넷주소로지정한호스트의네트워크정보를알아온다. 2
TCP 를사용한비연결형통신모델에서의함수호출 3
TCP 를사용한연결형통신모델에서의함수호출 4
2. recvfrom 비연결형통신모델에서소켓을통해메시지를수신한다. #include <sys/types.h> #include <sys/socket.h> int recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); sockfd 소켓기술자이다. buf 수신한메시지를저장할버퍼이다. len buf 의크기이다. flags recvfrom 의동작방식을결정한다. recv 와동일하다. from 메시지를송신하는쪽의정보가저장된다. fromlen from 의크기이다. 반환값 호출이성공하면수신한메시지의바이트수를반환하고, 실패하면 -1 을반환한다. 5
2. recvfrom recvfrom 함수 보통비연결형통신모델에서메시지를수신하기위해사용 연결형통신모델에서도사용할수있다. (from 인자를 NULL 로 ) int sockfd 소켓기술자를의미한다. 보통 recvfrom 이비연결형통신모델에서사용되므로소켓이 상대프로세스의소켓과연결되어있지는않다. void *buf, size_t len 수신한메시지를저장하기위한버퍼와버퍼의크기이다. int flags recvfrom 의동작방식을지정하는데보통 0 을준다. 6
2. recvfrom int flags 함수 send recv 심볼형상수 MSG_OOB MSG_DONTROUTE MSG_NOSIGNAL MSG_OOB MSG_PEEK MSG_NOSIGNAL 의미 대역을벗어난데이터를보낸다. 프로토콜이대역을벗어난데이터를지원해야한다. 직접연결된네트워크에존재하는호스트로전송할때게이트웨이를사용하지않고전송한다. 연결형소켓에서상대프로세스가연결을끊었을때발생하는 SIGPIPE 시그널을받지않는다. 일단데이터가아닌대역을벗어난데이터를수신한다. 도착한메시지큐에서첫번째메시지를제거하지않고읽어온다. 일반적인호출이라면큐에서메시지를가져오면서제거한다. 연결형소켓에서상태프로세스가연결을끊었을때발생하는 SIGPIPE 시그널을받지않는다. 7
2. recvfrom struct sockaddr *from 비연결형소켓인경우메시지를전송한측의정보가저장된다. NULL 일경우 recvfrom 은 recv 와동일하다. socklen_t *fromlen recvfrom() 호출시에는 from 의크기를나타낸다. 메시지를수신한이후에는 from 에저장된정보의실제길이를나타낸다. 반환값 호출이성공할경우수신한메시지의바이트수를반환한다. 실패하면 -1 을반환한다. 8
3. sendto 비연결형통신모델에서소켓을통해메시지를송신한다. #include <sys/types.h> #include <sys/socket.h> int sendto(int sockfd, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); sockfd 소켓기술자이다. msg 전송할메시지를저장하고있는버퍼이다. len 전송할메시지의길이이다. flags sendto 의동작방식을결정한다. send 와동일하다. to 메시지를수신하는쪽의주소등에대한정보이다. tolen to 의크기이다. 반환값 호출이성공하면전송한메시지의바이트수를반환하고, 실패하면 -1 을반환한다. 9
3. sendto sendto 함수 비연결형통신모델에서메시지를송신할때사용한다. int sockfd 소켓기술자로비연결형모델에서사용되므로상대프로세스의소켓과 연결되어있을필요는없다. const void *msg, size_t len 송신할메시지가담긴버퍼의포인터와메시지의크기이다. 10
3. sendto int flags sendto 의동작방식을설정하는데보통 0 을사용한다. const struct sockaddr *to 전송한메시지를수신하게될상대방의정보를저장한다. socklen_t tolen to 의크기이다. 11
예제프로그램완성 서버 (UDP) #define SIZE sizeof(struct sockaddr_in) main() { int sockfd; char msg; struct sockaddr_in server = {AF_INET, 2007, INADDR_ANY}; struct sockaddr_in client; int client_len = SIZE; listen(), accept() 를호출하지않음 sockfd = socket(af_inet, SOCK_DGRAM, 0); bind(sockfd, (struct sockaddr *) &server, SIZE); } while (1) { recvfrom(sockfd, &msg, 1, 0, (struct sockaddr *) &client, &client_len); sendto(sockfd, &msg, 1, 0, (struct sockaddr *) &client, client_len); } 12
예제프로그램완성 클라이언트 (UDP) #define SIZE sizeof(struct sockaddr_in) main() { int sockfd, server_len = SIZE; char msg; struct sockaddr_in server = {AF_INET, 2007}; server.sin_addr.s_addr = inet_addr("202.31.200.87"); sockfd = socket(af_inet, SOCK_DGRAM, 0); } while (read(0, &msg, 1)!= 0) { sendto(sockfd, &msg, 1, 0, (struct sockaddr *) &server, server_len); } recvfrom(sockfd, &msg, 1, 0, (struct sockaddr *) &server, &server_len); printf("%c", msg); 13
4. uname, gethostname 현재의호스트이름을구한다 #include <sys/utsname.h> intuname(structutsname*buf); #include <unistd.h> int gethostname(char *name, size_t len); buf 호스트의시스템정보가저장된다. name 호스트의이름이저장된다. len name 의길이이다. 반환값 호출이성공하면 0 을반환하고, 실패하면 -1 을반환한다. 14
4. uname, gethostname struct utsname struct utsname { char nodename[]; /* 호스트이름 */ char sysname[]; /* 운영체제이름 */ char version[]; /* 운영체제버전 */ char machine[]; /* 머신 (CPU) 의종류 */ char release[]; /* 릴리즈정보 */ }; nodename 현재의컴퓨터가네트워크상에서가지게되는이름 호스트의이름만저장되는게일반적 FQDN(Fully Qualified Domain Name) 일수도있다. 15
예제 13-5 ex 13-05.c #include <sys/utsname.h> #include <unistd.h> main() { struct utsname info; char myname[1024]; $ ex13-05 sysname: SunOS nodename: cs release: 5.8 version: Generic_108528-26 machine: sun4u hostname: cs $ uname(&info); printf("sysname: %s n", info.sysname); printf("nodename: %s n", info.nodename); printf("release: %s n", info.release); printf("version: %s n", info.version); printf("machine: %s n", info.machine); } gethostname(myname, 1024); printf("hostname: %s n", myname); 16
5. gethostbyname 호스트이름으로주소와관련된정보를알아온다 #include <netdb.h> struct hostent *gethostbyname(const char *name); name 호스트의이름으로도메인네임주소까지포함한다. 반환값 호출이성공하면 struct hostent형의포인터를반환하고, 실패하면 NULL 을반환한다. const char *name 호스트의이름 ce 와같이줄수도있고 ce.sungshin.ac.kr 과같이줄수도있다. 17
5. gethostbyname struct hostent struct hostent { char *h_name; /* 공식이름 */ char **h_aliases; /* 보조이름 ( 가명 ) 리스트 */ int h_addrtype; /* 주소형태 */ int h_length; /* 주소의길이 */ char **h_addr_list; /* list of addresses */ } h_name 호스트의공식이름 h_aliases 공식이름이아닌또다른이름즉별명을나타낸다. 18
5. gethostbyname h_addrtype 호스트의주소형태 IPv4 일경우 AF_INET IPv6 일경우 AF_INET6 h_length 호스트주소의크기 ( 바이트 ) IPv4 일경우 4 바이트 IPv6 일경우 6 바이트 h_addr_list 주소의리스트이다. 19
예제 13-6 ex 13-06.c main(int argc, char *argv[]) { struct hostent *hent; char **ptr; if (argc < 2) { printf("%s hostname n", argv[0]); exit(1); } if ((hent = gethostbyname(argv[1])) == NULL) { printf("fail to call gethostbyname() n"); exit(1); } printf("official name : %s n", hent->h_name); for (ptr = hent->h_aliases; *ptr!= NULL; ptr++) printf(" talias : %s n", *ptr); } if (hent->h_addrtype == AF_INET) { for (ptr = hent->h_addr_list; *ptr!= NULL; ptr++) printf(" taddress : %s n", inet_ntoa(*((struct in_addr *)*ptr))); } 20
실행결과 $ ex13-06 www.daum.net official name : daumtop.daum.akadns.net alias : www.daum.net address : 222.231.51.78 address : 211.115.115.211 address : 211.115.115.212 address : 222.231.51.77 $ ex13-06 ce official name : ce.kumoh.ac.kr alias : ce address : 202.31.200.87 $ ex13-06 www.google.com official name : www.l.google.com alias : www.google.com address : 66.102.7.147 address : 66.102.7.99 address : 66.102.7.104 $ 21
6. gethostbyaddr 주어진바이너리 IP 주소에해당하는호스트의이름을구한다 #include <netdb.h> struct hostent *gethostbyaddr(const char *addr, int len, int type); addr 바이너리형태의 IP 주소이다. len addr 의바이트크기이다. type 프로토콜군을지정한다. 반환값 호출이성공하면 struct hostent 형의포인터를반환하고, 실패하면 NULL 을반환한다. const char *addr 바이너리형태의 IP 주소이다. inet_addr 함수가반환하는 in_addr_t 형의값에대한포인터 22
int len addr 의바이트크기이다. IPv4 일경우 4, IPv6 일경우 6 이된다 int type AF_INET 또는 AF_INET6 이다. 23
예제 13-7 ex 13-07.c main(int argc, char *argv[]) { struct hostent *hent; in_addr_t ipaddr; char **ptr; if (argc < 2) { printf("%s ip_address n", argv[0]); exit(1); } if ((ipaddr = inet_addr(argv[1])) == -1) { printf("fail to call inet_addr() n"); exit(1); } hent = gethostbyaddr((char *)&ipaddr, 4, AF_INET); printf("official name : %s n", hent->h_name); for (ptr = hent->h_aliases; *ptr!= NULL; *ptr++) printf(" talias : %s n", *ptr); } if (hent->h_addrtype == AF_INET) { for (ptr = hent->h_addr_list; *ptr!= NULL; ptr++) printf(" taddress : %s n", inet_ntoa(*((struct in_addr *)*ptr))); } 24
실행결과 $ ex13-07 202.31.200.87 official name : ce.kumoh.ac.kr alias : ce address : 202.31.200.87 $ ex13-07 66.102.7.147 official name : mc-in-f147.google.com address : 66.102.7.147 $ 25
7. socket 을이용한 myftp 구현 FTP (File Transfer Protocol) FTP 클라이언트 put get FTP 서버 lcd!ls cd ls hash quit 26
7. socket 을이용한 myftp 구현 FTP (File Transfer Protocol) MYFTP Protocol quit myftp 클라이언트프로그램종료 lcd dir!ls ls 클라이언트쪽의현재디렉토리를 dir 변경 클라이언트쪽의현재디렉토리에대한파일목록을생성하여출력 서버쪽의현재디렉토리에대한파일목록을생성 소켓을이용하여클라이언트로파일목록전송 Escape 문자 (ASCII 코드는 27) 를이용하여전송종료를알림. hash 파일전송시매블록마다 # 문자를출력하여전송진행상황을보고 서버쪽에서도 # 문자가출력되도록하기위하여 hash 명령을서버로전송 27
7. socket 을이용한 myftp 구현 MYFTP Protocol cd dir 클라이언트는 cd 명령어와 dir 인자를서버로전송 서버에서는전송된명령어와인자를가지고서버쪽의현재디렉토리를변경 put file 클라이언트는 put 명령어와 file 인자를서버로전송 클라이언트에서는 file 을 open 한후한블록씩읽어들여소켓을통해서버로전송 서버에서는해당파일을생성한후소켓을통해전송된내용을저장 get file 클라이언트는 get 명령어와 file 인자를서버로전송 서버에서는해당파일을 open 한후한블록씩읽어소켓을통해클라이언트로전송 클라이언트에서는 file 을생성한후소켓을통해전송된내용을파일로저장 28
7. socket 을이용한 myftp 구현 MYFTP Protocol 명령어, 인자, 데이터전송방법 다음과같이전송할데이터의크기를 int 타입의변수에저장한후 이것을먼저전송하고나서실제데이터를전송한다. 전송종료를알리기위해서는마지막에데이터의크기를 0 으로지정한 헤더를전송한다. size data size data size data 0 Example 4 put 6 a.out 512 blabla 123 blabla 0 29