pythonpython开发-网络编程
智汇君开发 python开发-网络编程
$fileName
IP地址
定位唯一设备
ipv4:点分十进制
ipv6:冒号十六进制
本地环回地址:127.0.0.1对应域名localhost
ping 公网ip
ping 局域网ip:能ping说明在一个局域网或者网段内
ping localhost:能ping说明本地物理网卡没有问题
端口
通信:通过ip找到对应设备,再通过端口号找到对应进程应用程序,确定数据是给哪个进程的
共65536个
知名端口号:0-1023固定分配给特定服务
21:FTP服务
25:SMTP(简单邮件传输协议)服务
80:HTTP服务
22:SSH服务
443:HTTPS服务
动态端口号:一般程序员开发应用程序使用端口号称为动态端口号,范围是从1024到65535。如果程序员开发的程序没有设置端口号,操作系统会在动态端口号这个范围内随机生成一个给开发的应用程序使用。
当运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就会被释放。
TCP
传输数据之前先要确定传输的协议
TCP 的英文全拼(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信步骤:1.创建连接2.传输数据3.关闭连接
如:文件下载、上网等
TCP特点:
1.面向连接
通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源。
2.可靠传输
TCP采用发送应答机制
超时重传
错误校验(如延迟导致接收顺序错误,自动调整顺序)
流量控制和阻塞管理(网卡缓存区)
对应UDP(用户数据报协议):不建立连接、不可靠、不会管是否能够收到或者正确收到(上课用的广播、共屏)
TCP和UDP都是运输层的协议
socket
那么通信数据是如何完成传输的呢?socket套接字
进程通过网络与另一个机器上的进程通信、数据传输需要socket
只要跟网络相关的应用程序或者软件都使用到了socket。如qq、微信、浏览器、共屏软件等。
TCP网络应用程序
TCP网络应用程序:基于TCP协议、需要借助网络通信的程序
TCP网络应用程序开发分为:
主动发起建立连接请求的是客户端程序
等待接受连接请求的是服务端程序

网络程序通信的流程:
1.通过ip地址找到网络中的设备
2.通过端口号找到对应进程的端口
3.传输数据是还需要使用传输协议(tcp),保证数据的可靠性。
4.s0cket完成进程之间网络数的传输
tcp客户端程序开发
开发TCP客户端程序开发步骤回顾
1.创建客户端套接字对象
2.和服务端套接字建立连接
3.发送数据
4.接收数据
5.关闭客启端套接字
socket类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 导入socket模块 import socket 创建客户端socket对象 socket.socket(AddressFamily, Type)
参数说明: AddressFamily表示IP地址类型,分为IPv4和IPv6 Type表示传输协议类型
方法说明: connect(host,port)表示和服务端套接字建立连接 host是服务器ip地址 port是应用程序的端口号
send(data)表示发送数据,data是二进制数据 recv(buffersize)表示接收数据,buffersize是每次接收数据的长度
|
tcp客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| if __name__ == '__main__': import socket tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_client_socket.connect(("192.168.31.9",8080)) send_content = "你好,我是tcp客户端小白!" send_data = send_content.encode(encoding="gbk") tcp_client_socket.send(send_data) recv_data = tcp_client_socket.recv(1024) recv_content = recv_data.decode(encoding="gbk") print("接受的服务端数据为:", recv_data) tcp_client_socket.close()
|
tcp服务端程序开发
1 2 3 4 5 6 7 8
| 开发TCP服务端程序开发步骤回顾 1.创建服务端端套接字对象 2.绑定端口号 3.设置监听 4.等待接受客户端的连接请求 5.按收数据 6.发送数据 7.关闭套接字
|
socket类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 导入socket 模块 import socket 创建服务端socket对象 socket.socket(AddressFamily, Type) 参数说明: AddressFamily表示IP地址类型,分为IPv4和IPv6 Type表示传输协议类型
方法说明: bind(host,port))表示绑定端口号,host是ip地址 port 是端口号,ip地址一般不指定,表示本机的任何一个ip地址都可以(有的机器有多个网卡,不指定ip表示通过任一个ip都可以) listen(backlog)表示设置监听,backlog参数表示最大等待建立连接的个数(目前是单任务,一个客户端连接,其它的全部排队等待) accept()表示等待接受客户端的连接请求 send(data)表示发送数据,data是二进制数据 recv(buffersize)表示接收数据,buffersize是每次接收数据的长度
|

tcp服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| if __name__ == '__main__': import socket tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_server_socket.bind(("",9090)) tcp_server_socket.listen(128) new_server_socket,ip_port = tcp_server_socket.accept() print("来自:",ip_port) recv_data = new_server_socket.recv(1024) recv_content = recv_data.decode(encoding="utf-8") print("接受的客户端数据为:", recv_content) send_content = "问题正在处理..." send_data = send_content.encode(encoding="utf-8") new_server_socket.send(send_data) new_server_socket.close() tcp_server_socket.close()
|
端口号复用
当客户端和服务端建立连接后,服务端程序退出后端口号不会立即释放,需要等待大概1-2分钟。
解决办法有两种:
1.更换服务端端口号(极不推荐)
2.设置端口号复用(推荐大家使用)·也就是说让服务端程序退出后端口号立即释放
设置端口号复用的代码如下:
1 2 3 4
|
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| if __name__ == '__main__': import socket tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) tcp_server_socket.bind(("",9090)) tcp_server_socket.listen(128) new_server_socket,ip_port = tcp_server_socket.accept() print("来自:",ip_port) recv_data = new_server_socket.recv(1024) recv_content = recv_data.decode(encoding="utf-8") print("接受的客户端数据为:", recv_content) send_content = "问题正在处理..." send_data = send_content.encode(encoding="utf-8") new_server_socket.send(send_data) new_server_socket.close() tcp_server_socket.close()
|
TCP网络应用程序的注意点
1.当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
2.TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的
3.TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序。
4.listen后的套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
5.当TCP客户端程序和TCP服务端程序连接成功后TCP服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字。
6.关闭accept返回的套接字意味着和这个客户端已经通信完毕。
7.关闭listen后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信
8.当客户端的套接字调用close后,服务器端的recv 会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv 也会解阻塞,返回的数据长度也为0
tcp服务端服务多个客户端
目前只能循环排队服务客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| if __name__ == '__main__': import socket tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) tcp_server_socket.bind(("",9090)) tcp_server_socket.listen(128) while True: new_server_socket,ip_port = tcp_server_socket.accept() print("来自:",ip_port) recv_data = new_server_socket.recv(1024) recv_content = recv_data.decode(encoding="utf-8") print("接受的客户端数据为:", recv_content) send_content = "问题正在处理..." send_data = send_content.encode(encoding="utf-8") new_server_socket.send(send_data) new_server_socket.close() tcp_server_socket.close()
|
目前可以并行处理客户端连接,但是服务客户端时不能多轮处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import threading
def process(new_server_socket,ip_port): print("来自:",ip_port) recv_data = new_server_socket.recv(1024) recv_content = recv_data.decode(encoding="utf-8") print("接受的客户端数据为:", recv_content) send_content = "问题正在处理..." send_data = send_content.encode(encoding="utf-8") new_server_socket.send(send_data) new_server_socket.close()
if __name__ == '__main__': import socket tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) tcp_server_socket.bind(("",9090)) tcp_server_socket.listen(128) while True: new_server_socket,ip_port = tcp_server_socket.accept() args = {"new_server_socket":new_server_socket,"ip_port":ip_port} t = threading.Thread(target=process,kwargs=args) t.daemon = True t.start() tcp_server_socket.close()
|
最终程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import threading
def process(new_server_socket,ip_port): print("来自:",ip_port) while True: recv_data = new_server_socket.recv(1024) if len(recv_data) == 0: print(ip_port,"下线了!") break recv_content = recv_data.decode(encoding="utf-8") print("接受的客户端数据为:", recv_content) send_content = "问题正在处理..." send_data = send_content.encode(encoding="utf-8") new_server_socket.send(send_data) new_server_socket.close()
if __name__ == '__main__': import socket tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) tcp_server_socket.bind(("",9090)) tcp_server_socket.listen(128) while True: new_server_socket,ip_port = tcp_server_socket.accept() args = {"new_server_socket":new_server_socket,"ip_port":ip_port} t = threading.Thread(target=process,kwargs=args) t.daemon = True t.start()
tcp_server_socket.close()
|
socket之send和recv的原理剖析
认识TCP socket的发送和接收缓冲区
当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存中的一片空间。
send原理剖析
send是不是直接把数据发给服务端?
不是,要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的。它需要调用操作系统接口。也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间)。再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡
recv原理剖析
recv是不是直接从客户端接收数据?
不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据
send和recv原理剖析

说明:
- 发送数据是发送到发送缓冲区
- 接收数据是从接收缓冲区获取
小结
不管是recv还是send都不是直接接收到对方的数据和发送数据到对方,发送数据会写入到发送缓冲区,接收数据是从接收缓冲区来读取,发送数据和接收数据最终是由操作系统控制网卡来完成。