Giao Thức Socket Trong Lập Trình Mạng: Cơ Bản Và Ứng Dụng

Khái Niệm Cơ Bản Về Socket

Socket xuất phát từ hệ điều hành Unix, tuân theo triết lý "mọi thứ đều là tập tin". Đây là cơ chế cho phép xử lý mạng thông qua các thao tác mở, đọc, ghi và đóng tương tự như tập tin. Socket thực chất là một loại tập tin đặc biệt, với các hàm xử lý (IO, mở, đóng) dành riêng cho giao tiếp mạng.

Socket là nền tảng cho mọi kết nối mạng. Khi bạn truy cập http://www.example.com, trình duyệt sẽ tạo socket để kết nối, nhận phản hồi và hiển thị trang. Tương tự, các ứng dụng chat như Slack cũng sử dụng socket để truyền dữ liệu.

Phân Loại Socket

Loại Mô Tả
AF_INET Giao tiếp mạng giữa các máy chủ (IPv4)
AF_INET6 Giao tiếp mạng IPv6
SOCK_STREAM Socket luồng (giao thức TCP)
SOCK_DGRAM Socket gói tin (giao thức UDP)

Các Hàm Socket Chính

Phương Thức Giao Tiếp

  • bind(): Liên kết socket với địa chỉ và cổng
  • listen(): Chấp nhận kết nối TCP (tham số hàng đợi)
  • accept(): Xử lý kết nối mới (trả về socket và địa chỉ client)
  • connect(): Thiết lập kết nối tới server
  • recv(): Nhận dữ liệu (TCP)
  • send(): Gửi dữ liệu (TCP)
  • recvfrom(): Nhận dữ liệu (UDP)
  • sendto(): Gửi dữ liệu (UDP)

Ví Dụ Server/Client Cơ Bản

Server (server.py)

import socket
import threading

def start_server():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(('0.0.0.0', 5555))
    server_socket.listen(8)
    
    print("Chờ kết nối...")
    
    while True:
        client_conn, client_addr = server_socket.accept()
        client_thread = threading.Thread(target=handle_client, args=(client_conn, client_addr))
        client_thread.start()

def handle_client(conn, addr):
    conn.send(b"Chào mừng đến máy chủ!")
    while True:
        data = conn.recv(1024)
        if not data or data == b'quit':
            break
        print(f"Nhận từ {addr}: {data.decode()}")
        conn.send(f"Phản hồi: {data.decode()}".encode())
    conn.close()

if __name__ == "__main__":
    start_server()

Client (client.py)

import socket

def start_client():
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('127.0.0.1', 5555))
    print(client_socket.recv(1024).decode())
    
    while True:
        msg = input("Nhập tin nhắn: ").encode()
        client_socket.send(msg)
        if msg == b'quit':
            break
        print("Phản hồi:", client_socket.recv(1024).decode())
    
    client_socket.close()

if __name__ == "__main__":
    start_client()

Truyền Tệp Qua Socket

Server (file_server.py)

import socket
import struct
import os

def handle_file_transfer(conn):
    header_size = struct.calcsize('128sQ')
    header = conn.recv(header_size)
    filename, filesize = struct.unpack('128sQ', header)
    filename = filename.decode().strip('\x00')
    
    with open(f"received_{filename}", 'wb') as f:
        bytes_received = 0
        while bytes_received < filesize:
            chunk = conn.recv(min(1024, filesize - bytes_received))
            f.write(chunk)
            bytes_received += len(chunk)
    
    print(f"Đã nhận file: {filename}")
    conn.close()

def start_file_server():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(('0.0.0.0', 6666))
    server.listen(5)
    
    print("Chờ kết nối nhận file...")
    while True:
        conn, addr = server.accept()
        handle_file_transfer(conn)

if __name__ == "__main__":
    start_file_server()

Client (file_client.py)

import socket
import struct
import os

def send_file(filename):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(('127.0.0.1', 6666))
    
    file_size = os.path.getsize(filename)
    header = struct.pack('128sQ', filename.encode(), file_size)
    client.send(header)
    
    with open(filename, 'rb') as f:
        while chunk := f.read(1024):
            client.send(chunk)
    
    print(f"Đã gửi file: {filename}")
    client.close()

if __name__ == "__main__":
    send_file("test.jpg")

SocketServer: Framework Xây Dựng Server

SocketServer cung cấp lớp trừu tượng để xây dựng server mạng nhanh chóng, hỗ trợ đa luồng và đa tiến trình.

Thiết Kế Lớp

  • ThreadingTCPServer: Server TCP đa luồng
  • ForkingUDPServer: Server UDP đa tiến trình

Ví Dụ Server Đa Người Dùng

import socketserver
import logging

class MultiUserHandler(socketserver.BaseRequestHandler):
    clients = {}
    
    def setup(self):
        self.clients[self.client_address] = self.request
        logging.info(f"Kết nối mới từ {self.client_address}")
    
    def handle(self):
        while True:
            data = self.request.recv(1024).decode()
            if data == 'exit':
                break
            for addr, sock in self.clients.items():
                if addr != self.client_address:
                    sock.send(f"[{self.client_address}] {data}".encode())
    
    def finish(self):
        del self.clients[self.client_address]
        logging.info(f"Kết nối {self.client_address} đóng")

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    server = socketserver.ThreadingTCPServer(('0.0.0.0', 7777), MultiUserHandler)
    server.serve_forever()

Thẻ: Python Socket Network Programming Threading Server

Đăng vào ngày 24 tháng 5 lúc 11:10