Hướng dẫn Triển khai Giao tiếp Client-Server với Mã hóa
Giới thiệu
Bài viết này hướng dẫn cách xây dựng ứng dụng giao tiếp mạng giữa máy khách và máy chủ sử dụng Socket trong Python, đồng thời trình bày kỹ thuật mã hóa dữ liệu trước khi truyền qua mạng.
Phần 1: Xây dựng Server và Client cơ bản
1.1. Chuẩn bị môi trường
Trước tiên, cần xác định địa chỉ IP của máy tính. Mở terminal và chạy lệnh sau:
ipconfig
Ghi lại địa chỉ IPv4 từ adapter WLAN để sử dụng cho kết nối.
1.2. Mã nguồn Client
Dưới đây là code client sử dụng giao thức TCP:
import socket
# Khởi tạo đối tượng socket
client_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Thiết lập địa chỉ server
server_host = 'localhost'
server_port = 8888
# Kết nối đến server
client_conn.connect((server_host, server_port))
print(f"Đã kết nối đến server {server_host}:{server_port}")
# Vòng lặp giao tiếp
while True:
# Nhận tin nhắn từ người dùng
outgoing_msg = input('Nhập tin nhắn gửi cho server: ')
client_conn.send(outgoing_msg.encode('utf-8'))
# Nhận phản hồi từ server
incoming_data = client_conn.recv(1024).decode('utf-8')
if not incoming_data:
break
print(f'Server phản hồi: {incoming_data}')
# Kiểm tra điều kiện thoát
if input("Tiếp tục? Y/N: ").upper() == "N":
break
# Đóng kết nối
client_conn.close()
print("Đã đóng kết nối")
1.3. Mã nguồn Server
import socket
# Khởi tạo socket server
server_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Gắn địa chỉ và cổng
server_host = 'localhost'
server_port = 8888
server_conn.bind((server_host, server_port))
# Lắng nghe kết nối
server_conn.listen(1)
print(f'Server đang lắng nghe tại {server_host}:{server_port}')
# Chấp nhận kết nối từ client
client_conn, client_addr = server_conn.accept()
print(f"Chấp nhận kết nối từ {client_addr}")
# Vòng lặp xử lý tin nhắn
while True:
# Nhận dữ liệu từ client
incoming_data = client_conn.recv(1024).decode('utf-8')
if not incoming_data:
break
print(f'Client gửi: {incoming_data}')
# Gửi phản hồi cho client
response_msg = input('Nhập phản hồi gửi cho client: ')
client_conn.send(response_msg.encode('utf-8'))
# Kiểm tra điều kiện dừng
if input("Tiếp tục? Y/N: ").upper() == "N":
break
# Đóng các kết nối
client_conn.close()
server_conn.close()
print("Server đã dừng")
1.4. Cách chạy chương trình
- Chạy file server trước để khởi động service
- Chạy file client để kết nối đến server
- Hai bên có thể trao đổi tin nhắn theo thời gian thực
Phần 2: Mã hóa File trước khi Truyền
2.1. Cài đặt thư viện mã hóa
Cài đặt thư viện pycryptodome để sử dụng các thuật toán mã hóa:
pip install pycryptodome
2.2. Thuật toán XOR Cipher
XOR cipher là thuật toán mã hóa đối xứng đơn giản, sử dụng phép XOR bitwise giữa ký tự trong plaintext và key:
def xor_encrypt(text, secret_key):
"""Mã hóa văn bản bằng thuật toán XOR"""
encrypted_result = ""
for idx in range(len(text)):
# XOR từng ký tự với ký tự tương ứng trong key (lặp lại key nếu cần)
encrypted_result += chr(ord(text[idx]) ^ ord(secret_key[idx % len(secret_key)]))
return encrypted_result
def xor_decrypt(encrypted_text, secret_key):
"""Giải mã văn bản đã mã hóa - cùng logic với mã hóa do tính chất khả nghịch của XOR"""
decrypted_result = ""
for idx in range(len(encrypted_text)):
decrypted_result += chr(ord(encrypted_text[idx]) ^ ord(secret_key[idx % len(secret_key)]))
return decrypted_result
# Ví dụ sử dụng
sample_text = "Hello, World!"
secret_key = "mykey"
encrypted = xor_encrypt(sample_text, secret_key)
print(f"Bản mã: {encrypted}")
decrypted = xor_decrypt(encrypted, secret_key)
print(f"Bản rõ: {decrypted}")
Nguyên lý hoạt động: Do tính chất (A ^ B) ^ B = A, việc XOR hai lần với cùng key sẽ khôi phục văn bản gốc.
2.3. Mã hóa AES-CBC
AES-CBC là chế độ mã hóa an toàn hơn sử dụng khối mã hóa AES với Initialization Vector (IV):
import os
# Khóa bí mật dùng chung - phải là 16, 24 hoặc 32 byte
SHARED_KEY = b'SecureKey123456' # 16 bytes
def encode_data(plaintext):
"""
Mã hóa dữ liệu sử dụng AES-CBC
Trả về: IV (16 bytes) + ciphertext
"""
iv = os.urandom(16) # Tạo IV ngẫu nhiên 16 bytes
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
cipher_obj = AES.new(SHARED_KEY, AES.MODE_CBC, iv)
# Padding theo chuẩn PKCS7
padded_data = pad(plaintext, AES.block_size)
ciphertext = cipher_obj.encrypt(padded_data)
return iv + ciphertext
def decode_data(encrypted_package):
"""
Giải mã dữ liệu đã mã hóa
Input: IV (16 bytes) + ciphertext
"""
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
iv = encrypted_package[:16]
ciphertext = encrypted_package[16:]
cipher_obj = AES.new(SHARED_KEY, AES.MODE_CBC, iv)
decrypted_padded = cipher_obj.decrypt(ciphertext)
return unpad(decrypted_padded, AES.block_size)
2.4. Client gửi File đã mã hóa
import socket
from crypto_utils import encode_data # Import hàm mã hóa từ phần trên
# Thiết lập kết nối TCP
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
target_host = 'localhost'
target_port = 8888
client_socket.connect((target_host, target_port))
print("Đã kết nối đến server")
# Đọc file gốc
source_file = 'data_original.txt'
with open(source_file, 'rb') as f:
raw_data = f.read()
# Mã hóa dữ liệu
encrypted_package = encode_data(raw_data)
print(f"Đã mã hóa {len(raw_data)} bytes dữ liệu")
# Gửi dữ liệu đã mã hóa
client_socket.sendall(encrypted_package)
print("Đã gửi file đã mã hóa")
client_socket.close()
2.5. Server nhận và giải mã File
import socket
from crypto_utils import decode_data
# Khởi tạo server
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bind_host = 'localhost'
bind_port = 8888
server_socket.bind((bind_host, bind_port))
server_socket.listen(1)
print(f"Server lắng nghe tại {bind_host}:{bind_port}")
# Chấp nhận kết nối
client_conn, remote_addr = server_socket.accept()
print(f"Nhận kết nối từ {remote_addr}")
# Nhận dữ liệu theo từng chunk
received_data = b''
while True:
chunk = client_conn.recv(4096)
if not chunk:
break
received_data += chunk
# Giải mã và lưu file
try:
decoded_content = decode_data(received_data)
output_file = 'data_received.txt'
with open(output_file, 'wb') as f:
f.write(decoded_content)
print(f"Đã giải mã và lưu file: {output_file}")
except Exception as error:
print(f"Lỗi giải mã: {str(error)}")
client_conn.close()
server_socket.close()
Phần 3: Quản lý Code với Git
3.1. Thiết lập Git repository
- Tạo repository mới trên nền tảng Git (GitHub/Gitee/GitLab)
- Sao chép URL repository
- Trong IDE, sử dụng lệnh git clone để tải repository về máy local
3.2. Commit và Push code
# Thêm các file vào staging
git add .
# Tạo commit với mô tả
git commit -m "Thêm chức năng mã hóa file"
# Đẩy code lên remote repository
git push origin main
Kết luận
Bài viết đã trình bày các kỹ thuật cơ bản trong lập trình mạng với Socket Python, bao gồm:
- Giao thức TCP cho giao tiếp client-server
- Thuật toán XOR cipher cho mã hóa đơn giản
- AES-CBC cho mã hóa bảo mật cao hơn
- Các thao tác file trong Python
- Quản lý code với Git
Tài liệu tham khảo
- Python Documentation - socket module
- PyCryptodome Documentation
- Tài liệu về AES-CBC mode