Python Socket网络编程详解与实践
一:基本概念
服务器:提供服务的一方,负责监听特定端口,等待客户端的连接请求并提供相应服务。 客户端:请求服务的一方,向服务器发起连接请求,与服务器进行数据通信以获取所需服务。 套接字(Socket):网络通信的端点,可理解为网络通信中的一个接口或端口,用于在不同计算机之间发送和接收数据。
三次握手
TCP 三次握手是 TCP/IP 协议族中,建立 TCP 连接时使用的一种机制,用于确保通信双方都准备好进行数据传输,并且能够正常接收和发送数据。以下是对 TCP 三次握手的详细介绍:
第一次握手:客户端发送 SYN 包
客户端向服务器发送一个带有 SYN(Synchronize Sequence Numbers)标志位的 TCP 数据包,该数据包中还会包含一个随机生成的序列号
seq=x
。这个数据包的目的是向服务器表明客户端想要建立一个 TCP 连接,并初始化自己的序列号。第二次握手:服务器发送 SYN+ACK 包
服务器接收到客户端的 SYN 包后,会确认客户端的请求。服务器会向客户端发送一个带有 SYN 和 ACK(Acknowledgment)标志位的 TCP 数据包。其中,SYN 标志位用于初始化服务器到客户端的连接,服务器也会随机生成一个序列号
seq=y
。同时,ACK 标志位用于确认客户端的 SYN 包,确认号ack=x+1
,表示服务器已经成功收到客户端序列号为x
的 SYN 包,期望客户端下一次发送的数据从序列号x + 1
开始。第三次握手:客户端发送 ACK 包
客户端收到服务器的 SYN+ACK 包后,会检查确认号是否正确以及 SYN 标志位是否正确等。如果确认无误,客户端会向服务器发送一个带有 ACK 标志位的 TCP 数据包,确认号
ack=y+1
,表示客户端已经成功收到服务器序列号为y
的 SYN 包,期望服务器下一次发送的数据从序列号y + 1
开始,而客户端自己的序列号则为seq=x+1
。服务器收到这个 ACK 包后,连接就正式建立成功,双方可以开始进行数据传输了。通过这三次握手,客户端和服务器就能够确认彼此的接收和发送能力,从而建立起可靠的 TCP 连接,为后续的数据传输提供了基础。TCP 三次握手的核心目的就是实现通信双方的同步,确保连接的可靠性和稳定性,防止出现数据丢失或混乱等问题。
二.Python 中的 socket 模块
Python 标准库中的
socket
模块用于进行 Socket 编程,常用函数和方法如下:
socket.socket()
:创建一个新的 Socket 对象。socket.bind(address)
:将 Socket 绑定到指定的地址(IP 地址和端口号)。socket.listen(backlog)
:使 Socket 处于监听状态,等待连接请求,backlog
指定了连接队列的最大长度。socket.accept()
:接受连接请求,返回一个新的 Socket 对象和客户端地址。socket.connect(address)
:连接到指定地址的服务器。socket.send(bytes)
:发送数据,参数bytes
是要发送的字节数据。socket.recv(bufsize)
:接收数据,bufsize
指定了接收数据的缓冲区大小。
三.socket编程
3.1 TCP编程
tcp服务器端
import socket
def start_server():
# 创建一个TCP/IP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定Socket到地址(IP地址和端口号)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
# 监听连接请求
server_socket.listen(1)
print('服务器启动,等待连接...')
while True:
# 接受连接请求
client_socket, client_address = server_socket.accept()
try:
print('连接自:', client_address)
# 接收数据
data = client_socket.recv(1024)
print('接收到的数据:', data.decode())
# 发送响应数据
response = 'HTTP/1.0 200 OK\r\n\r\nHello, World!'
client_socket.sendall(response.encode())
finally:
# 关闭连接
client_socket.close()
if __name__ == '__main__':
start_server()
tcp客户端
import socket
def start_client():
# 创建一个TCP/IP Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
server_address = ('localhost', 65432)
print('连接到服务器:', server_address)
client_socket.connect(server_address)
try:
# 发送数据
message = 'GET / HTTP/1.0\r\n\r\n'
print('发送数据:', message)
client_socket.sendall(message.encode())
# 接收响应数据
data = client_socket.recv(1024)
print('接收到的数据:', data.decode())
finally:
# 关闭连接
client_socket.close()
if __name__ == '__main__':
start_client()
3.2 UDP编程
udp服务器端
import socket
udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_server.bind(('127.0.0.1', 9090))
print("UDP服务器启动中...")
while True:
data, addr = udp_server.recvfrom(1024)
print(f"来自 {addr} 的消息:{data.decode()}")
udp_server.sendto(b"消息已收到", addr)
udp客户端
import socket
udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 9090)
message = "你好,服务器!"
udp_client.sendto(message.encode(), server_address)
response, _ = udp_client.recvfrom(1024)
print(f"服务器响应:{response.decode()}")
udp_client.close()
四.模拟ssh协议实现命令执行并返回执行结果
客户端代码
# -*- coding: utf-8 -*-
# Author: s0rin
import socket
import time
def main(target,port):
sk = socket.socket()
sk.connect((target,port))
while True:
date = input("输入命令>>>")
sk.send((date.encode()))
#版本1
res = sk.recv(1024)
print("字节长度:",len(res))
print("执行命令结果:{}".format(res.decode()))
#版本2
cmd_ret_bytes_len=sk.recv(1024)
cmd_res_len = int(cmd_ret_bytes_len.decode())
recv_num=0
while recv_num<cmd_res_len:
data = sk.recv(1024)
print(data.decode())
recv_num+=len(data)
print("data的长度:",recv_num,cmd_res_len)
if __name__ == '__main__':
target = "127.0.0.1"
port = 6666
main(target,port)
服务端代码
# -*- coding: utf-8 -*-
# Author: s0rin
import socket
import subprocess
import time
import struct
def main(ip_port):
sock = socket.socket()
sock.bind((ip_port))
sock.listen(10)
while True:
conn ,addr = sock.accept()
print("客户端{}建立连接".format(addr))
while True:
cmd = conn.recv(1024)
if not cmd:
print(f"{conn.getpeername()}客户端推出")
print("执行命令",cmd.decode("gbk"))
#版本1
cmd_ret_bytes = subprocess.getoutput(cmd).encode()
conn.send(cmd_ret_bytes)
#版本2
cmd_ret_bytes = subprocess.getoutput(cmd).encode()
print("响应字节数",len(cmd_ret_bytes))
cmd_ret_bytes_len = str(len(cmd_ret_bytes)).encode()
conn.send(cmd_ret_bytes_len)
conn.send(cmd_ret_bytes)
if __name__ == '__main__':
ip_port = ("127.0.0.1",6666)
main(ip_port)
作者:S_Sorin