Python网络编程入门:Socket基础、通信流程与代码实现
本文详解Python网络编程基础,涵盖Socket库的核心语法、常用函数及通信流程。通过服务端与客户端的交互示例,演示如何绑定IP端口、建立连接、收发数据,并逐步实现通信循环与多客户端并发处理,帮助开发者掌握Python网络编程的核心技能。
一、什么是网络编程
网络编程涉及计算机基础理论与操作系统差异。由于示例基于Windows环境,后续内容均适用于Windows系统,且需注意Windows与macOS在字符编码上的区别。本文首先实现简单的服务端发送、客户端接收功能,后续将扩展至模拟SSH远程命令处理及粘包问题,最终实现文件下载功能。
网络编程的核心理论包括网络基础与五层协议模型。这些理论解释了文件在客户端与服务端之间的传输机制及接收过程。本质上,这是客户端(接收方)与服务端(发送方)之间的交互过程。建议读者结合专业教程深入理解,但无论细节如何,核心始终在于建立这种交互连接。
二、Socket套接字
Python的强大功能很大程度上得益于丰富的第三方库,其中Socket(套接字)库是实现网络通信的关键。专业而言,应用程序通过“套接字”向网络发出请求或应答,从而实现主机间或同一计算机上进程间的通信。利用Socket库,即可实现前文所述的客户端与服务端交互。
1. Socket的基本语法
socket(family,type,[protocol])
创建Socket时,family参数有三种可选值。
socket.AF_UNIX 仅适用于单一Unix系统进程间通信。
socket.AF_INET 用于服务器之间的网络通信。
socket.AF_INET6 IPv6
type参数同样有三种选项。
socket.SOCK_STREAM 流式Socket,使用TCP协议时选择此项。
socket.SOCK_DGRAM数据报式Socket,使用UDP协议时选择此项。
socket.SOCK_RAW 原始套接字。普通套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;此外,SOCK_RAW也能处理特殊的IPv4报文。利用原始套接字,可通过IP_HDRINCL选项由用户构造IP头。
protocol参数指明接收的协议类型,通常为0或不填,一般无需设置。
2. 与Socket相关的常用函数
服务端相关函数
address通常指本机IP地址,可通过Windows命令提示符输入ipconfig命令查看IPv4地址获取。
s.bind(address)将套接字绑定到地址。在客户端程序中,需绑定IP和端口才能实现交互。
s.listen(backlog)设置操作系统允许挂起的最大连接数量,即服务端最多能处理的并发连接数。
s.accept()接受TCP连接并返回(conn, address)。其中conn是新的套接字对象,用于接收和发送数据;address是连接客户端的地址。
客户端相关函数
s.connect(address)连接到指定address处的套接字。
s.recv(bufsize)接收TCP套接字的数据。数据以字符串形式返回,bufsize指定接收的最大数据量。
公共函数
s.send(string)
发送TCP数据。将string中的数据发送到连接的套接字,返回值为实际发送的字节数,可能小于string的字节大小。
s.sendall(string)
完整发送TCP数据。将string中的数据发送到连接的套接字,在返回前会尝试发送所有数据。成功返回None,失败则抛出异常。
s.recvfrom(bufsize)
接收UDP套接字的数据。与recv()类似,但返回值为(data, address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
s.sendto(string,address)
发送UDP数据。将数据发送到套接字,address为(ipaddr, port)形式的元组,指定远程地址。返回值为发送的字节数。
s.close()
关闭套接字。
三、程序需求分析
网络交互可类比生活中的打电话:发送数据相当于拨号,接收数据相当于接听。由此区分服务端和客户端,以下场景将演示这种交互过程。
服务端分析
要实现数据发送,首先需引入Socket库。服务端需执行一系列绑定操作,利用前述函数实现。具体流程包括:模拟手机(引入Socket)、绑定IP端口(插卡)、开机监听、等待连接、收发消息及挂断电话。
注意事项:
1. 绑定操作前,需通过命令提示符输入ipconfig命令获取本机IPv4地址。
2. 绑定地址时需指定端口号,端口号可任意选择,但若被占用需更换其他端口。
3. 在接收消息后,可使用upper()函数将客户端发送的数据转换为大写后返回给客户端。
4. 客户端使用accept()接收TCP连接并返回(conn, address)。
--------------------------------服务端----------------------
import socket
#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone) #测试你的手机
#2.插卡 绑定手机卡
phone.bind(("192.168.2.18",3234))
#3.开机
phone.listen(5) #5代表最大挂起的连接数
#4.等电话链接
print("starting")
conn,client_add = phone.accept()
# 5.收发消息
data=conn.recv(1024) #1024代表接收数据的最大数,单位是bits
print("客户端数据",data)
conn.send(data.upper())
#6.挂电话
conn.close()
#7.关机
phone.close()客户端分析
服务端与客户端是一一对应的。在收发消息环节,客户端发送小写“hello”,服务端则返回大写“HELLO”。
-------------------------------客户端-----------------------------
import socket
#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
#2.拨号
phone.connect(("192.168.2.18",3234))
#3.发收消息
phone.send("hells".encode("utf"))
data=phone.recv(1024)
print(data)
phone.close()四、代码升级与优化
加入通信循环
前述代码仅实现固定收发,功能过于简单。为实现客户端与服务端之间的循环通信及自定义内容交互,需加入输入处理与循环逻辑。
----------------------------服务端------------------------
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
phone.bind(("172.20.10.4",3234))
phone.listen(5) print("starting")
conn,client_add = phone.accept()
print(client_add)
while True:
data=conn.recv(1024)
print("客户端数据",data)
conn.send(data.upper())
conn.close()
phone.close()----------------------------------客户端------------------------
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
phone.connect(("172.20.10.4",3234))
while True:
msg = input(">>>:").strip()
phone.send(msg.encode("utf-8"))
data=phone.recv(1024)
print(data)
phone.close()如前所述,我们在客户端加入了循环输入功能。在服务端加入相应循环后,即可实现持续的循环输入与响应。
加入连接循环及完善处理
之前的程序是一个客户端对应一个服务端。实际应用中,服务端应能同时处理多个客户端的数据收发。主要修改服务端代码,客户端代码变化不大,仅需增加数据发送判断。
1. 由于未学习并发编程,代码通过循环实现:服务端接收完一个客户端数据后,可继续接收另一个客户端的数据。
2. 增加一行代码判断端口是否被占用,以减少错误发生。
3. 增加客户端后,需判断是否需要接收其他客户端的数据,或多客户端是否都发送了数据。因此,需使用try和except进行异常处理与判断。
--------------------------------服务端-----------------------
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #判断接口是否被占用
phone.bind(("172.20.10.4",3234))
phone.listen(5)
print("starting")
while True: #没有学习并发编程 没办法执行代码后返回到这继续执行,所以用循环解决
conn,client_add = phone.accept()
print(client_add)
while True:
try:
data=conn.recv(1024)
if not data:break
print("客户端数据",data)
conn.send(data.upper())
except ConnectionResetError :
break
conn.close()
phone.close()-----------------客户端1-----------------
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("172.20.10.4",3234))
while True:
msg = input(">>>:").strip()
if not msg: continue #若输入空则继续循环
phone.send(msg.encode("utf-8"))
# print("if send none")
data=phone.recv(1024)
print(data)
# print(data.decode("utf-8"))
phone.close()-----------------------------客户端2---------------------
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("172.20.10.4",3234))
while True:
msg = input(">>>:").strip()
if not msg: continue #若输入空则继续循环
phone.send(msg.encode("utf-8"))
# print("if send none")
data=phone.recv(1024)
print(data)
# print(data.decode("utf-8"))
phone.close()总结
本文到此结束,希望能对您有所帮助。欢迎继续关注本站获取更多内容!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









