네트워크 프로그래밍과 소켓에 대한 이해

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

 - 소켓이라는 것을 기반으로 프로그래밍을 하기 때문에 소켓 프로그램이라고도 함.

 - 네트워크로 연결된 둘 이상의 컴퓨터 사이엥서의 데이터 송수신 프로그램의 작성을 의미함.


소켓에 대한 간단한 이해

 - 네트워크(인터넷)의 연결 도구

 - 운영체제에 의해 제공이 되는 소프트웨어적인 장치

 - 소켓은 프로그래머에게 데이터 송수신에 대한 물리적, 소프트웨어적 세세한 내용을 신경 쓰지 않게 한다.


전화 받는 소켓의 생성

소켓의 비유와 분류

 - TCP 소켓은 전화기에 비유될 수 있다.

 - 소켓은 socket 함수의 호출을 통해서 생성한다.

 - 단, 전화를 거는 용도의 소켓과 전화를 수신하는 용도의 소켓 생성 방법에는 차이가 있다. 


 #include <sys/socket.h>

int socket(int domain, int type, int protocol); 

-> 성공시 파일 디스크립터, 실패시 -1 반환

전화번호의 부여

소켓의 주소 할당 및 연결

 - 전화기에 전화번호가 부여되듯이 소켓에도 주소정보가 할당된다.

 - 소켓의 주소정보는 IP와 PORT번호로 구성이 된다. 


 #include <sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen); 

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


전화기의 연결

연결요청이 가능한 상태의 소켓 

 - 연결요청이 가능한 상태의 소켓은 걸려오는 전화를 받을 수 있는 상태에 비유 할 수 있다.

 - 전화를 거는 용도의 소켓은 연결 요청이 가능한 상태의 소켓이 될 필요가 없다. 이는 걸려오는 전화를 받는 용도의 소켓에서 필요한 상태이다.


 #include <sys/socket.h>

int listen(int sockfd, int backlog); 

-> 소켓에 할당된 IP와 PORT 번호로 연결요청이 가능한 상태가 된다.


수화기를 드는 상황

연결요청의 수락

 - 걸려오는 전화에 대해서 수락의 의미로 수화기를 드는 것에 비유할 수 있다.

 - 연결요청이 수락되어야 데이터의 송수신이 가능하다.

 - 수락된 이후에 데이터의 송수신은 양방향으로 가능하다.


 #include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 

-> 성공 시 파일 디스크립터, 실패시 - 1반환

accept 함수 호출 이후에는 데이터의 송수신이 가능하다. 단, 연결요청이 있을 때에만 accept 함수가 반환을 한다.


연결요청을 허용하는 소켓의 생성과정

1단계.     소켓의 생성                            socket 함수 호출

2단계.     IP와 PORT번호의 할당      bind  함수 호출

3단계.     연결요청 가능상태로 변경  listen 함수호출

4단계.     연결요청에 대한 수락           accept 함수 호출


예제 hello_server.c를 통해서 함수의 호출과정 확인하기

 - 연결요청을 허용하는 프로그램을 가리켜 일반적으로 서버(Server)라 한다.

 - 서버는 연결을 요청하는 클라이언트보다 먼저 실행되어야 한다.

 - 클라이언트보다 복잡한 실행의 과정을 거친다.

 -> 이렇게 생성된 소켓을 가리켜 서버 소켓 또는 리스닝 소켓이라 한다.


<hello_server.c>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


void error_handling(char *message);


int main(int argc, char *argv[])

{

int serv_sock;

int clnt_sock;


struct sockaddr_in serv_addr;

struct sockaddr_in clnt_addr;

socklen_t clnt_addr_size;


char message[]="Hello World!";

if(argc!=2){

printf("Usage : %s <port>\n", argv[0]);

exit(1);

}

serv_sock=socket(PF_INET, SOCK_STREAM, 0);

if(serv_sock == -1)

error_handling("socket() error");

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family=AF_INET;

serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

serv_addr.sin_port=htons(atoi(argv[1]));

if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 )

error_handling("bind() error"); 

if(listen(serv_sock, 5)==-1)

error_handling("listen() error");

clnt_addr_size=sizeof(clnt_addr);  

clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);

if(clnt_sock==-1)

error_handling("accept() error");  

write(clnt_sock, message, sizeof(message));

close(clnt_sock);

close(serv_sock);

return 0;

}


void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);


전화 거는 소켓의 구현

연결을 요청하는 소켓의 구현

 - 전화를 거는 상황에 비유할 수 있다.

 - 리스닝 소켓과 달리 구현의 과정이 매우 간단하다.

 - '소켓의 생성'과 '연결의 요청'으로 구분된다.


<hello_client.c>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


void error_handling(char *message);


int main(int argc, char* argv[])

{

int sock;

struct sockaddr_in serv_addr;

char message[30];

int str_len;

if(argc!=3){

printf("Usage : %s <IP> <port>\n", argv[0]);

exit(1);

}

sock=socket(PF_INET, SOCK_STREAM, 0);

if(sock == -1)

error_handling("socket() error");

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family=AF_INET;

serv_addr.sin_addr.s_addr=inet_addr(argv[1]);

serv_addr.sin_port=htons(atoi(argv[2]));

if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) 

error_handling("connect() error!");

str_len=read(sock, message, sizeof(message)-1);

if(str_len==-1)

error_handling("read() error!");

printf("Message from server: %s \n", message);  

close(sock);

return 0;

}


void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);


블로그 이미지

잉비니

,