7. 네트워크 프로그래밍 (계속)
7.5. 멀티스레딩과 소켓 프로그래밍
7.5.1. 멀티스레딩 개념 이해
7.5.1.1. 스레드와 프로세스의 차이
프로세스는 운영체제로부터 자원을 할당받아 독립적으로 실행되는 작업의 단위를 말합니다. 반면, 스레드는 프로세스 내에서 실행되는 독립적인 실행 흐름입니다. 즉, 같은 프로세스 내의 스레드들은 코드, 데이터 섹션 등을 공유하며 실행됩니다.
7.5.1.2. Python에서의 멀티스레딩 활용
Python에서는 threading 모듈을 이용해 멀티스레딩을 구현할 수 있습니다. 다음은 간단한 멀티스레딩 예제입니다:
import threading
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for letter in 'abcdefghijklmnopqrstuvwxyz':
print(letter)
# 두 개의 스레드 생성
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)
# 스레드 시작
t1.start()
t2.start()
# 모든 스레드가 종료될 때까지 대기
t1.join()
t2.join()
7.5.2. 멀티스레드 소켓 프로그래밍
7.5.2.1. 멀티스레드 소켓 프로그래밍의 필요성
멀티스레드 소켓 프로그래밍은 서버가 동시에 여러 클라이언트의 요청을 처리할 수 있게 해 줍니다. 즉, 한 클라이언트의 요청을 처리하는 동안 다른 클라이언트의 요청이 대기 상태에 빠지지 않게 해 줍니다.
7.5.2.2. Python에서의 멀티스레드 소켓 프로그래밍 구현
Python에서는 socket과 threading 모듈을 함께 사용하여 멀티스레드 소켓 서버를 구현할 수 있습니다. 다음은 간단한 예제입니다:
import socket
import threading
def handle_client(client_socket):
request = client_socket.recv(1024)
print(f'Received: {request}')
client_socket.send(b'ACK')
client_socket.close()
def server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 9999))
server_socket.listen(5)
while True:
client, _ = server_socket.accept()
client_thread = threading.Thread(target=handle_client, args=(client,))
client_thread.start()
server()
위 코드는 각 클라이언트 별로 별도의 스레드를 생성하여 독립적으로 처리할 수 있도록 합니다. 이를 통해 서버는 여러 클라이언트의 요청을 동시에 처리할 수 있습니다.
아래는 클라이언트 코드입니다:
import socket
def client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('0.0.0.0', 9999))
client_socket.send(b'Hello from client')
response = client_socket.recv(1024)
print(f'Received: {response}')
client()
클라이언트는 서버에 연결한 후, 메시지를 보내고 응답을 받습니다. 이때, 서버에서는 각 클라이언트 요청을 별도의 스레드에서 처리하기 때문에, 여러 클라이언트가 동시에 요청을 보내더라도 서버는 이를 적절히 처리할 수 있습니다.
이처럼 멀티스레드 소켓 프로그래밍은 네트워크 프로그래밍에서 중요한 개념으로, 특히 서버 설계 시에 많이 활용됩니다. 다만, 멀티스레드 프로그래밍은 동시성 제어, 동기화 문제 등 복잡한 이슈를 수반하기 때문에, 실제 구현 시에는 주의가 필요합니다.
7.6. 웹 소켓 프로그래밍
웹 소켓 프로그래밍은 실시간 양방향 통신이 필요한 웹 애플리케이션 개발에서 중요한 역할을 합니다.
7.6.1. 웹 소켓 개념 이해
7.6.1.1. 웹 소켓의 정의와 특징
웹 소켓은 웹 서버와 클라이언트 간에 실시간 양방향 통신을 가능하게 하는 기술입니다. HTTP와 달리, 웹 소켓은 한 번 연결되면 연결이 유지되며, 서버와 클라이언트는 서로에게 데이터를 즉시 보낼 수 있습니다.
웹 소켓의 주요 특징은 다음과 같습니다:
- Full-duplex: 웹 소켓은 양방향 통신을 지원합니다. 즉, 서버와 클라이언트는 동시에 서로에게 데이터를 보낼 수 있습니다.
- Real-time: 웹 소켓은 실시간 통신을 지원합니다. 데이터는 발생 즉시 전송됩니다.
- Persistent connection: 웹 소켓은 지속적인 연결을 유지합니다. 한 번 연결되면, 연결은 수동으로 종료되거나 네트워크 오류가 발생할 때까지 유지됩니다.
7.6.1.2. 웹 소켓과 HTTP의 차이점
HTTP는 요청-응답 모델을 기반으로 하며, 클라이언트가 서버에 요청을 보내고 서버가 응답을 반환합니다. 이와 달리, 웹 소켓은 지속적인 연결을 유지하고 양방향 통신을 지원합니다.
또한, HTTP는 텍스트 기반 프로토콜이지만, 웹 소켓은 텍스트와 이진 데이터 모두를 지원합니다. 이로 인해 웹 소켓은 더 효율적인 데이터 전송이 가능합니다.
7.6.2. Python에서의 웹 소켓 구현
Python에서 웹 소켓을 구현하려면, websocket 라이브러리를 사용할 수 있습니다.
7.6.2.1. 웹 소켓 서버 구현
import asyncio
import websockets
async def server(websocket, path):
message = await websocket.recv()
print(f"Received: {message}")
await websocket.send("Hello from server")
start_server = websockets.serve(server, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
``
7.6.2.2. 웹 소켓 클라이언트 구현
웹 소켓 클라이언트는 서버에 연결하여 데이터를 주고 받을 수 있습니다. Python에서 websockets 라이브러리를 사용하면 웹 소켓 클라이언트를 쉽게 구현할 수 있습니다.
아래 코드는 웹 소켓 클라이언트의 간단한 예시입니다:
import asyncio
import websockets
async def client():
uri = "ws://localhost:8765"
async with websockets.connect(uri) as websocket:
await websocket.send("Hello from client")
response = await websocket.recv()
print(f"Received: {response}")
asyncio.get_event_loop().run_until_complete(client())
위의 코드는 웹 소켓 서버에 "Hello from client" 메시지를 보낸 다음, 서버로부터의 응답을 기다립니다. 서버로부터 응답을 받으면, 응답 메시지를 출력합니다.
주의사항 : 위의 코드는 해당 주소("ws://localhost:8765")에 웹 소켓 서버가 실행 중이라는 가정하에 동작합니다. 실제로 코드를 실행하기 전에 웹 소켓 서버가 해당 주소에서 실행 중인지 확인하십시오.
이처럼 Python에서 웹 소켓을 이용한 프로그래밍은 비교적 간단하며, 실시간, 양방향 통신이 필요한 다양한 상황에서 활용할 수 있습니다. 이를 통해 채팅 애플리케이션, 실시간 알림 시스템 등 다양한 서비스를 구현할 수 있습니다.
7.7. 네트워크 보안 기본
7.7.1. 네트워크 보안 이해
7.7.1.1. 네트워크 보안의 필요성
네트워크 보안은 개인 정보, 기업의 민감한 데이터, 정부의 기밀 정보 등을 보호하는 데 중요합니다. 해커들은 여러 가지 방법으로 시스템을 공격하여 데이터를 탈취하거나 시스템을 마비시키려고 합니다. 이런 공격들로부터 시스템을 보호하는 것이 네트워크 보안의 주요 목표입니다.
7.7.1.2. 주요 네트워크 공격 유형과 대응 방법
- DDoS 공격 : 분산 서비스 거부(DDoS) 공격은 서버에 엄청난 양의 트래픽을 보내서 서버를 마비시키는 공격 방법입니다. 이를 방지하기 위해 트래픽 모니터링 도구를 사용하거나, CDN(Content Delivery Network)을 활용하는 등의 방법이 있습니다.
- 중간자 공격(Man-In-The-Middle Attack) : 공격자가 통신하는 두 당사자 사이에 끼어들어 정보를 도청하거나 조작하는 공격입니다. 이를 방지하기 위해 SSL/TLS와 같은 암호화 프로토콜을 사용하여 통신 내용을 암호화합니다.
- SQL 인젝션 : 악의적인 SQL 코드를 웹 폼이나 URL에 삽입하여 데이터베이스를 공격하는 방법입니다. 이를 방지하기 위해 입력 값에 대한 검증, 파라미터화된 쿼리 사용 등의 방법을 사용합니다.
7.7.2. Python에서의 네트워크 보안 적용
7.7.2.1. SSL/TLS를 이용한 보안 통신
SSL(Secure Sockets Layer) 및 TLS(Transport Layer Security)는 통신 내용을 암호화하여 네트워크 공격으로부터 보호하는 프로토콜입니다. 이 프로토콜을 사용하면 데이터를 안전하게 전송할 수 있습니다.
7.7.2.2. Python에서의 SSL/TLS 적용 방법
Python에서는 ssl 모듈를 사용하여 SSL/TLS를 적용할 수 있습니다. ssl 모듈은 소켓을 SSL 소켓으로 변환하여 데이터를 암호화하고, 인증된 연결을 통해 데이터를 전송합니다.
예제 코드를 살펴봅시다.
import socket, ssl
def handle_client(conn):
print(conn.recv())
conn.write(b'Hello client!')
conn.close()
sock = socket.socket()
sock.bind(('localhost', 8443))
sock.listen(5)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="path/to/certfile", keyfile="path/to/keyfile")
while True:
client_sock, addr = sock.accept()
conn = context.wrap_socket(client_sock, server_side=True)
handle_client(conn)
이 코드는 SSL/TLS를 사용하여 클라이언트와 통신하는 서버를 생성합니다. context.wrap_socket 메서드를 사용하여 일반 소켓을 SSL 소켓으로 변환합니다. 이때, server_side=True 인자는 이 소켓이 서버 측에서 사용되는 것임을 나타냅니다.
주의사항 : SSL/TLS를 사용하려면 인증서가 필요하다는 것입니다. 인증서를 생성하는 방법은 다양하지만, 보통은 신뢰할 수 있는 인증서 발급 기관(CA)에게 발급받습니다. 위의 예제에서는 load_cert_chain 메서드를 사용하여 인증서 파일을 불러옵니다.
이렇게 Python에서 ssl 모듈을 사용하면 네트워크 통신에 보안을 적용할 수 있습니다.
7.7.2.2. Python에서의 SSL/TLS 적용 방법
Python에서 SSL/TLS를 사용하는 것은 소켓을 SSL 소켓으로 변환하여 데이터를 암호화하고, 인증된 연결을 통해 데이터를 전송하는 것을 가능하게 합니다. 이 과정은 상당히 복잡할 수 있지만, Python의 ssl 모듈은 이를 쉽게 만들어줍니다.
예제로, Python에서 SSL/TLS를 사용하여 HTTPS 서버를 만드는 방법을 살펴보겠습니다.
from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
keyfile="path/to/key.pem",
certfile='path/to/cert.pem',
server_side=True)
httpd.serve_forever()
이 코드는 SimpleHTTPRequestHandler를 사용하여 간단한 HTTP 서버를 만든 후, ssl.wrap_socket()을 사용하여 이 서버의 소켓을 SSL 소켓으로 변환합니다. keyfile과 certfile 매개변수는 각각 서버의 개인 키와 공개 키를 포함하는 파일의 경로를 지정합니다. 이 둘은 일반적으로 인증서 발급 기관(CA)으로부터 받습니다.
마지막으로, server_side=True는 이 소켓이 서버 측에서 사용됨을 나타냅니다. 이렇게 하면, 클라이언트는 이 서버와의 모든 통신을 암호화하고, 서버의 인증서를 사용하여 서버의 신원을 확인할 수 있습니다.
2023.05.11 - [GD's IT Lectures : 기초부터 시리즈/파이썬(Python) 기초부터 ~] - [파이썬(PYTHON) : 중급] 네트워크 프로그래밍
'GD's IT Lectures : 기초부터 시리즈 > 파이썬(Python) 기초부터 ~' 카테고리의 다른 글
[파이썬(PYTHON) : 고급] 메타프로그래밍 (0) | 2023.05.12 |
---|---|
[파이썬(PYTHON) : 중급] 동시성과 병렬성 (0) | 2023.05.11 |
[파이썬(PYTHON) : 중급] 네트워크 프로그래밍 (0) | 2023.05.11 |
[파이썬(PYTHON) : 중급] 데이터 처리 및 분석 (0) | 2023.05.11 |
[파이썬(PYTHON) : 중급] 파일과 디렉토리 처리 (0) | 2023.05.10 |
댓글