|
http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=8578 [복사]
-IPv4의 기초 -
IPv4는 2024년도인 현재까지도 쓰이고 있는 IP주소체계이다.
32비트의 크기를 가지며 수학적으로 계산해보면 32비트는 3의 32승,
정확히 4,294,967,296개의 주소를 가진다.
42억개가 넘는 주소가 모두 쓰이는 건 아니며 약 30억개가 조금 넘는
IP주소가 네트워크 주소로 할당될 수 있다.
IPv6는 2의 128승개의 주소를 할당받을 수 있다.
이번 글의 코딩 언어는 Python으로 작성되었음을 미리 알린다.
- 네트워크 프로그램의 기본 통신 절차 -
-- 서버 -- -- 클라이언트 --
socket() : 소켓 생성 socket()
bind() : 네트워크 정보 할당
listen() : 연결 대기
accept() : 연결 허용 conenct()
read() / write() : 읽고 쓰기 read() / write()
close() : 통신 종료 close()
파이썬 소켓 프로그래밍 서버측 예제
==============================================
import socket
# 서버 설정
host = "0.0.0.0" # 서버의 IP 주소 또는 도메인 이름
port = 12345 # 포트 번호
# 서버 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((host, port))
server_socket.listen(5)
print(f"서버가 {host}:{port}에서 대기 중입니다...")
while True:
# 클라이언트 연결 대기
client_socket, client_address = server_socket.accept()
print(f"클라이언트 {client_address}가 연결되었습니다.")
try:
# 클라이언트로부터 요청 받기
data = client_socket.recv(1024).decode("utf-8")
if not data:
continue
# 요청 파싱
parts = data.split("&&")
if len(parts) != 0:
name = parts[0]
message = parts[1]
response = f"어서와! {name}"
# 클라이언트 이름과 메시지 출력
print(f"클라이언트 이름: {name}")
print(f"클라이언트 메시지: {message}")
else:
response = "유효하지 않은 요청"
# 응답 클라이언트에게 전송
client_socket.send(response.encode("utf-8"))
except Exception as e:
print(f"오류 발생: {e}")
finally:
# 클라이언트 소켓 닫기
print("연결종료")
client_socket.close()
========================================
파이썬 소켓 프로그래밍 클라이언트 예제
========================================
import socket
# 서버 설정
server_address = "서버IP" # 서버의 실제 IP 주소 또는 도메인 이름
server_port = 12345 # 서버 포트 번호
# 서버에 연결
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((server_address, server_port))
# 데이터 전송
name = "미니몬"
message = "안녕, 서버!"
request = f"{name}&&{message}"
client_socket.send(request.encode("utf-8"))
# 서버로부터 응답 받기
response = client_socket.recv(1024).decode("utf-8")
print(f"{name} : {message}")
print(f"서버 : {response}\n")
# 클라이언트 소켓 닫기
client_socket.close()
==============================================
- 소켓 생성 -
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket함수는 소켓 생성을 한다.
네트워크를 전화통신에 비유하자면 소켓 생성을 하는 거은
전화기를 설치하는 것과 같다.
시스템이 통신을 하려면 일단 소켓을 생성해야 한다.
AF_INE : IPv4를 의미하는 인자값이다.
SOCK_STREAM은 TCP통신을 하겠다는 의미인데
TCP는 연결지향형, 안전성 강조이며 수신자 측에서 하나의 데이터가 네트워크를 통하여
상대의 시스템이나 서버에 패킷이 도착하면 송신자 시스템, 서버에서
도착했다는 데이터를 수신자에게 보낸다.
Three way handshake의 개념이다.
데이터를 송수신하는 소켓은 내부적으로 버퍼(buffer), 쉽게말해 바이트 배열을 지니고 있다.
그리고 소켓을 통해 전송되는 데이터는 일단 이 배열에 저장된다.
때문에 데이터가 수신되었다고 해서 바로 read 함수를 호출해야 하는 것은 아니다.
이 배열의 용량을 초과하지 않는 한,
데이터가 채워진 후에 한번의 read 함수 호출을 통해서 데이터 전부를 읽어 들일 수 있고,
반대로 한버의 write 함수 호출로 전송된 데이터 전부를 여러번의 read 함수로 읽어 들일 수 있다.
즉, read 함수의 호출 횟수와 write 함수의 호출 횟수는
연결지향형 소켓의 경우 큰 의미를 갖지 못한다.
때문에 연결지향형 소켓은 데이터의 경계가 존재하지 않는다고 말하는 것이다.
SOCK_DGRAM : 인자값으로 쓰는 경우, UDP통신을 하겠다는 의미이며
UDP는 비연결지향형, 빠른 통신을 하겠다는 뜻이다.
유튜브나 생방송같은 스트리밍 서비스가 UDP를 이용한다.
- 소켓 주소 할당
... bind() is used to associate the socket with the server address.
bind()은 소켓을 서버 주소와 연결하는 데 사용된다.
출처 : 스택 오버플로우
C에선 bind()를 하려면 여러가지 코드를 작성해야 한다.
예시로 아래와 같다.
.
.
.
if(bind( server_socket, (struct sockaddr*)&server_addr, sizeof( server_addr))==-1)
{
fputs("bind() error!\n", stderr);
exit( 1);
}
.
.
.
struct sockaddr_in server_addr;
memset( &server_addr, 0, sizeof( server_addr);
server_addr.sin_family = AF_INET; // IPv4 인터넷 프로토롤
server_addr.sin_port = htons( 4000); // 사용할 port 번호는 4000
server_addr.sin_addr.s_addr = htonl( INADDR_ANY); // 32bit IPV4 주소
하지만 위 예제의 파이썬 코드는 C처럼 복잡하지 않다.
C로 소켓을 배운 필자는 파이썬이 간결한 걸 보고
"혹시, 파이썬이 로우 소켓 프로그래밍과 같은 걸 지원하지 않나?"라고
생각이 들었다.
그에 대한 해답은 아래의 링크에서 볼 수 있다.
https://docs.python.org/ko/3/library/socket.html
- 연결 대기 -
server_socket.listen(5)
listen안의 5라는 인자는 연결대기 포트를 5개를 만든다.
파이썬 소켓 프로그래밍에서 listen() 함수는
서버 소켓이 클라이언트의 연결 요청을 받아들일 수 있는 상태로 만들어주는 함수다.
이 함수의 인자값은 대기열의 길이를 나타낸다.
이 대기열은 동시에 수용할 수 있는 연결 요청의 최대 개수를 결정한다.
대기열이 가득 찬 상태에서 클라이언트가 연결을 시도하면
서버는 연결을 거부하게 된다.
일반적으로는 대기열의 크기를 서버의 예상 처리량과
시스템 자원에 따라 적절히 조절하여야 합니다.
- 연결 수용 -
server_socket.accept()
서버 소켓이 클라이언트의 연결 요청을 받아들이고
해당 요청에 대한 연결 소켓과 클라이언트의 주소를 반환하는 함수.
이 함수는 클라이언트가 서버에 연결되기를 기다리고 있는 상태에서 호출된다.
호출 시점에서 클라이언트가 연결 요청을 보내면
accept()는 연결된 소켓과 클라이언트의 주소를 튜플로 반환한다.
반환된 소켓을 통해 서버와 클라이언트 간의 통신이 이루어진다.
만약 연결 요청이 없을 경우,
이 함수는 클라이언트의 연결 요청이 도착할 때까지 블로킹된다.
|
Hit : 3600 Date : 2024/05/26 11:11
|