Python网络编程基础
IP地址ip地址表现形式查看ip地址LinuxWindows 检查网络是否正常 端口与端口号端口号分类知名端口号动态端口号 TCP协议概念TCP通讯步骤特点 socket套接字TCP客户端程序开发步骤1:创建客户端程序的套接字对象socket模块导入 socket类socket对象创建 2:和服务端程序建立连接connect方法 3:发送数据字符串编码encode() send方法 4:接收数据recv方法字符串解码decode() 5:关闭客户端程序的套接字close方法 客户端程序代码汇总: TCP服务端程序开发步骤1:创建服务端程序的套接字对象2:绑定端口号bind方法设置端口号复用 3:设置监听listen()方法 4:等待接受客户端程序的连接请求accept()方法 5:接收数据6:发送数据7:关闭服务端程序的套接字服务端程序代码汇总: 多任务版服务端程序IP地址
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。 IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
换而言之,IP 地址就是标识网络中设备的一个地址,好比现实生活中某家公司的办公地址。通过办公地址,能找到某家公司。类似的,通过IP地址,能够找到想找的某台能够进行网络通信的设备。
ip地址表现形式
IP 地址分为两类:IPv4和IPv6
IPv4 是目前正在使用的ip地址。它由4段.
分隔的十进制数字组成,每一段最大不超过255。(点分十进制)
互联网蓬勃发展,ip地址需求量迅速增大,为了避免ip地址用完,人们又设计出新的ip地址定义。IPv6出现。
IPv6由8段用:
分隔的十六进制数字组成,每一段不超过四位。(冒号十六进制)
IPv6一劳永逸地解决了ip地址不够的问题,还改善了IPv4的不少问题。
不过,现在还不急于推广IPv6。IPv4尚且够用。所以说,IPv6是未来使用的ip地址。
查看ip地址
查看ip地址的方式有很多,这里介绍终端命令行方式。
Linux
ifconfig
全称:network interfaces configuringens33,lo表示网卡名ens33表示以太网,其inet表示设备在网络中的ip地址lo全称“loopback”,表示“回环”网络接口。它不代表真正的网络接口,而是一个虚拟的网络接口, 其 IP 地址默认是127.0.0.1,通常仅用于对本机的网络测试。域名(通常意义上的网址)是ip地址的别名,通过域名可以解析出对应的ip地址。如域名localhost
表示回环地址127.0.0.1。
Windows
ipconfig
检查网络是否正常
ping 域名/ip地址
ping 检查是否能上公网(外部网络)ping 当前局域网的ip地址 检查是否在同一个局域网内ping 127.0.0.1 检查本地网卡是否正常正常的话会显示接收数据不正常的话什么都没有,光标一直在等待
端口与端口号
端口(port),又称为连接端口、协议端口(protocol port)。端口是数据传输的通道。
通过ip地址找到某台网络设备后,要想与某个特定的程序(进程)进行数据传输,就要找到该程序(进程)对应的端口,通过端口,进行数据传输。
端口号是操作系统为了统一管理各程序的端口而编的号。端口号共有65536个。
ip地址相当于公司的办公地址,通过办公地址找到公司后,要想和公司的某个部门通信,就要找到部门的”门“,这个“门”就是端口,门牌号就是端口号。
端口号分类
每个端口号唯一对应一个端口。但端口可以供不同的程序使用。程序运行时都要绑定一个端口,占用并使用一个端口号。
知名端口号
知名端口号是指众所周知的端口号,范围从0到1023。
这些端口号一般固定分配给一些系统服务进程,比如21端口分配给FTP(文件传输协议)服务,25端口分配给SMTP(简单邮件传输协议)服务,80端口分配给HTTP服务。
动态端口号
一般程序员开发应用程序可以使用的端口号称为动态端口号, 范围是从1024到65535。
如果程序员开发的程序没有特意设置端口号,操作系统会在动态端口号的范围内随机生成一个端口号给开发的应用程序使用。
运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就会被释放,可以供其他程序使用。如果没有特殊的端口绑定操作的话,下次不一定就是这个。
TCP协议
前面我们已经学习了
ip地址 → \rightarrow → 网络设备 → \rightarrow → 端口号 → \rightarrow → 端口 → \rightarrow → 进程
可通过ip地址和端口号凯定位某个特定进程
进程之间进行数据传输,这是两者之间的事情。
我们需要一个协议,来确保数据传输能够按照某一规则成功进行。
TCP协议就是其中之一。
概念
TCP协议(Transmission Control Protocol),即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
面向连接:TCP协议要求数据传输的双方进程只有在两者的端口之间建立有效连接后,才能进行数据传输。
可靠:字面意思。
基于字节流:可以传输大量二进制数据。
TCP通讯步骤
建立连接
传输数据
断开连接
特点
面向连接 通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源。 可靠传输 TCP 采用发送应答机制(三次握手建立连接,四次握手断开连接)超时重传错误校验流量控制和阻塞管理socket套接字
实现数据传输,需要一个工具,它可以与端口绑定,负责数据传输的一切事务。
它就是socket套接字(英文意思为插座)。
socket负责实现进程之间的网络数据传输,好比数据的搬运工。
socket聚合了一系列与数据传输有关的函数
connect()bind()listen()accept()send()recv()close()
TCP客户端程序开发
步骤
创建客户端程序的套接字对象和服务端程序建立连接发送数据接收数据关闭客户端程序的套接字1:创建客户端程序的套接字对象
socket模块
socket模块是python内置的处理socket的类
导入
import socket
socket类
socket对象创建
client_socket=socket.socket(AddressFamily, Type)
AddressFamily
代表ip地址类型
目前一般选择socket.AF_INET
Type
代表socket
类型
TCP协议下的程序选择socket.SOCK_STREAM
返回socket套接字对象这里用client_socket
接收
所以最常见的这行代码是:
client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
2:和服务端程序建立连接
connect方法
client_socket.connect(_address)
_address是一个元组,格式为(host,port)。host是服务器ip地址(字符串),port是端口号。connect方法可以与ip地址为host,端口为port的服务端程序建立连接
如:
client_socket.connect(("192.168.147.1",8080))
3:发送数据
TCP协议要求只能发送二进制数据。
字符串编码
直接发送字符串是不行的,需要将字符串编码为二进制字节数据。
encode()
byte_str=string.encode(encoding)
encoding代表编码方式,为字符串,常用的有"gbk“(汉字国标码),”UTF-8“(万国码)…返回string以encoding方式编码后得到的字节流
send方法
client_socket.send(byte_str)
将byte_str
传输到已经建立连接的服务端程序中
如:
send_data = "客户端发来消息...".encode("gbk")client_socket.send(send_data)
通过网络调试助手看到的结果:
4:接收数据
recv方法
recv_data=client_socket.recv(_bufsize)
返回从已经建立连接的服务端程序中接收到的字节流数据_bufsize为最大接受的字节大小
字符串解码
decode()
string=byte_str.decode(encoding)
返回byte_str以encoding方式进行解码后得到的字符串
如:
用网络调试助手充当服务端
recv_date=client_socket.recv(1024)recv_date=recv_date.decode("gbk")print(recv_date)
5:关闭客户端程序的套接字
close方法
client_socket.close()
关闭客户端的socket,断开连接
客户端程序代码汇总:
import socket # 导入socket库if __name__ == "__main__":# 创建客户端程序的socket对象# socket.AF_INET:ip地址类型为IPv4# socket.SOCK_STREAM:面向连接client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 连接服务端程序# 192.168.147.1为服务端ip地址# 8080为服务端程序的端口号client_socket.connect(("192.168.147.1", 8080))# 将字符串数据编码并发送至服务端程序send_data = "客户端发来消息...".encode("gbk")client_socket.send(send_data)# 接收来自服务端程序的字节流数据并解码recv_date = client_socket.recv(1024)recv_date = recv_date.decode("gbk")print(recv_date)# 关闭客户端程序的socket,断开与服务端程序的连接client_socket.close()
TCP服务端程序开发
步骤
创建服务端程序的套接字对象绑定端口号设置监听等待接受客户端的连接请求接收数据发送数据关闭服务端程序的套接字1:创建服务端程序的套接字对象
import socketserver_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
语法同客户端程序
2:绑定端口号
服务端程序要让客户端程序能够找到,所以一般要要绑定一个固定的端口号
bind方法
server_socket.bind(_address)
_address为元组,格式为(host, port)。host是服务端本地ip地址,一般设为“”
,自动取。port为端口号,需指定以供客户端程序来连接。
如:
server_socket.bind(("", 8989))
设置端口号复用
服务端程序运行结束后,端口号并不会立即释放,需等待2-3分钟。我们可以在bind
方法前设置下面这行代码来设置端口号复用,即程序运行完立刻释放端口号。
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
将socket.SO_REUSEADDR
设置为True
,即勾选端口复用选项
3:设置监听
客户端程序需要一直监听,直到接收到了客户端程序发来的连接请求。
listen()方法
server_socket.listen(_backlog)
_backlog
为最大监听数,即最多可以同时收到_backlog
个客户端程序的连接请求,并进行等待。server_socket在每个线程中只能同时连接一个客户端程序,其他被监听的客户端程序将被阻塞,排队等待连接。当申请建立连接的客户端程序超过最大监听数时,若还有客户端程序要发出连接请求,那么这个客户端程序连排队的机会都没有,直接报错。
如:
server_socket.listen(1024)
代表最多可以同时监听1024个客户端程序。
4:等待接受客户端程序的连接请求
服务端程序要一直等待监听。如果有客户端程序发来连接请求,服务端程序可以接受并处理。
accept()方法
new_server_socket,client_address=server_socket.accept()
没有客户端程序发来连接请求,则停在该行代码不动。有客户端发来连接请求,就接受请求,并建立连接。返回一个新的socket对象,专门与进行连接的客户端程序进行数据传输。这里用new_server_socket
接收以元组形式返回建立连接的客户端程序的ip地址和端口号。这里用client_address
接收。
5:接收数据
语法同客户端程序,不过要用accept
返回的新套接字来处理。
6:发送数据
语法同客户端程序,不过要用accept
返回的新套接字来处理。
7:关闭服务端程序的套接字
两个套接字都要记得关闭。
new_server_socket.close()server_socket.close()
关闭new_server_socket
意味着对应的这个客户端程序和服务端程序断开连接。服务端程序还可以继续与其他新的客户端程序连接。关闭server_socket
意味着服务端程序的套接字关闭,不再能与新的客户端程序连接,但之前的连接还保留。
服务端程序代码汇总:
import socketif __name__ == '__main__':# 创建服务端程序的socket对象server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置端口号复用,让程序退出端口号立即释放server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 给程序绑定端口号server_socket.bind(("", 8989))# 设置监听# 128:最大等待建立连接的个数server_socket.listen(128)# 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞,代码才能继续往下执行# 1. 专门用于和客户端程序通信的套接字: new_server_socket# 2. 客户端的ip地址和端口号: client_addressnew_server_socket, client_address = server_socket.accept()print("客户端程序的ip地址和端口号:", client_address)# 接收客户端程序发送的字节流数据并解码为字符串recv_data = new_server_socket.recv(1024)recv_data = recv_data.decode("gbk")print(recv_data)# 将字符串编码得到的字节流传输给客户端程序send_data = "客户端发来消息...".encode("gbk")new_server_socket.send(send_data)# 关闭服务端程序与客户端程序传输专用的套接字new_server_socket.close()# 关闭服务端程序的套接字,结束向新的客户端程序提供连接机会server_socket.close()
多任务版服务端程序
通过多线程的方式处理多个客户端程序的数据传输请求。
import socketimport threadingdef handle(handle_socket, address):"""与客户端程序进行数据传输并处理"""while True:recv_data = handle_socket.recv(1024)if recv_data: # 对收到的消息进行处理print(recv_data.decode("gbk"), address, sep=" from ")handle_socket.send("OK,数据处理中...".encode("gbk"))else: # 收到的消息为空print("客户端程序已退出...", address, sep=" from ")break# 终止和客户端程序进行通信handle_socket.close()if __name__ == '__main__':# 创建服务端套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置端口号复用,让程序退出端口号立即释放server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 绑定端口号server_socket.bind(("", 8080))# 设置监听server_socket.listen(128)# 循环等待接收客户端程序的连接请求while True:server_client_socket, client_address = server_socket.accept()print("已成功连接客户端程序...", client_address, sep=" from ")# 每当客户端和服务端建立连接成功以后,创建一个子线程,不同子线程负责处理不同客户端程序的消息sub_thread = threading.Thread(target=handle, args=(server_client_socket, client_address))# 设置守护主线程sub_thread.Daemon = True# 启动子线程sub_thread.start()# 服务端程序套接字可以不关闭,因为服务端程序需要一直运行