Young & Rich

오늘은 TCP 소켓 프로그래밍에 대해서 포스팅을 하겠습니다.

 

일단, 네트워크는 5계층으로 나뉩니다.

(7계층도 있지만, 간략하게 5계층으로 설명하겠습니다.)

 

[ 네트워크 5계층 ]

  1. 어플리케이션층
    1. HTTP, SMTP, FTP
  2. 전송계층
    1. TCP(Transmission Control Protocol)/UDP(User Datagram Protocol)
  3. 네트워크층
    1. IP(Internet Protocol), 라우팅
  4. 네트워크 접속계층(이더넷) - 물리 & 링크

네트워크 5계층
네트워크 5계층

 

[ TCP/IP 배경지식 ]

  1. 주소
    1. 32bit - 4byte(0~255 : 2의8승, 8bit * 4 = 32bit)
      1. 192.168.101.180
  2. 포트
    1. 16bit unsigned 이진수(1~65,535) : 0은 예약
  3. 클라이언트와 서버
    1. 클라이언트
      1. Host 및 명령을 요청하는 부분이 Client - Server의 주소 및 포트를 알고 있어야함
    2. 서버
      1. 클라이언트의 주소를 알고 있지 않아도 됨(최초의 통신 내용을 받았을 때 소켓 API로 주소를 알아낼 수 있음), 요청을 받아 명령을 수행한 뒤에 응답
  4. 소켓
    1. 두 프로그램이 네트워크를 통해 서로 통신을 수행 할 수 있도록 양쪽에 생성되는 링크의 단자입니다. 두 소켓이 연결되면 서로 다른 프로세스끼리 데이터를 전달 할 수 있습니다.

 

 

[ TCP 소켓 프로그래밍 ]

 

클라이언트단에서 사용하는 기본 함수

socket -> connect -> send -> recv -> close

int socket(int protocolFamily, int type, int protocol)
PF_INET : SOCK_STREAM or SOCK_DGRAM : IPPROTO_TCP or IPPROTO_UDP or 0(defulat)
0 : socket descriptor(음이 아닌 값), connect, recv, send, close에 모두 사용됨
-1 : 실패
 
[Example]
client_socket = socket( PF_INET, SOCK_STREAM, 0);
if (client_socket == -1) 
{
    printf( "create socket failed\n");
    return -1;
}
 
 
 
int close(int socket)
0 : 성공
-1 : 실패
 소켓을 모두 사용하고 자원정리 할 때 사용되는 함수
 
 
int connect(int socket, struct sockaddr *foreignAddress, unsigned int addressLength)
socket api return 값, 아래의 코드블럭의 주소 구조체에 채워져 있는 주소값, 주소 구조체의 길이
[Example]
while ( connect( client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 )
{
    if (fail_cnt <= 10) 
    {
        sleep(1);
        fail_cnt++;
    }
    else
    {
        printf("connection failed..");
        return -1;
    }
}
 
 
 
int send(int socket, const void *msg, unsigned int msgLength, int flags)
int recv(int socket, void *recvBuffer, unsigned int bufferLength, int flags)
성공 시 send 한 byte length, 실패 시 -1
성공 시 recv 한 byte length, 실패 시 -1

소켓 프로그래밍에 사용되는 구조체

struct sockaddr
{
    unsigned short sa_familty;      /* Address familty(e.g. AF_INET) */
 
    char sa_data[14];               /* Family-specific address information */
 
}
 
 
struct in_addr
{
    unsigned long s_addr;   /* Internet Address 32 bits */
 
}
 
 
struct sockaddr_in
{
    unsigned short sin_familty;     /* Internet Protocol (AF_INET) */
 
    unsigned short sin_port;        /* Address Port 16 bits */
 
    struct in_addr sin_addr;        /* Internet Address 32 bits */
 
    char sin_zero[8];               /* Not used */
 
}

 

[ 예제 프로그램 ]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define PORT 1004
#define IPADDR "127.0.0.1" // Loopback 주소, 자기 자신 주소
#define BUFFER_SIZE 4096

void main()
{
	int socket_fd = -1;
	struct sockaddr_in c_addr;

	char send_buffer[BUFFER_SIZE], recv_buffer[BUFFER_SIZE];

	socket_fd = socket(PF_INET, SOCK_STREAM, 0);		// SOCK_STREAM : TCP

	memset(&c_addr, 0, sizeof(c_addr));
	c_addr.sin_addr.s_addr = inet_addr(IPADDR);		// IP 주소
	c_addr.sin_family = AF_INET;		// IPv4 설정
	c_addr.sin_port = htons(PORT);		// PORT 설정

	if(connect(socket_fd, (struct sockaddr *)&c_addr, sizeof(c_addr)) == -1 )
	{
		// 실패 예외처리
		close(socket_fd);
	}

	while(1)
	{
		// 원하는 메세지 send
		n_send = send(socket_fd, send_buffer, BUFFER_SIZE);
		
		// 서버단에서 메세지 recv
		n_recv = read(socket_fd, recv_buffer, BUFFER_SIZE);

		if ( 조건문 )
		{
			// 종료 조건
			break;
		}

	}

	if ( socket_fd > 0 )
	{
		// 소켓 종료
		close(socket_fd);
	}
}

 

위에 처럼 간단하게 프로그래밍을 할 수 있습니다.

 

클라이언트는 물론 서버와 통신 프로그램과 같이 해야 정상적으로 작동합니다.

connect 단계에서 서버가 작동하고 있지 않으면 에러가 나면서 종료됩니다.

 

이상 간단한 클라이언트 프로그램이였습니다.

 

다음번엔 서버 프로그래밍에 대해서 포스팅 하겠습니다.

 

그럼 20000.

 

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band