공부중
[TCP/IP 소켓]네트워크 프로그래밍과 소켓의 이해 본문
정수형이 서버세미나를 한다고 해서 덥석 물어볼려고 한다
그전에 정리를 조금 해봐야겠다..
∙네트워크 프로그래밍이란?
네트워크로 연결되어있는 서로 다은 두 컴퓨터가 데이터를 주고 받을 수 있도록 하는 것.
운영체제에서 소켓(Socket)이라는 것을 제공하기 때문에 물리적인 연결을 기반으로 하는 소프트웨어적인 데이터 송수신 방법을 고민할 필요가 없어졌다.
이는 물리적으로 연결된 네트워크상에서의 데이터 송수신에 사용할 수 있는 소프트웨어적인 장치를 의미한다.
∙전화 받는 소켓의 구현
순서 | 비유대상 | 함수 |
1 | 전화기 구입 | socket |
2 | 전화번호 | bind |
3 | 전화기의 케이블 연결 | listen |
4 | 수화기를 들기 | accept |
#include <sys/socket.h> int socket(int domain, int type, int protocol); |
성공 시 파일 디스크립터, 실패시 -1반환 |
일단은 socket이라는 함수가 소켓을 생성하는 구나 하는 정도만 이해하자.
#include <sys/socket.h> int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen); |
성공시 0, 실패시 -1 반환 |
bind 함수호출을 통해서 소켓에 주소정보를 할당
#include <sys/socket.h> int listen(int sockfd, int backlog); |
성공시 0, 실패시 -1 반환 |
소켓을 연결요청이 가능한 상태가 되게 한다.
#include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr,socklen_t *addrlen); |
성공시 파일 디스크립터, 실패시 -1반환 |
누군가 데이터의 송수신을 위해 연결요청이 올 때 그 요청을 수락해준다.
∙전화 거는 소켓의 구현
#include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen); |
성공시 0, 실패 시 -1반환 |
전화를 거는(연결을 요청하는) 기능의 함수
∙저 수준 파일 입출력(low-level File Access)과 파일 디스크립터(File Descriptor)
저 수준이란… "표준에 상관없이 운영체제가 독립적으로 제공하는.."이라는 의미로 받아들이면 된다.
파일 디스크립터(파일 핸들)란 시스템으로부터 할당 받은 파일 또는 소켓에 부여된 정수를 의미한다.
∙파일 열기
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *path, int flag); | |
성공 시 파일 디스크립터, 실패 시 -1반환 | |
| 파일 이름을 나타내는 문자열의 주소 값 전달 |
| 파일의 오픈 모드 정보 전달 |
오픈 모드 | 의 미 |
| 필요시 파일을 생성 |
| 기존 데이터 전부 삭제 |
| 기존데이터 보관, 뒤에 이어서 저장 |
| 읽기전용으로 파일 열기 |
| 쓰기전용으로 파일 열기 |
| 읽기, 쓰기 겸용으로 열기 |
open 함수의 두 번째 매개변수 flag에 전달할 수 있는 값과 의미이다.
∙파일 닫기
#include <unistd.h> int close(int fd); | |
성공 시 0, 실패 시 -1 반환 | |
| 닫고자 하는 파일 또는 소켓의 파일 디스크립터 전달 |
위 함수를 호출하면서 파일 디스크립터를 인자로 전달하면 해당 파일은 종료하게 된다.
위 함수는 파일 뿐만 아니라 소켓을 닫을 때에도 사용된다.
∙파일에 데이터 쓰기
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t nbytes); | |
성공 시 전달한 바이트 수, 실패 시 -1 반환 | |
| 데이터 전송대상을 나타내는 파일 디스크립터 전달. |
| 전송할 데이터가 저장된 버퍼의 주소 값 전달 |
| 전송할 데이터의 바이트 수 전달 |
write함수는 파일에 데이터를 출력(전송)하는 함수이다.
리눅스에서는 파일과 소켓을 동일하게 취급하므로, 소켓을 통해 다른 컴퓨터에 데이터를 전송할 때에도 이 함수를 사용할 수 있다.
size_t는 typedef을 통해서 unsigned int로 정의 되어있다.
∙파일에 저장된 데이터 읽기
#include <unistd.h> ssize_t read(int fd, void *buf, size_t nbytes); | |
성공 시 수신한 바이트 수(단 파일의 끝을 만나면 0), 실패 시 -1 반환 | |
| 데이터 수신대상을 나타내는 파일 디스크립터 전달. |
| 수신한 데이터를 저장할 버퍼의 주소 값 전달 |
| 수신할 최대 바이트 수 전달 |
write 함수의 상대적인 기능을 제공하는 read 함수는 데이터를 입력(수신)하는 기능의 함수 이다.
∙윈도우 소켓을 위한 헤더와 라이브러리의 설정
윈속(윈도우 소켓)을 기반으로 프로그램을 개발하기 위해서는 기본적으로 다음 두 가지를 진행해야 한다.
- 헤더파일 winsock2.h를 포함한다.
- ws2_32.lib 라이브러리를 링크시켜야 한다.
⊙라이브러리 링크 시키는 방법
- 프로젝트 오른쪽 버튼을 누른 뒤 속성
- 속성창에서 '구성속성'→'링커'→'입력'→'추가 종속성' 혹은 '구성속성'→'입력'→'추가 종속성'
- 라이브러리 추가.
∙윈속(winsock)의 초기화
#include <winsock2.h> int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); | |
성공 시 0, 실패 시 0이 아닌 에러코드 값 반환 | |
| 프로그래머가 사용할 윈속의 버전정보 전달 |
| WSADATA라는 구조체 변수의 주소 값 전달 |
윈도우 소켓에는 몇몇 버전이 존재하는데 사용할 소켓의 버전정보를 WORD형으로 구성해서 wVersionRequested로 전달해야 한다.
예로 사용할 소켓의 버전이 1.2이면 1이 주 버전이고 2가 부 버전이므로 0x0201을 인자로 전달해야 한다.
이 번거로운 것을 해결해줄 매크로 함수 MAKEWORD가 제공되고 있다.
이 함수를 사용하면 다음과 같이 간단하게 WORD형 버전 정보를 구성 할 수 있다.
MAKEWORD(1,2) //주 버전 1, 부 버전 2, 0x0201반환
MAKEWORD(2,2) //주 버전 2, 부 버전 2, 0x0202 반환
lpWSAData에는 WSADATA구조체 변수의 주소 값을 인자로 전달해야 한다. (LPWSADATA는 WSADATA의 포인터 형이다.)
그러면 함수 호출이 완료되고 난 다음에 해당 변수에는 초기화된 라이브러리의 정보가 채워진다.
특별히 큰 의미는 지니지 않으나 함수호출을 위해서 반드시 WSADATA구조체 변수의 주소 값을 전달 해야한다.
#include <windsock2.h> int WSACleanup(void) |
성공시 0 , 실패시 SOCKET_ERROR반환 |
위 함수를 호출하면 할당된 윈속 라이브러리는 윈도우 운영체제에 반환이 되면서 윈속관련 함수의 호출이 불가능해진다.
더 이상 윈속관련 함수의 호출이 불필요할 때, 위 함수를 호출하는 것이 원칙이나 프로그램이 종료되기 직전에 호출하는 것이 보통이다.
∙윈도우 기반 소켓관련 함수들
#include <winsock2.h> SOCKET socket(int af, int type, int protocol); |
성공 시 소켓핸들, 실패 시 INVALID_SOCKET 반환 |
리눅스의 socket함수와 동일한 기능을 제공한다.
#include <winsock2.h> int bind(SOCKET s, const struct sockaddr *name, int namelen); |
성공 시 소켓 핸들, 실패 시 SOCKET_ERROR반환 |
리눅스의 bind 함수와 동일한 기능을 제공한다.
IP주소와 PORT번호의 할당을 목적으로 호출되는 함수이다.
#include <winsock2.h> int listen(SOCKET s, int backlog); |
성공 시 0, 실패 시 SOCKET_ERROR반환 |
리눅스의 listen 함수와 동일한 기능을 제공한다
소켓이 클라이언트 프로그램의 연결 요청을 받아들일 수 있는 상태가 되게 하는 것을 목적으로 호출되는 함수이다.
#include <winsock2.h> SOCKET accept(SOCKET s, struct sockaddr* addr, int *addrlen); |
성공 시 소켓핸들, 실패 시 INVALID_SOCKET 반환 |
리눅스의 accept함수와 동일한 기능을 제공한다.
클라이언트 프로그램에서의 연결요청을 수락할 때 호출하는 함수이다.
#include <winsock2.h> int connect(SOCKET s, const struct sockaddr *name, int namelen); |
성공 시 0, 실패 시 SOCKET_ERROR반환 |
클라이언트 프로그램에서 소켓을 기반으로 연결요청을 할 때 호출하는 함수로써, 리눅스의 connect함수와 동일 한 기능을 제공한다.
#include <winsock2.h> int closesocket(SOCKET s); |
성공시 0, 실패 시 SOCKET_ERROR 반환 |
소켓을 닫을 때 호출하는 함수이다.
∙윈도우 기반 입출력 함수
#include <windsock2.h> int send(SOCKET s, const char *buf, int len, int flags); | |
성공 시 전송된 바이트 수, 실패시 SOCKET_ERROR반환 | |
| 데이터 전송 상과의 연결을 의미하는 소켓의 핸들 값 전달. |
| 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달. |
| 전송할 바이트 수 전달. |
| 데이터 전송 시 적용할 다양한 옵션 정보 전달. |
리눅스의 write 함수와 비교하면 마지막 매개변수 flags가 존재하는 것 이외에는 차이가 없다.
리눅스에도 동일한 함수가 존재한다.
#include <winsock2.h> int recv(SOCKET s, const char* buf, int len, int flags); | |
성공 시 수신한 바이트 수(단 EOF 전송 시 0), 실패 시 SOCKET_ERROR반환 | |
| 데이터 수신 대상과의 연결을 의미하는 소켓의 핸들 값 전달. |
| 수신된 데이터를 저장할 버퍼의 주소 값 전달. |
| 수신할 수 있는 최대 바이트 수 전달. |
| 데이터 수신 시 적용할 다양한 옵션 정보 전달. |
'Programing > TCP IP 소켓' 카테고리의 다른 글
[TCP/IP] TCP 기반 서버 / 클라이언트 - 1 (2) | 2013.01.29 |
---|---|
[TCP/IP]주소체계와 데이터 정렬 (0) | 2013.01.08 |
[TCP/IP 소켓]소켓의 타입과 프로토콜의 설정 (0) | 2013.01.07 |