-
소켓으로 문자열 전송 (TCP/IP 통신)개발 지식 2022. 4. 5. 14:14
* 소켓(SOCKET)이란?
출처 : https://helloworld-88.tistory.com/215
소켓은 네트워크로 데이터를 보내거나 네트워크로부터 데이터를 받기 위한 창구 역할을 한다. 그러므로 프로세스가 데이터를 보내거나 받기 위해서는 반드시 소켓을 열어서 소켓에 데이터를 써보내거나 소켓으로부터 데이터를 읽어들여야 한다.
소켓은 프로토콜, IP주소, 포트넘버로 정의된다. 프로토콜은 통신에서 어떤 시스템이 다른 시스템과 통신을 원활하게 수용하도록 해주는 통신 규약을 말한다. IP주소는 전 세계 컴퓨터에 부여된 고유의 식별 주소이다. 포트는 네트워크 상에서 통신하기 위해서 호스트 내부적으로 프로세스가 할당받아야 하는 고유한 숫자이다. 즉 같은 컴퓨터 내에서 프로그램을 식별하는 번호이다.
소켓이란 떨어져 있는 두 호스트를 연결해주는 도구로서 인터페이스 역할을 한다. 데이터를 주고 받을 수 있는 구조체로 소켓을 통해 데이터 통로가 만들어 진다. 이러한 소켓은 역할에 따라 서버 소켓, 클라이언트 소켓으로 구분된다.
IP 주소와 포트 비유 : 각 국가별로 서로 다른 IP를 가진다. 한국 IP로 선박을 통해 물건을 보내는데 어떤 항구로 보내야할까. 항구끼리는 같은 IP를 가지지만 항구 간에는 서로 다른 포트를 가지고 있다. 그래서 가령 한국의 인천항으로 보내기 위해서는 한국 IP와 인천항 포트를 알아야 보낼 수 있는 것이다. AGV 같은 경우, AGV 마다 IP가 있고, AGV 안에서 database와 통신하기 위해서는 해당 AGV의 IP와 database에 해당하는 포트를 알아야 한다.
* 소켓통신의 흐름
- 서버
서버는 클라이언트 소켓의 연결 요청을 기다리고, 연결 요청이 오면 클라이언트 소켓을 생성하여 통신이 가능하게 한다.
1) socket() 함수를 이용하여 소켓을 생성
2) bind() 함수로 ip와 port번호를 설정하게 됩니다. 소켓을 주소에 묶는다.
3) listen() 함수로 클라이언트의 접근 요청에 수신 대기열을 만들어 몇 개의 클라이언트를 대기할지 결정
4) accept() 함수를 사용하여 클라이언트의 요청을 수락하고 소켓을 생성
- 클라이언트
실제로 데이터 송수신이 일어난다.
1) socket() 함수로 가장 먼저 소켓을 연다.
2) connect() 함수를 이용하여 통신 할 서버의 설정된 ip와 port 번호에 통신을 시도
3) 통시을 시도할때 서버가 accept() 함수를 이용하여 클라이언트의 socket descriptor를 반환
4) 이를 통해 클라이언트와 서버가 서로 read(), write()를 하며 통신
* 소켓종류
- 스트림 (TCP)
양방향으로 바이트 스트림을 전송, 연결 지향성
오류 수정, 정송처리, 흐름제어 보장
송신된 순서에 따라 중복되지 않게 데이터를 수신 -> 오버헤드가 발생
소량의 데이터보다 대량의 데이터 전송에 적합 -> TCP를 사용
- 데이터그램 (UDP)
비연결형소켓
데이터의 크기에 제한이 있음
확실하게 전달이 보장되지 않음. 데이터가 손실되어도 오류가 발생하지 않음
실시간 멀티미디어 정보를 처리하기 위해 주로 사용
* HTTP 통신과 SOCKET 통신의 비교
- HTTP 통신
클라이언트의 요청이 있을 때만 서버가 응답하여 해당 정보를 전송하고 곧바로 연결을 종료하는 방식
- HTTP 통신의 특징
클라이언트가 요청을 보내는 경우에만 서버가 응답하는 단방향 통신이다.
서버로부터 응답을 받은 후에는 연결이 바로 종료된다.
실시간 연결이 아니고 필요한 경우에만 서버로 요청을 보내는 상황에 유용하다.
요청을 보내 서버의 응답을 기다리는 어플리케이션의 개발에 주로 사용된다.
- SOCKET 통신
서버와 클라이언트가 특정 포트를 통해 실시간으로 양방향 통신을 하는 방식
- SOCKET 통신의 특징
서버와 클라이언트가 계속 연결을 유지하는 양방향 통신이다.
서버와 클라이언트가 실시간으로 데이터를 주고받는 상황이 필요한 경우에 사용된다.
실시간 동영상 스트리밍이나 온라인 게임 등과 같은 경우에 자주 사용된다.
* 프로토콜
출처 : https://oceancoding.blogspot.com/2020/06/c.html
소켓으로 전송되는 데이터는 문자열, 이미지, 파일 등의 구분할 수 없는 바이너리 형태의 Byte Array 데이터입니다. 따라서 어떤 데이터가 어떤 사이즈로 전송되는지 서버와 클라이언트 간에 약속을 정해야 합니다. 이 약속을 프로토콜이라고 부릅니다.
unsigned long long type (64bit의 경우, 8Byte)인 size_t 사용
TYPE (1 Byte, unsigned char) : 소켓 전송 데이터 타입
DATA_SIZE (8 Byte, size_t) : 소켓 전송 데이터의 크기
DATA (n Byte, signed char) : 소켓에 전송하는 실제 데이터 (문자,이미지,파일)
출처 : https://www.youtube.com/watch?v=PuIy2PzigVM
* 네크워크
송신자와 수신자 사이에 메시지를 주고 받기 위한 것들의 집합
컴퓨터, 전화기, 스마트폰 등은 네트워크 끝에 있는 단말기
단말기 사이에 통신을 위해 스위치, 게이트웨이, 라우터
네트워크의 복잡한 그물망을 구름(cloud)이라고 표현합니다.
1. TCP/IP 네트워크 소개
표준 기구에서는 다양한 통신 모델을 제시하고 있어요. 통신 모델 중에 제일 유명한 OSI 모델(OSI 7계층)
7계층 - Application(응용) 계층
6계층 - Presentatoin 계층 (암호, 압축, 인증)
5계층 - Session 계층 (송신자와 수신자 대화 설정) 송신자 IP:Port - 수신자 IP:Port
4계층 - Transport 계층 (전송 방식을 결정) Stream(연결,순차), DataGram(비연결 데이터단위) - 운영체제에서 기능 제공
3계층 - Network 계층 (망의 ID 결정 및 판단) IP 주소로 송신자와 수신자를 알 수 있음 - 운영체제에서 기능 제공
2계층 - DataLink (네트워크 인터페이스) O/S에서 물리장치로 전달하기 위한 디바이스 드라이버
1계층 - Physical (물리장치) ex. LAN 카드
전송자 단말에서는 7계층에서 1계층으로 그리고 라우터에게 전달.
라우터에서는 목적지가 외부망인지 판별
목적지 라우터에서는 지역망의 단말에게 전달
수신자 단말에서는 1계층에서 7계층으로 처리
이와 같이 각 계층에 따라 맡은 역할을 수행하여 네트워크 통신을 하라는 것이 OSI 모델 (OSI7계층)
계층별 데이터. 계층에 따라 데이터를 부르는 이름이 다릅니다.
5~7 : data, 4 : Message, 3 : Packet, 2 : Frame
네트워크 보안을 다루는 곳에서는 Frame과 Packet 용어를 많이 사용합니다.
소켓 프로그래밍을 하는 개발자는 Packet, Message 용어를 자주 사용합니다.
공통적으로 가장 많이 사용하는 용어는 Packet
통신 모델과 TCP/IP 프로토콜
통신 모델은 표준 기구에 따라 서로 다릅니다. OSI모델, 인터넷 프로토콜 스위트, DoD 모델
DoD 모델은 Network Interface, Internet, Trasport, Application 4개 계층으로 구성
IETF에서는 인터넷 프로토콜 스위프를 제시. 인터넷 5계층(TCP/IP 5계층)이라고 부른다.
모델에 대응하는 TCP/IP 프로토콜은 2:Ethernet, 3:IP, 4:TCP/UDP (인터넷 프로토콜 스위트)
DNS : Domain Name Service
DHCP : 동적 IP 할당
TELNET : 네트워크 관리에 사용하는 터미널 명령
FTP : 파일 전송 프로토콜
HTTP : Hyper Text 전송 프로토콜(웹)
SMTP : Short Message 전송 프로토콜 이메일
우리는 응용에 해당하는 부분을 만든다. 응용 프로토콜은 사용하지 않습니다.
운영체제에서 제공하는 전송 및 네트워크 계층을 사용하는 소켓 라이브러리를 이용해서 개발한다.
송신자 응용 계층과 수시자 응용 계층 사이에 data를 주고 받는 것 - 수평 통신
송신자와 수신자의 Presentation 계층에서 같은 방식으로 암호화, 압축, 인증을 수행 - 수평 통신
송신자와 수신자 사이의 연결. 송신자 IP:Port - 수신자 IP:Port - 수평 통신
이처럼 단말과 단말 사이에 같은 계층끼리의 통신을 수평 통신(프로토콜 스택)이라고 한다.
S/W를 구현할때 하위 계층에서 제공하는 서비스나 기능을 사용하는 것을 수직 통신이라고 한다.
PDI : 패킷 데이터 정보(프로토콜 스택), SDU : 패킷 데이터, ICI : 제어 정보
N계층에서 SDU 앞에 PDI를 붙이고 뒤에 ICI를 붙여서 N-1계층 전달
N-1계층에서는 N계층의 ICI로 오류를 확인. (N) PDI + SDU = (N-1) SDU
N-1계층에서는 다시 앞에 PDI를 붙이고 뒤에 ICI를 붙여서 N-2계층에 전달
N-2계층에서는 수신한 ICI로 오류를 확인 (N-1) PDI + SDU = (N-2) SDU
수직 통신을 하는 과정에서 이처럼 data를 capsulation 합니다.
응용에서 만든 data를 전송 계층에서 메시지에 TCP 프로토콜 스택을 붙이고, 네트워크 계층에서는 IP 프로토콜 스택을 붙이고, DataLink 계층에서는 ethernet 프로토콜 스택을 붙입니다.
이와 같이 capsulation한 Frame을 물리적인 장치로 전달하는 것이죠.
수신하는 곳에서는 역으로 진행합니다. DataLink 계층에서 ethernet 프로토콜 스택을 확인, Network 계층에서 IP 프로토콜 스택을 확인, Transport 계층에서 TCP 프로토콜을 확인.
세션을 통해 Message를 응용에 전달
메시지에 프로토콜 스택을 붙여 나가는 것을 capsulation이라고 한다.
하나씩 프로토콜 스택을 분석 제거하는 것을 decapsulation이라고 한다.
이번 강의는 앞으로 구현할 소켓 통신에 관한 이론 네트워크와 TCP/IP 프로토콜을 알아보았다.
2. 윈도우즈 소켓
소켓은 통신 프로그래밍에 사용하는 입출력 인터페이스. 라이브러리다.
윈도우즈에서 사용하는 소켓은 윈속이라고 부른다. 윈속 2.2를 사용하겠다.
윈속을 사용하기 위해 Winsock2.h 파일을 포함한다.
ws2_32.dll 동적 링커 라이브러리를 사용하겠다는 의미
윈속을 사용 시작과 끝에서 관련 함수를 호출한다. WSAStartup, WSACleanup
* 바이트 정렬
바이트 정렬은 2바이트 이상의 데이터를 메모리에 표현할때 저장하는 방법.
16진수 두자리가 1바이트. 이유) 16진수 한자리는 2진수 네자리로 표현가능. 16진수 두자리는 2진수 여덟자리.
2진수 각 자리당 1pin씩 붙어있으면 데이터 입력 가능. 총 8pin 이니까. 8bit. 1Byte.
big endian은 높은 주소부터 little endian은 낮은 주소부터 기록
대부분 컴퓨터는 little endian. 네트워크 표준은 big endian.
바이트 정렬 변환 함수
호스트(컴퓨터?)와 네트워크 사이의 바이트 정렬을 변환하는 함수들
u_long htonl(u_long hostlong); // host byte order data를 network byte order로 4Byte 데이터를 변환해달라.
u_short htons(u_short hostshort); // ~ 2Byte 데이터를 변환해달라.
u_long ntohl(u_long netlong);
u_short ntohs(u_short netshort);
unsigned int idata = 0x12345678 // 4바이트 변수
unsigned short sdata = 0x1234 // 2바이트 변수
printf("host:%#x network:%#x \n", idata, htonl(idata)); // host:0x12345678 network:0x78563412
printf("host:%#x network:%#x \n", sdata, htons(sdata)); // host:0x1234 network:0x3412
* IPv4 주소 변환
inet_addr 함수는 문자열 주소 표현을 4바이트로 변환 ex. IPv4 문자열 주소 "192.168.34.45" 32비트, 4바이트
inet_ntoa 함수는 4바이트 주소를 문자열 주소로 변환
* 로컬 호스트 IPv4 주소 얻어내기
gethostbyname 함수 호출로 호스트 엔트리를 구합니다.
호스트 엔트리 목록을 조사하여 IPv4를 찾아냅니다.
자주 사용하는 윈속 함수
3. 첫번째 TCP/IP 통신 에코 서버/클라이언트 구현
* 서버 측
TCP 통신에서 서버는 먼저 대기 소켓을 생성합니다.
소켓 생성 후에 네트워크 인터페이스와 결합(bind)합니다. - 네트워크 인터페이스 예시. 랜카드
bind 후에 listen 함수로 백 로그 큐 크기를 설정합니다.
클라이언트 연결 요청 대기 및 수락을 반복합니다.
연결 대기와 연결 수락하는 작업은 accept 함수가 합니다.
accept 함수는 클라이언트와 통신할 소켓을 반환합니다.
대기 소켓 : 처음 생성한 소켓은 클라이언트 연결 요청을 대기하는 소켓
송수신 소켓 : accept 반환 소켓은 클라이언트와 송수신하는 소켓
송수신 소켓으로 클라이언트와 메시지를 주고 받습니다.
연결을 끊을 때 closesocket 함수를 호출합니다.
대기 소켓의 경우 계속 loop를 돌고 있기에 해당 소켓을 닫지 않는 경우가 많다.
* 클라이언트 측
소켓 생성한 후에 bind는 생략할 수 있습니다.
필요가 없다면 굳이 bind를 호출하지 않습니다.
conect 함수로 서버 측 IP:Port로 연결 요청합니다.
연결 후에 서버와 송수신합니다.
메시지 전송은 send, 수신은 recv
끝낼 때는 closesocket 함수로 소켓을 닫습니다.
4. 스레드 사용하여 여러 클라이언트에게 서비스하는 에코 서버
'개발 지식' 카테고리의 다른 글
[개발 지식] 컴파일, 링크, 디버그, 빌드 (0) 2022.04.07 [개발 지식] C/C++ 외부 라이브러리 dll/lib 차이점 (0) 2022.04.07 [개발 지식] visual studio 관련 Debug/Release, x86/x64, 로컬/원격 디버거 (0) 2022.04.07 [개발 지식] 코드에서 해당 파일로 바로가기 단축키 F12 (0) 2022.04.04 [개발 지식] webserver 만들기 (0) 2022.04.04