1、简介
- Socket(套接字)是网络编程中用于描述IP地址和端口的一个抽象概念,通过它可以实现不同主机间的通信。套接字可以分为几种不同的类型,每种类型对应不同的协议和传输模式。
1.1、基本概念
- IP地址:用于标识网络中的计算机或设备。
- 端口:用于标识计算机上的特定服务或进程。
- 套接字:IP地址和端口的组合,用于实现网络通信。
1.2、套接字类型
- 流式套接字(Stream Socket):基于TCP(Transmission Control Protocol)协议,提供面向连接、可靠的字节流服务。适用于需要高可靠性的数据传输场景,如HTTP、FTP等。
- 数据报套接字(Datagram Socket):基于UDP(User Datagram Protocol)协议,提供无连接、不可靠的消息传递服务。适用于对实时性要求较高,但对可靠性要求较低的场景,如视频传输、在线游戏等。
- 原始套接字(Raw Socket):允许直接访问底层协议,如IP、ICMP等,通常用于网络诊断和开发网络协议。
1.3、编程基本步骤
- 创建套接字
-
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建一个TCP/IP套接字 # socket.AF_INET:表示使用IPv4地址。 # socket.SOCK_STREAM:表示使用TCP协议。
-
- 绑定地址和端口
-
s.bind(('localhost', 8080)) # 绑定到本地地址和端口
-
- 监听连接(服务器端特有)
-
s.listen(5) # 开始监听,最多允许5个连接排队
-
- 接受连接(服务器端特有)
-
conn, addr = s.accept() # 接受一个客户端连接 print('Connected by', addr)
-
- 连接服务器(客户端特有)
-
s.connect(('localhost', 8080)) # 连接到服务器
-
- 发送和接收数据
-
s.sendall(b'Hello, world') # 发送数据 data = s.recv(1024) # 接收数据
-
- 关闭套接字
-
s.close() # 关闭套接字
-
2、过程
- 准备一个FTP服务器,这里使用LightFTP。安装和启动过程参考:FTP协议——LightFTP安装(Linux)_lwftp-CSDN博客
- 首先准备好要发送的消息(十六进制),可以使用wireshark捕获。
- 由于我的LightFTP是安装在虚拟机中,套接字程序是在本机中运行的,所以目的ip地址要填虚拟机的ip地址。
-
import socket import struct def send_to_server(server_ip, server_port, messages): try: # 创建一个 TCP/IP 套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接到服务器 server_address = (server_ip, server_port) print(f"Connecting to {server_ip} port {server_port}") sock.connect(server_address) # 接受连接响应 response = sock.recv(4096) if response is not None: print(f"Received response for message: {response}") try: for i, message in enumerate(messages): # 发送消息 print(f"Sending message {i + 1}: {message}") sock.sendall(message) # 接收服务器的响应 response = sock.recv(4096) print(f"Received response for message {i + 1}: {response}") finally: # 关闭套接字 print("Closing connection") sock.close() except Exception as e: print(f"An error occurred: {e}") # 转换消息格式 def transform(msg): strInput = msg # 输入的十六进制字符串 dataSend = b"" # 初始化一个空的字节对象,用于存储转换后的二进制数据 shortInput = "" # 初始化一个空字符串,用于暂存每两个字符 cnt = 1 # 初始化计数器,记录字符位置 for chInput in strInput: shortInput += chInput # 将当前字符添加到 shortInput if cnt % 2 == 0: # 如果计数器是偶数,表示已经收集到两个字符 intInput = int(shortInput, 16) # 将两个字符的十六进制字符串转换为整数 dataSend += struct.pack(">B", intInput) # 将整数打包为一个字节,并添加到 dataSend shortInput = "" # 清空 shortInput,准备下一次收集两个字符 cnt += 1 # 增加计数器 return dataSend # 返回转换后的二进制数据 if __name__ == "__main__": server_ip = '192.168.182.130' # 改为FTP服务器的ip server_port = 21 # FTP 服务器默认端口是 21 # 十六进制消息 msgs = [ '555345522077656261646d696e0d0a', # 登录用户名 '50415353203232320d0a', # 密码 '4c4953540d0a' # ls ] messages = [transform(msg) for msg in msgs] send_to_server(server_ip, server_port, messages)
-
- 运行结果: