网络编程(socket)
一、Socket模块
1、简介:封装了网络编程所需的代码,提供接口供用户使用
2、客户端编程流程:(1)、定义socket类 (2)、连接到服务器 (3)、接收数据 (4)、关闭客户端
3、服务端编程流程:(1)、定义socket类 (2)、绑定IP、端口 (3)、开始监听 (4)、接收客户端数据 (5)、接发数据 (6)、关闭服务端
4、无论是server还是client,最好接收数据不超过8192K
5、发送前数据会放到缓冲区,从缓冲区发送到client的条件是:(1)、缓冲区满(默认情况) (2)、超时
例子如下:
import socket def main(): client = socket.socket() # 定义了一个socket类,并且提供了一个连接 client.connect(('localhost', 6969)) # 连接地址,端口,用元组 client.send(b'Hello World') # 发送数据 data = client.recv(1024) # 接收数据 print(data) if __name__ == '__main__': main()
import socket def main(): server = socket.socket() server.bind(('localhost', 6969)) # 绑定端口 server.listen() # 监听端口 print('我在等电话') conn, addr = server.accept() # 接受请求,conn为客户端连接实例,addr为地址,相当于要等电话 print('电话来了') data = conn.recv(1024) # 接受conn发送请求,此处默认是阻塞 print(data) conn.send(data.upper()) # 向conn发送数据 server.close()
以下对上述例子进行改进,客户端可一直与服务器通话:
server.py
import socket def main(): server = socket.socket() server.bind(('localhost', 6969)) # 绑定端口 server.listen() # 监听端口 print('我在等电话') conn, addr = server.accept() # 接受请求,conn为客户端实例,addr为地址 print('电话来了') while True: try: data = conn.recv(1024) # 接受conn发送请求 print('recv:', data) conn.send(data.upper()) # 向conn发送数据 except ConnectionResetError: break server.close() if __name__ == '__main__': main()
client.py
import socket def main(): client = socket.socket() # 定义了一个socket类,并且提供了一个连接 client.connect(('localhost', 6969)) # 连接地址,端口,用元组 while True: send_str = input('输入发送的字符串:') client.send(send_str.encode('utf-8')) # 发送数据 data = client.recv(1024) # 接收数据 print('recv:', data.decode('utf-8')) client.close() if __name__ == '__main__': main()
以下例子只需要改变服务端,但客户端1断开时客户端2再连上
import socket def main(): server = socket.socket() server.bind(('localhost', 6969)) # 绑定端口 server.listen() # 监听端口,里面的参数为监听的个数 print('我在等电话') while True: conn, addr = server.accept() # 接受请求,conn为客户端实例,addr为地址 print('电话来了') while True: try: data = conn.recv(1024) # 接受conn发送请求 print('recv:', data) conn.send(data.upper()) # 向conn发送数据 except ConnectionResetError: break server.close() if __name__ == '__main__': main()
注意:客户端发送的空数据,服务器收不了
以下例子能实现客户端发送命令,服务器端返回命令结果
client.py
import socket def main(): client = socket.socket() # 定义了一个socket类,并且提供了一个连接 client.connect(('localhost', 6969)) # 连接地址,端口,用元组 while True: send_str = input('输入发送的字符串:') client.send(send_str.encode('utf-8')) # 发送数据 data = client.recv(102400) # 接收数据 print(data.decode('utf-8')) client.close() if __name__ == '__main__': main()
server.py
import socket import os def main(): server = socket.socket() server.bind(('localhost', 6969)) # 绑定端口 server.listen() # 监听端口,里面的参数为监听的个数 print('我在等电话') while True: conn, addr = server.accept() # 接受请求,conn为客户端实例,addr为地址 print('电话来了') while True: try: data = conn.recv(1024) # 接受conn发送请求 data = data.decode('utf-8') com_res = os.popen(data).read() conn.send(com_res.encode('utf-8')) # 向conn发送数据 except ConnectionResetError: break server.close() if __name__ == '__main__': main()
以下程序能实现服务器发文件,客户端收文件,但由于客户端收文件大小有限,故不能一次发送完
server.py
import socket def main(): server = socket.socket() server.bind(('localhost', 6969)) # 绑定端口 server.listen() # 监听端口,里面的参数为监听的个数 print('我在等电话') while True: conn, addr = server.accept() # 接受请求,conn为客户端实例,addr为地址 print('电话来了') with open('test.rar', 'rb') as f: conn.sendall(f.read()) server.close() if __name__ == '__main__': main()
client.py
import socket def main(): client = socket.socket() # 定义了一个socket类,并且提供了一个连接 client.connect(('localhost', 6969)) # 连接地址,端口,用元组 f = open('test_client.rar', 'wb') while True: send_str = input('输入发送的字符串:') client.send(send_str.encode('utf-8')) # 发送数据 data = client.recv(1024000) # 接收数据 f.write(data) client.close() if __name__ == '__main__': main()
粘包:网络中,程序里有两个send语句放在一起,两个send的数据合并一起一并发送。
如下:
server.py

1 def main(): 2 server = socket.socket() 3 server.bind(('localhost', 6969)) 4 server.listen() 5 while True: 6 conn, addr = server.accept() 7 print('新客户端:', addr) 8 while True: 9 rec_data_byte = conn.recv(1024) 10 if len(rec_data_byte) == 0: 11 print('客户端已断开!') 12 break 13 else: 14 rec_data_str = rec_data_byte.decode('utf-8') 15 cmd_res_str = os.popen(rec_data_str).read() 16 if not cmd_res_str: 17 cmd_res_str = '没有此命令' 18 conn.send(str(len(cmd_res_str.encode('utf-8'))).encode('utf-8')) 19 conn.send(cmd_res_str.encode('utf-8')) 20 print('\033[1;31m发送完成\033[0m') 21 server.close() 22 23 24 if __name__ == '__main__': 25 main()
client.py

1 def main(): 2 client = socket.socket() 3 client.connect(('localhost', 6969)) 4 while True: 5 send_str = input('>>:').strip() 6 if send_str: 7 send_byte = send_str.encode('utf-8') 8 client.send(send_byte) 9 total_cmd_res_size_int = int(client.recv(1024)) 10 print('总共需要接收\033[1;31m%s\033[0m字节' % total_cmd_res_size_int) 11 total_cur_recv_size = 0 12 while total_cur_recv_size < total_cmd_res_size_int: 13 recv_data = client.recv(1024) 14 total_cur_recv_size += len(recv_data) 15 print(recv_data.decode('utf-8', errors='ignore')) 16 else: 17 print('I have received \033[1;31m%s\033[0m字节!' % total_cur_recv_size) 18 client.close() 19 20 21 if __name__ == '__main__': 22 main()
粘包解决方法:
(1)、在两个send中间加一个等待时间time.sleep(0.5),但不建议,会卡顿感。
(2)、可在两个send中接收对方的一条数据。
以下例子模拟客户端从ftp服务器下载数据,并且经过md5校验。
server.py

1 import socket 2 import os 3 import hashlib 4 5 6 def main(): 7 server = socket.socket() 8 server.bind(('localhost', 6969)) 9 server.listen() 10 while True: 11 conn, addr = server.accept() 12 print('新客户端:', addr) 13 while True: 14 try: 15 # 接收客户端命令 16 com_byte = conn.recv(1024) 17 except ConnectionResetError: 18 # 处理客户端断开 19 print('客户端已断开') 20 break 21 # 获取文件名 22 file_name = com_byte.decode('utf-8').split(' ')[1] 23 # 判断文件是否存在 24 if os.path.isfile(file_name): 25 m = hashlib.md5() 26 # 获取文件大小 27 file_size = os.stat(file_name)[6] 28 # print(file_size) 29 # print(type(file_size)) 30 # 发送文件大小给客户端 31 conn.send(str(file_size).encode('utf-8')) 32 # 收到客户端的回复 33 conn.recv(1024) 34 f = open(file_name, 'rb') 35 for line in f: 36 m.update(line) 37 conn.send(line) 38 conn.send(m.hexdigest().encode('utf-8')) 39 print('\033[1;31m发送完成\033[0m') 40 f.close() 41 server.close() 42 43 44 if __name__ == '__main__': 45 main()
client.py

1 import socket 2 import hashlib 3 4 5 def main(): 6 client = socket.socket() 7 client.connect(('localhost', 6969)) 8 while True: 9 # 提示输入命令 10 cmd_str = input('>>:').strip() 11 if cmd_str.startswith('get'): 12 file_name = cmd_str.split(' ')[1] 13 cmd_byte = cmd_str.encode('utf-8') 14 # 发送命令给服务器 15 client.send(cmd_byte) 16 # 获取下载文件大小 17 file_size = int(client.recv(1024)) 18 client.send('我已经准备好了接收'.encode('utf-8')) 19 print('总共需要接收\033[1;31m%s\033[0m字节' % file_size) 20 # 总接收大小 21 received_size = 0 22 f = open(file_name + '.new', 'wb') 23 m = hashlib.md5() 24 # 循环接收数据 25 while received_size < file_size: 26 # 不是最后一次收数据 27 if file_size - received_size > 1024: 28 size = 1024 29 # 最后一次收数据 30 else: 31 size = file_size - received_size 32 recv_data = client.recv(size) 33 m.update(recv_data) 34 received_size += len(recv_data) 35 f.write(recv_data) 36 else: 37 print('\033[1;31m下载文件完成\033[0m') 38 print('从服务器端收到的md5是', client.recv(1024).decode('utf-8')) 39 print('本地文件的md5是', m.hexdigest()) 40 f.close() 41 client.close() 42 43 44 if __name__ == '__main__': 45 main()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」