780 likes | 965 Views
Linux Socket Programming - Introducing Sockets –. Network Lab. 이 성 현. 목 차. 소켓의 역사 소켓의 본질 리눅스 커널과 응용 프로그램의 소켓 참조 소켓 C 프로그램 예제. 간단한 역사 소개. 1957. 10. 04 - Sputnik 발사 성공 1958. 01. 07 - ARPA(Advanced Research Projects Agency) 출범
E N D
Linux Socket Programming- Introducing Sockets – Network Lab. 이 성 현 한남대학교 컴퓨터공학과 컴퓨터 네트워크 실험실
목 차 • 소켓의 역사 • 소켓의 본질 • 리눅스 커널과 응용 프로그램의 소켓 참조 • 소켓 C 프로그램 예제
간단한 역사 소개 • 1957. 10. 04 - Sputnik 발사 성공 • 1958. 01. 07 - ARPA(Advanced Research Projects Agency) 출범 • 1962 - J.C.R Licklider : 서로 다른 컴퓨터 간의 통신을 위 한 아이디어 창출 • 1969 - ARPA & UNIX • 1982 - 4.1BSD와 4.2BSD에 TCP/IP를 포함한 UCB 배포 • 1991. 10. 05 – Linux 0.02 발표
간단한 역사 소개(계속) October 4, 1957 Sputnik ARPA January 1, 1958 1962 J.C.R Licklider ARPANET UNIX 1969 1979 DARPA funds UCB 1982 4.1BSD and 4.2BSD Sockets October 5, 1991 Linux 0.02 그림 1.1: ARPA으로부터 24년 후에 BSD 소켓 발달
소켓의 이해 • 소켓의 정의 –전화 네트워크와의 비교 • 리눅스의 소켓은 전화와 유사 • 소켓은 통신라인의 종점을 표시 • 전화 : 전화번호 – 소켓 : 네트워크 주소 • 소켓은 통신의 종점이기 때문에 종료 가능
Telephone Network 소켓의 이해(계속) • 전화 네트워크 그림 1.2 전화 네트워크
소켓에 대한 이해(계속) • 소켓의 정의 • 소켓은 소프트웨어로 작성된 통신 접속점 • 소켓은 서버와 서로 특정한 규약을 사용하여 데이터를 전송하는 방식 • 네트워크 응용 프로그램은 소켓을 통해 데이터 송수신 • 소켓 인터페이스 - 응용 프로그램에서 TCP/IP를 이용하는 창구 역할을 하는 인터페이스
소켓의 이해(계속) (OSI 계층) 5-7 응용 1 응용 2 응용 3 소켓 인터페이스 소켓 1 소켓 2 소켓 3 4 TCP/IP 3 네트워크 드라이버 2 1 네트워크 그림 1.3: 소켓 인터페이스 위치
소켓의 이해(계속) • 소켓 사용 • open(2) 함수를 사용하여 파일을 열 때, 파일 기술자를 리턴하면 성공 • read(2), write(2), lseek(2), close(2)를 사용하여 파일을 열 수 있다.
소켓의 이해(계속) • 소켓과 파이프의 차이점 • 소켓은 lseek(2)할 수 없다. • 소켓은 위치 주소를 가지지만, 파일과 파이프는 네트워크 주소를 가질 수 없다. • 소켓은 서로 다른 옵션을 사용할 수 있으며, 소켓에 대한 질문과 ioctl(2)를 사용할 수 있다. • 소켓은 입/출력을 위해 올바른 상태를 가져야 하지만, 오픈된 파일은 어떠한 때라도 읽거나 쓸 수 있다.
소켓의 이해(계속) • 소켓 참조 • open(2) 함수를 호출하여 새로운 파일을 열었을 때, 파일 기술자를 리눅스 커널에서 리턴 • 파일 기술자를 호출하여, 파일이 열려질 때 0 또는 양의 정수 값을 이용
소켓의 이해(계속) • 파일 기술자가 커널에 위치하는 과정 • 파일을 열기 위해서 open(2) 함수 호출 • 파일 기술자 3이 열려진 파일을 참조하기위해서 리턴된다. • 새로운 소켓이 적당한 함수를 호출하여 생성된다. • 파일 기술자 4는 새로운 소켓을 참조하기 위해서 리턴된다. • 다른 파일이 open(2)를 호출하여 열린다. • 파일 기술자 5는 새로 오픈된 파일을 참조하기 위해서 리턴된다.
소켓의 이해(계속) 서버 클라이언트 socket() socket() bind() listen() connect() 연결요청 accept() write() 데이터 read() write() 데이터 read() close() 종료 그림 1.4: 소켓 연결 개요
소켓의 이해(계속) • 소켓 함수의 예 • socket() : 사용하고자 하는 통신 프로토콜을 지정 • int socket(int domain, int type, int protocol); • socketpair() : 소켓 연결의 한 쌍을 지정 • int socketpair(int domain, int type, int protocol, int sv[2]); • bind() : 소켓에 이름을 결합 • int bind(int sockfd, sockaddr * myaddr, int addrlen);
소켓의 이해(계속) • 소켓 함수의 예 • connect() : 클라이언트가 서버에 연결을 요청하기 위해 호출 • int connect(int socfd, struct sockaddr *servaddr, int addrlen); • listen() : 서버 프로세스가 통신할 연결기반 소켓 설정 • int listen(int sockfd, int size); • accept() : 서버 프로세스에서 클라이언트 소켓과 연결을 설정 하기 위해 호출 • int accept(int sockfd, struct sockaddr *peer, int *addrlen);
소켓의 이해(계속) • 소켓 함수의 예 • write() : 다른 소켓에 메시지 전송 • ssize_t write(int fd, const void *buf, size_t count); • read() : 다른 소켓에서 메시지 수신 • ssize_t read(int fd, void *buf, size_t count); • close() : 소켓의 연결을 종료 • int close(int fd);
소켓과 파이프의 비교 • pipe • pipe(2) 함수 호출이 성공이면, 두개의 파일 기술자가 리턴된다. • filedes[0] : 파이프의 끝까지 읽기 위해서 파일 기술자를 담는다. • filedes[1] : 파이프의 끝까지 쓰기 위해서 파일 기술자를 받는다. • 오직 하나의 직접적인 통신 라인 생성
소켓과 파이프의 비교(계속) • 소켓 • 직접적인 통신 프로세스만 허용 • 프로세스는 소켓을 열기 위해 파일 기술자 3 사용 • 지역 프로세스가 파일 기술자 3으로부터 정보를 받아 통신이 이루어지는 원격 프로세스에 보낼 수 있다.
소켓의 생성 • Socketpair(2) 함수 int socketpair(int domain, int type, int protocol, int sv[2]); • 소켓의 도메인 • 소켓의 형태 • 소켓이 사용하는 프로토콜 • 소켓을 생성하고 참조하는 파일 기술자를 받기 위한 배열 포인터
소켓의 생성(계속) • type 인수 –소켓의 타입 선언 • SOCK_STREAM • 스트림 소켓 • SOCK_DGRAM • 데이터그램 소켓
소켓의 생성(계속) • socketpair(2) 리턴 값 • success : 0 • error : -1, errno 에 에러 발생 이유 출력
소켓의 생성(계속) • socketpair(2) 예제 – Listing 1.1 • 13: int • 14: main(int argc,char**argv) { • 15: int z; /* Status return code */ • 16: int s[2]; /* Pair of sockets */ • 16 라인에서 소켓이 생성되고 참조되는 두 개의 새로운 파일 기술자를 s[2]의 배열로 받음
소켓의 생성(계속) • socketpair(2) 예제 – Listing 1.1 • 21: z = socketpair(AF_LOCAL,SOCK_STREAM,0,s); • socketpair(2) 함수 호출 • AF_LOCAL : 도메인 인수 지정 • SOCK_STREAM : 소켓 타입 • 0 : 프로토콜 0으로 지정 • s : 파일 기술자를 받기 위한 배열 포인터 지정
소켓의 생성(계속) • socketpair(2) 예제 – Listing 1.1 • 23: if ( z == -1 ) { • 24: fprintf(stderr, • 25: "%s: socketpair(AF_LOCAL,SOCK_STREAM,0)\n", • 26: strerror(errno)); • 27: return 1; /* Failed */ • 에러 발생 출력
소켓의 생성(계속) • socketpair(2) 예제 – Listing 1.1 • 33: printf("s[0] = %d;\n",s[0]); • 34: printf("s[1] = %d;\n",s[1]); • 소켓 s[0]의 파일 기술자 출력 • 소켓 s[1]의 파일 기술자 출력
소켓의 생성(계속) • socketpair(2) 예제 – Listing 1.1 • 36: system("netstat--unix -p"); • netstat(1) 명령어는 system(3) 함수를 사용 • --unix : AF_LOCAL 도메인을 출력 • -p : 프로세스의 정보를 출력
소켓의 생성(계속) • 실행 결과 • 1: $ ./01lst01 • 2: s[0] = 3; • 3: s[1] = 4; • 4: (Not all processes could be identified, non-owned process info • 5: will not be shown, you would have to be root to see it all.) • 6: Active UNIX domain sockets (w/o servers) • 7: ProtoRefCntFlags Type State I-Node PID/Program name Path • 8: unix 1 [ ] STREAM CONNECTED 112354 - @0000022c • 9: unix 1 [ ] STREAM CONNECTED 112220 - @0000020e • 10: unix 12 [ ] DGRAM485 - /dev/log • 11: unix 1 [ ] STREAM CONNECTED 112286 - @00000218 ……………………… • 21: unix 1 [ ] STREAM CONNECTED 288195 28402/01lst01 • 22: unix 1 [ ] STREAM CONNECTED 288194 28402/01lst01 ………………………
소켓의 생성(계속) • 실행 결과 분석 • 2-3 라인 : 파일 기술자 3, 4에 의해 열려진 소켓 • 2-45 라인 : netstat(1) 명령으로 system(3) 함수를 호 출하여 출력 • 21-22라인 : 소켓의 정보 출력 • 프로그램 명 : 01lst01 • 프로세스 ID : 28402
소켓의 입출력 실행 • read(2), write(2), close(2) 함수 호출 • #include <unistd.h> • ssize_t read(int fd, void *buf, size_t count); • ssize_t write(int fd, constvoid *buf, size_t count); • int close(int fd); • read(2) : 파일 기술자의 이용 가능한 값을 count 바 이트에 정의된 값 만큼 buf 에 할당 • 리턴값 : 읽은 바이트 숫자
소켓의 입출력 실행(계속) • read(2), write(2), close(2) 함수 호출 • write(2) : 버퍼 buf를 제공받은 파일 기술자 fd 로부 터 데이터를 작성 • 리턴 값 : 작성중인 바이트 숫자, 일반적으로 count 인수 값 과 일치 • close(2) : 파일 기술자가 성공적으로 종료되었을 때 0을 리턴
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 16: int s[2]; /* Pair of sockets */ …………………. • 23: z = socketpair(AF_LOCAL,SOCK_STREAM,0,s); • socketpair(2) 함수가 23 라인에서 호출되고, 성공적으로 이루어 졌다면, s[2]배열의 s[0]와 s[1]에 파일 기술자 리턴
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 25: if ( z == -1 ) { • 26: fprintf(stderr, • 27: "%s: socketpair(AF_LOCAL,SOCK_STREAM," • 28: "0)\n", • 29: strerror(errno)); • 30: return 1; • 에러 발생 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 36: z = write(s[1],cp="Hello?",6); • “Hello?” 메시지가 소켓s[1]에 작성, write(2) 함수의 count 인수에 6으로 할당된 버퍼 값 때문에 공백 바이트를 작성하지 않는다.
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 37: if ( z < 0 ) { • 38: fprintf(stderr, • 39: "%s: write(%d,\"%s\",%d)\n", • 40: strerror(errno),s[1],cp,strlen(cp)); • 41: return 2; /* Failed write */ • 에러 발생 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 44: printf("Wrote message '%s' on s[1]\n",cp); • s[1]의 메시지 출력 • 49: z = read(s[0],buf,sizeofbuf); • 소켓 s[0]의 메시지를 읽어 버퍼에 저장
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 50: if ( z < 0 ) { • 51: fprintf(stderr, • 52: "%s: read(%d,buf,%d)\n", • 53: strerror(errno),s[0],sizeofbuf); • 54: return 3; /* Failed read */ • 에러 발생 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 60: buf[z] = 0; /* NULterminate */ • 61: printf("Received message '%s' from socket s[0]\n", • 62: buf); • 소켓이 성공적으로 메시지를 받았다는 것을 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 67: z = write(s[0],cp="Go away!",8); • 68: if ( z < 0 ) { • 69: fprintf(stderr, • 70: "%s: write(%d,\"%s\",%d)\n", • 71: strerror(errno),s[0],cp,strlen(cp)); • 72: return 4; /* Failed write */ • 소켓 s[0]에 “Go away!”메시지를 저장 • 에러 발생 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 75: printf("Wrote message '%s' on s[0]\n",cp); • s[0]의 메시지 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 80: z = read(s[1],buf,sizeofbuf); • 81: if ( z < 0 ) { • 82: fprintf(stderr, • 83: "%s: read(%d,buf,%d)\n", • 84: strerror(errno),s[1],sizeofbuf); • 85: return 3; /* Failed read */ • 소켓 s[1]의 메시지를 읽어 버퍼에 저장 • 에러 발생 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 91: buf[z] = 0; /* NULterminate */ • 92: printf("Received message '%s' from socket s[1]\n", • 93: buf); • 메시지의 수신이 성공 • 소켓 s[1]으로부터 받은 메시지 출력
소켓의 입출력 실행(계속) • 예제 프로그램-Listing 1.2 • 98: close(s[0]); • 99: close(s[1]); • 소켓 s[0]와 s[1]을 종료 • 102: return 0; • 프로그램을 종료
소켓의 입출력 실행(계속) • 실행 결과 • $ ./01lst02 • Wrote message 'Hello?' on s[1] • Received message 'Hello?' from socket s[0] • Wrote message 'Go away!' on s[0] • Received message 'Go away!' from socket s[1] • Done.
소켓의 종료 • close(2) 함수 • 소켓 종료시에 사용 • 소켓이 종료되면, 원격 소켓으로부터 데이터 받을 수 없음. • 한 쌍의 소켓에서 하나만 종료된 것을 의미
소켓의 종료(계속) • shutdown(2) 함수 • #include shutdown(int s, int how); • shutdown 함수는 두 개의 인수를 요구 • 명시한 함수를 부분적으로 shutdown시키기 위한 소켓 기술자 s • 소켓을 shutdown 시키는 방법을 가리키는 how 인수 • 리턴값 • 함수 호출 성공 : 0 • 함수 호출 실패 : -1
소켓의 종료(계속) • how 인수가 허용하는 값 테이블 1.1: shutdown(2) 함수의 how 인수 허용 값
소켓의 종료(계속) • 소켓 쓰기 shutdown • 쓰기를 허용하지 않는 예제 • int z; • int s; /*Socket */ • z = shutdown(s, SHUT_WR); • if ( z == -1 ) • perror("shutdown()");
소켓의 종료(계속) • 소켓 쓰기 종료의 문제 해결 • 커널 네트워킹 소프트웨어에 의해 데이터가 버퍼에 저장된다. • EOF 지시자를 원격 소켓에 보낸다. 이것은 원격 일기 프로세스에게 소켓에 더 이상의 데이터가 없음을 알려준다. • EOF 지시자 이후에 보내는 메시지를 받기 위해 부분적으로 소켓을 열어 놓는다. • EOF 지시자를 보낸 소켓을 종료한다.
소켓의 종료(계속) • 중복 소켓 처리 • int s; /* Existionsocket */ • int d; /* Duplicated socket */ • d = dup(s); /* duplicate this socket */ • close(s); /* nothing happens yet */ • close(d); /* last close, so shutdown socket */
소켓의 종료(계속) • shutdown() 함수 사용 • int s; /* Existing socket */ • int d; /* Duplicated socket */ • d = dup(s); /* duplicate this socket */ • shutdown(s, SHUT_RDWR); /* immediate shutdown */ • shutdown() 함수가 소켓 s를 shutdown