Skip to content
0

文章发布较早,内容可能过时,阅读注意甄别。

Socket编程

1 python实现

1.1 TCP协议

1、服务器代码

python
# === TCP 服务端程序 ===

# 导入socket 库
from socket import *
import threading

# 主机地址为0.0.0.0, 表示绑定本机所有网络接口ip地址
# 主机地址127.0.0.1表示主机环回地址
# 等待客户端来连接
IP = '127.0.0.1'
# IP = '10.26.2.3'
# 端口号
PORT = 50000
# 定义一次从socket缓冲区最多读入512个字节数据
BUFFER = 512

# 实例化一个socket对象
# 参数 AF_INET表示该socket网络层使用IP协议
# 参数SOCK_STREAM 表示socket传输层使用tcp协议
server_socket = socket(AF_INET, SOCK_STREAM)

# socket绑定地址和端口
server_socket.bind((IP, PORT))

# 使用socket处于监听状态, 等待客户端的连接请求
# 参数5表示,最多接收多少个等待连接的客户端
server_socket.listen(5)
print(f"{IP}服务端启动成功, 在{PORT}端口等待客户端连接...")


# 定义处理客户端连接的函数
def handle_client(client_socket, addr):
    print(f'接收一个客户端连接: {addr}')
    try:
        while True:
            # 尝试读取对方发送的消息
            data = client_socket.recv(BUFFER)
            if not data:
                # 如果返回空bytes,表示对方关闭了连接
                break
            # 读取的字节数据解码为字符串
            info = data.decode()
            print(f'收到客户端{addr}发来的信息: {info}')
            # 发送响应,编码为bytes
            client_socket.send(f'服务端接收到了信息 {info}'.encode())
    finally:
        # 关闭客户端连接
        client_socket.close()
        print(f'断开客户端连接: {addr}')

try:
    # 主循环,接受客户端连接
    while True:
        client_socket, addr = server_socket.accept()
        # 为每个客户端连接创建一个新线程
        client_thread = threading.Thread(target=handle_client, args=(client_socket, addr))
        client_thread.start()
except KeyboardInterrupt:
    # 当用户按下Ctrl+C时,退出程序
    print("服务器正在关闭...")
finally:
    server_socket.close()
    print("套接字已关闭。")

# listenSocket.close()

2、客户机代码

python
# === TCP客户端程序 ===
from socket import *

# IP = '127.0.0.1'
IP = '10.26.2.3'
SERVER_PORT = 50000
BUFFER = 512

# 实例化一个socket对象,指明协议
dataSocket = socket(AF_INET, SOCK_STREAM)

# 连接服务端socket
dataSocket.connect((IP, SERVER_PORT))
print(f"已经和服务器{IP}:{SERVER_PORT}建立TCP连接")

while True:
    # 从终端读入用户输入的字符串
    toSend = input('>>')
    if toSend == 'exit':
        print(f"和服务器{IP}:{SERVER_PORT}断开TCP连接")
        break
    # 发送消息,也要编码为bytes
    dataSocket.send(toSend.encode())

    # 等待接收服务端的消息
    recved = dataSocket.recv(BUFFER)
    # 如果返回空bytes, 表示对方关闭了连接
    if not recved:
        break
    # 打印读取的信息
    print(recved.decode())

dataSocket.close()

1.2 UDP协议

1、服务器代码

python
# === UDP 服务端程序 ===

# 导入socket 库
from socket import *

# 主机地址为0.0.0.0, 表示绑定本机所有网络接口ip地址
# 主机地址127.0.0.1表示主机环回地址
# IP = '127.0.0.1'
IP = '10.26.2.3'
# 端口号
PORT = 50000
# 定义一次从socket缓冲区最多读入512个字节数据
BUFFER = 512

# 实例化一个socket对象
# 参数 AF_INET表示该socket网络层使用IP协议
# 参数SOCK_DGRAM 表示socket传输层使用udp协议
udpSocket = socket(AF_INET, SOCK_DGRAM)

# socket绑定地址和端口
udpSocket.bind((IP, PORT))
print(f"{IP}服务端启动成功, 在{PORT}端口等待客户端连接...")


try:
    while True:
        # UDP不需要accept连接,直接从缓冲区读取数据报
        data, addr = udpSocket.recvfrom(BUFFER)

        # 读取的字节数据是bytes类型, 需要解码为字符串
        info = data.decode()
        print(f'收到来自 {addr} 的信息: {info}')

        # 发送的数据类型必须是bytes, 所以要编码
        response = f'服务端接收到了信息 {info}'.encode()
        udpSocket.sendto(response, addr)  # 使用sendto方法发送数据报,需要指定目标地址
except KeyboardInterrupt:
    # 当用户按下Ctrl+C时,退出程序
    print("服务器正在关闭...")
finally:
    udpSocket.close()
    print("套接字已关闭。")

# UDP服务器通常不需要显式关闭socket,除非要立即停止服务
# 但为了代码整洁,可以在必要时关闭socket
# udpSocket.close()

2、客户机代码

python
# === UDP客户端程序 ===
from socket import *

# IP = '127.0.0.1'
IP = '10.26.2.3'
SERVER_PORT = 50000
BUFFER = 512

# 实例化一个socket对象,指明协议为UDP
udpSocket = socket(AF_INET, SOCK_DGRAM)

# UDP客户端不需要显式连接服务端,因为它发送的是数据报
# 数据报自带目标地址和端口信息

while True:
    # 从终端读入用户输入的字符串
    toSend = input('>> ')
    if toSend.lower() == 'exit':  # 允许用户输入'exit'或'EXIT'等不区分大小写的退出指令
        print(f"和服务器{IP}:{SERVER_PORT}断开连接")
        break

    # 发送消息,也要编码为bytes
    udpSocket.sendto(toSend.encode(), (IP, SERVER_PORT))

    # 等待接收服务端的消息
    # UDP是无连接的,recvfrom会阻塞直到接收到数据报
    data, server = udpSocket.recvfrom(BUFFER)

    # 打印读取的信息
    print(data.decode())

# UDP客户端通常不需要显式关闭socket,但为了代码整洁,可以在退出前关闭它
udpSocket.close()

WARNING

1、服务器和客户机的IP地址和端口需要对应

2、运行的时候需要先运行服务器socket代码,再运行客户机socket代码

最近更新