TCP Socket 编程核心原理

TCP(传输控制协议)是一种面向连接、可靠、基于字节流的传输层协议,在 Socket 编程中,TCP 通信遵循经典的「客户端 - 服务器」

  • 服务器端:负责监听指定端口,等待客户端连接,建立连接后收发数据。
  • 客户端:主动向服务器发起连接请求,连接成功后与服务器交互数据。
  • 核心特点:三次握手建立连接、四次挥手关闭连接、数据重传保证可靠性、拥塞控制。

注意:通信结束后需要关闭连接以释放资源close()

函数作用核心参数
socket.socket()创建 Socket 对象AF_INET(IPv4)、SOCK_STREAM(TCP)
bind()绑定 IP 和端口元组(ip地址, 端口号),如('127.0.0.1', 8888)
listen()开始监听backlog(最大等待连接数)
accept()接受客户端连接返回(conn, addr)(连接对象、客户端地址)
connect()客户端连接服务器元组(服务器IP, 端口号)
recv()接收数据bufsize(每次接收的最大字节数)
send()发送数据需编码为字节流(如data.encode('utf-8')
close()关闭连接

服务器端代码(tcp_server.py)

import socket
import time

def tcp_server():
    # 1. 创建TCP Socket对象(AF_INET=IPv4,SOCK_STREAM=TCP)
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2. 设置端口复用(避免程序重启后端口被占用)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    # 3. 绑定IP和端口(''表示监听所有网卡,8888为自定义端口)
    server_addr = ('', 8888)
    try:
        server_socket.bind(server_addr)
    except OSError as e:
        if "address already in use" in str(e).lower():
            print(f"错误:端口8888已被占用!请关闭占用该端口的程序,或修改端口号。")
            print("Windows查看端口占用:netstat -ano | findstr 8888")
            print("Linux/Mac查看端口占用:lsof -i:8888")
        else:
            print(f"绑定端口失败:{e}")
        # 停留10秒,让你看到错误信息
        time.sleep(10)
        return
    
    # 4. 开始监听(5为最大等待连接数)
    server_socket.listen(5)
    print("="*50)
    print("TCP服务器已启动,监听端口8888...")
    print("提示:请在另一个终端启动客户端,按Ctrl+C关闭服务器")
    print("="*50)
    
    try:
        # 5. 循环接受客户端连接(阻塞式)
        while True:
            # 接受连接,返回新的连接对象(用于收发数据)和客户端地址
            conn, client_addr = server_socket.accept()
            print(f"\n客户端{client_addr}已连接")
            
            # 6. 循环收发数据
            while True:
                # 接收客户端数据,最多1024字节
                recv_data = conn.recv(1024)
                if not recv_data:  # 客户端关闭连接时,recv返回空
                    print(f"客户端{client_addr}已断开连接")
                    break
                
                # 打印接收的内容(解码为字符串)
                print(f"收到客户端{client_addr}消息:{recv_data.decode('utf-8')}")
                
                # 向客户端发送响应数据
                send_data = f"服务器已收到:{recv_data.decode('utf-8')}"
                conn.send(send_data.encode('utf-8'))
    except KeyboardInterrupt:
        print("\n\n检测到Ctrl+C,服务器即将关闭...")
    except Exception as e:
        print(f"\n服务器运行出错:{e}")
    finally:
        # 7. 关闭服务器Socket
        server_socket.close()
        print("服务器已关闭")
        # 停留5秒,避免窗口直接关闭
        time.sleep(5)

if __name__ == "__main__":
    tcp_server()

客户端代码(tcp_client.py)

import socket
import time

def tcp_client():
    # 1. 创建TCP Socket对象
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2. 连接服务器(指定服务器IP和端口)
    server_addr = ('127.0.0.1', 8888)  # 本地测试用127.0.0.1,远程需改服务器实际IP
    print("="*50)
    print(f"正在连接服务器 {server_addr[0]}:{server_addr[1]}...")
    print("提示:若连接失败,请先确认服务器已启动")
    print("="*50)
    
    try:
        client_socket.connect(server_addr)
        print("已成功连接到TCP服务器!")
        print("输入'exit'可退出客户端\n")
        
        # 3. 循环发送数据
        while True:
            # 输入要发送的消息
            send_msg = input("请输入要发送的消息:")
            if send_msg.lower() == 'exit':
                break
            if not send_msg:  # 避免发送空消息
                print("消息不能为空,请重新输入!")
                continue
            
            # 发送数据(需编码为字节流)
            client_socket.send(send_msg.encode('utf-8'))
            
            # 接收服务器响应
            recv_data = client_socket.recv(1024)
            print(f"服务器响应:{recv_data.decode('utf-8')}\n")
    except ConnectionRefusedError:
        print("连接失败:服务器未启动,或IP/端口错误!")
        print("请先运行tcp_server.py启动服务器,再运行客户端")
    except Exception as e:
        print(f"客户端运行出错:{e}")
    finally:
        # 4. 关闭客户端Socket
        client_socket.close()
        print("\n客户端已断开连接")
        # 停留5秒,避免窗口直接关闭
        time.sleep(5)

if __name__ == "__main__":
    tcp_client()

运行步骤:

  • 第一步:执行python tcp_server.py启动服务器;
  • 第二步:执行python tcp_client.py启动客户端;
  • 第三步:在客户端输入消息,服务器会接收并响应,输入exit关闭客户端。


设计一个简易的对话系统

#客户端代码(tcp_client.py)
# coding=UTF-8
import socket  # 导入网络通信模块

# 定义一个问答字典,键是客户端可能发送的消息,值是对应的回复
language = {
    'what is your name': 'I am Tom',
    'how old are you': '19',
    'bye': 'bye'
}

HOST = '127.0.0.1'  # 服务端绑定的IP地址(本地回环地址)
PORT = 6666         # 服务端监听的端口号

# 创建Socket对象,使用IPv4和TCP协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))  # 绑定IP和端口
s.listen(1)           # 开始监听,最多允许1个等待连接

print("Listing at port 6666")
conn, addr = s.accept()  # 接受客户端连接,返回连接对象和客户端地址
print('Connect by: ', addr)

while True:
    data = conn.recv(1024)  # 接收客户端数据,最大1024字节
    data = data.decode()    # 将字节数据解码为字符串
    if not data:            # 如果没有收到数据,退出循环
        break
    print('Received message:', data)
    # 根据客户端消息从字典中获取回复,默认返回'Nothing'
    conn.sendall(language.get(data, 'Nothing').encode())

conn.close()  # 关闭客户端连接
s.close()     # 关闭服务端Socket
#服务器端代码(tcp_server.py)
# coding=UTF-8
import socket, sys

HOST = "127.0.0.1"  # 服务端IP地址(本地回环地址)
PORT = 6666          # 服务端监听的端口号

# 创建Socket对象,使用IPv4和TCP协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    s.connect((HOST, PORT))  # 尝试连接服务端
except Exception as e:
    print('server not found!')  # 连接失败时提示
    sys.exit()  # 退出程序

while True:
    c = input('YOU SAY:')  # 接收用户输入
    s.sendall(c.encode())  # 将输入内容编码为字节并发送给服务端
    data = s.recv(1024)    # 接收服务端返回的数据
    data = data.decode()   # 将字节数据解码为字符串
    print('Received:', data)  # 打印服务端回复
    
    if c.lower() == 'bye':  
        break  # 退出循环,结束通信

s.close()  # 关闭客户端Socket

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐