[소켓 #02] 소켓의 타입과 프로토콜의 설정

이석환·2023년 4월 13일

Socket Programming

목록 보기
3/18

1. 01주차 복습

  • Layer에서 통신이 이루어질 때 protocol

2. 프로토콜의 이해와 소켓의 생성

  • 프로토콜
    개념적으로 약속을 의미
    컴퓨터 상호간의 데이터 송수신에 필요한 통신규약
    소켓을 생성할 때 기본적인 프로토콜을 지정해야 한다.
int socket(int domain, int type, int protocol);
//ex
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
  • domain - 소켓이 사용할 프로토콜 체계(Protocol Family) 정보 전달
    ex) IPv4, IPv6, IPX, low level socket 등 설정
  • type - 소켓의 데이터 전송방식에 대한 정보 전달
    ex) TCP, UDP 설정
  • protocol - 두 컴퓨터간 통신에 사용되는 프로토콜 정보 전달
    ex) 특정 프로토콜 사용을 지정 (보통 0)

매개변수 domain, type 그리고 protocol이 모두 protocol 정보와 관련이 있다.

3. 프로토콜 체계 (Protocol Family)

프로토콜도 종류에 따라서 부류가 나뉜다.
그 부류를 가리켜 "프로토콜 체계"라 한다.
프로토콜 체계의 PF_INET은 IPv4 인터넷 프로토콜 체계를 의미한다.
해당 교재와 이 블로그에서는 이를 기반으로 소켓 프로그래밍을 학습하여 기재한다.



4. 소켓의 타입 (Type)

데이터 전송방식을 의미
소켓이 생성될 때 소켓의 타입도 결정되어야 한다.

  • 프로토콜 체계 PF_INET의 대표적인 소켓 타입
    연결 지향형 소켓 타입 (TCP 소켓) : SOCK_STREAM
    비 연결 지향형 소켓 타입 (UDP 소켓) : SOCK_DGRAM

연결지향형 소켓(SOCK_STREAM)의 데이터 전송특성 : TCP 소켓

  • 중간에 데이터 소멸되지 않는다.
  • 전송 순서대로 데이터가 수신된다.
  • 데이터의 경계가 존재하지 않는다.
  • 소켓 대 소켓의 연결은 반드시 1대1의 구조



비연결지향형 소켓(SOCK_DGRAM)의 데이터 전송특성 : UDP 소켓

  • 전송순서 상관없이 빠른 속도의 전송을 지향
  • 데이터 손실 및 파손의 우려가 있다.
  • 데이터의 경계가 존재한다.
  • 한 번에 전송할 수 있는 데이터의 크기가 제한된다.

데이터 경계

  • TCP 소켓
    전송되는 데이터의 경계(boundary)가 존재하지 않음
    데이터 전송 횟수와 수신 횟수가 일치하지 않음
    1회 최대 전송 크기인 MTU (Maximum Transmission Unit)만큼 전송됨
    Ethernet : 1500 byte

  • UDP 소켓
    전송되는 데이터의 경계(boundary)가 존재함
    데이터 전송 횟수와 수신 횟수가 일치해야 함

프로토콜의 최종 선택 !

// IPv4 인터넷 프로토콜 체계에서 동작하는 연결지향형 데이터 전송 소켓
int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

// IPv4 인터넷 프로토콜 체계에서 동작하는 비 연결지향형 데이터 전송 소켓
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  • 첫 번째, 두 번째 인자로 전달된 정보를 통해서 소켓의 프로토콜이 사실상 결정되기 때문에 세 번째 인자로 0을 전달해도 된다 !
//server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

void error_handling(char *message);

int main(int argc, char *argv[])
{
	int serv_sock;
	int clnt_sock;
	char message[1024];
	int str_len = 0;
	int idx = 0, read_len = 0;

	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;
	
	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");  

	read(clnt_sock,message,sizeof(message));

	printf("Message from client: %s \n",message);
	
	strcat(message,"(From Server)");

	write(clnt_sock, message, strlen(message)+1);
	close(clnt_sock);
	close(serv_sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
//client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.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[] = "2020118198, LeeSeokhwan";
	char recv_msg[1024];
	int str_len=0;
	int idx=0, read_len=0;
	
	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!");

	write(sock, message, sizeof(message));

	while(read_len=read(sock, &recv_msg[idx++], 1))
	{
		if(read_len==-1)
			error_handling("read() error!");
		
		str_len+=read_len;
	}

	printf("Message from server: %s \n", recv_msg);
	printf("Function read call count: %d \n", str_len);
	close(sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

참고 : https://recipes4dev.tistory.com/153
윤성우의 열혈 TCP/IP 소켓 프로그래밍
Git : https://github.com/im2sh/Socket_Programming/tree/main/lab02

profile
반갑습니다.

0개의 댓글