공부중

[TCP/IP 소켓]네트워크 프로그래밍과 소켓의 이해 본문

Programing/TCP IP 소켓

[TCP/IP 소켓]네트워크 프로그래밍과 소켓의 이해

곤란 2013. 1. 7. 19:23
반응형

 

정수형이 서버세미나를 한다고 해서 덥석 물어볼려고 한다

그전에 정리를 조금 해봐야겠다..

 

∙네트워크 프로그래밍이란?

네트워크로 연결되어있는 서로 다은 두 컴퓨터가 데이터를 주고 받을 수 있도록 하는 것.

 

운영체제에서 소켓(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반환

  • path

파일 이름을 나타내는 문자열의 주소 값 전달

  • flag

파일의 오픈 모드 정보 전달

 

오픈 모드

의 미

  • O_CREAT

필요시 파일을 생성

  • O_TRUNC

기존 데이터 전부 삭제

  • O_APPEND

기존데이터 보관, 뒤에 이어서 저장

  • O_RDONLY

읽기전용으로 파일 열기

  • O_WRONLY

쓰기전용으로 파일 열기

  • O_RDWR

읽기, 쓰기 겸용으로 열기

open 함수의 두 번째 매개변수 flag에 전달할 수 있는 값과 의미이다.

 

∙파일 닫기

#include <unistd.h>

int close(int fd); 

성공 시 0, 실패 시 -1 반환

  • fd

닫고자 하는 파일 또는 소켓의 파일 디스크립터 전달

위 함수를 호출하면서 파일 디스크립터를 인자로 전달하면 해당 파일은 종료하게 된다.

위 함수는 파일 뿐만 아니라 소켓을 닫을 때에도 사용된다.

 

∙파일에 데이터 쓰기

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t nbytes); 

성공 시 전달한 바이트 수, 실패 시 -1 반환

  • fd

데이터 전송대상을 나타내는 파일 디스크립터 전달.

  • buf

전송할 데이터가 저장된 버퍼의 주소 값 전달

  • nbytes

전송할 데이터의 바이트 수 전달

write함수는 파일에 데이터를 출력(전송)하는 함수이다.

리눅스에서는 파일과 소켓을 동일하게 취급하므로, 소켓을 통해 다른 컴퓨터에 데이터를 전송할 때에도 이 함수를 사용할 수 있다.

size_t는 typedef을 통해서 unsigned int로 정의 되어있다.

 

∙파일에 저장된 데이터 읽기

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

성공 시 수신한 바이트 수(단 파일의 끝을 만나면 0), 실패 시 -1 반환

  • fd

데이터 수신대상을 나타내는 파일 디스크립터 전달.

  • buf

수신한 데이터를 저장할 버퍼의 주소 값 전달

  • nbytes

수신할 최대 바이트 수 전달

write 함수의 상대적인 기능을 제공하는 read 함수는 데이터를 입력(수신)하는 기능의 함수 이다.

 

 

∙윈도우 소켓을 위한 헤더와 라이브러리의 설정

윈속(윈도우 소켓)을 기반으로 프로그램을 개발하기 위해서는 기본적으로 다음 두 가지를 진행해야 한다.

  • 헤더파일 winsock2.h를 포함한다.
  • ws2_32.lib 라이브러리를 링크시켜야 한다.

 

⊙라이브러리 링크 시키는 방법

  1. 프로젝트 오른쪽 버튼을 누른 뒤 속성

  2. 속성창에서 '구성속성'→'링커'→'입력'→'추가 종속성' 혹은 '구성속성'→'입력'→'추가 종속성'

  3. 라이브러리 추가.

 

 

 

∙윈속(winsock)의 초기화

#include <winsock2.h>

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 

성공 시 0, 실패 시 0이 아닌 에러코드 값 반환

  • wVersionRequested 

프로그래머가 사용할 윈속의 버전정보 전달

  • lpWsaData 

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반환

  • s

데이터 전송 상과의 연결을 의미하는 소켓의 핸들 값 전달.

  • buf

전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달.

  • len

전송할 바이트 수 전달.

  • flags

데이터 전송 시 적용할 다양한 옵션 정보 전달.

리눅스의 write 함수와 비교하면 마지막 매개변수 flags가 존재하는 것 이외에는 차이가 없다.

리눅스에도 동일한 함수가 존재한다.

 

#include <winsock2.h>

int recv(SOCKET s, const char* buf, int len, int flags); 

성공 시 수신한 바이트 수(단 EOF 전송 시 0), 실패 시 SOCKET_ERROR반환

  • s

데이터 수신 대상과의 연결을 의미하는 소켓의 핸들 값 전달.

  • buf

수신된 데이터를 저장할 버퍼의 주소 값 전달.

  • len

수신할 수 있는 최대 바이트 수 전달.

  • flags

데이터 수신 시 적용할 다양한 옵션 정보 전달.

 

반응형