网络编程
python基础之socket编程
阅读目录
==============================
一.C/S、B/S架构client<------>server browser<------>server
学习socket编程就是要编写一个客户端软件和服务端软件
然后实现服务端与客户端基于网络通信
二.osi七层
目前我们掌握5层就够了
引子:
须知一个完整的计算机系统是由硬件、操作系统、应用软件三者组成,具备了这三个条件,一台计算机系统就可以自己跟自己玩了(打个单机游戏,玩个扫雷啥的)
如果你要跟别人一起玩,那你就需要上网了,什么是互联网?
互联网的核心就是由一堆协议组成,协议就是标准,比如全世界人通信的标准是英语
网络通信原理:详点此处
三.socket层
四.socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,
对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只要遵循socket的规定去编程,写出的程序自然就是遵循 tcp/udp标准的。
也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序
而程序的pid是同一台机器上不同进程或者线程的标识
五.tcp与udp协议(传输层)
tcp三次握手和四次挥手
p.s四次挥手客户端和服务端位置对调
listen(监听)和rcvd(收消息)和established(建立连接)三者相互转化,
受到syn洪水攻击的时候,服务器上会有大量的syn 状态,服务器三种状态会进行切换
fin_wait_1表示主动断开连接的一方进入的状态(通常是服务端来发)
高并发的情况下服务端会进入time_wait状态
六.TCP协议
6.1基于TCP协议的套接字通信
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 AF_INET基于网络通信的套接字 # SOCK_STREAM流氏协议(tcp) SOCK_DGRAM报氏协议(udp) phone.bind(('127.0.0.1',8081)) #插手机卡,补充:0-65535 0-1024给系统用的 phone.listen(5) # 开机 这个5是控制最大的请求数,不是链接数,同一时间能来的请求数只有5 print('start...') conn,client_addr=phone.accept() # 等电话连接 print('连接来了:',conn,client_addr)#conn是一个套接字对象,定制了一个打印格式 # 收发消息 msg=conn.recv(1024) #收消息,1024是一个最大的限制 1024个字节 print('客户端的消息: ',msg) conn.send(msg+b'SB') # 挂电话 conn.close() # 关机 phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 phone.send('你好'.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
6.2通信循环
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('start') conn,client_addr=phone.accept() #conn是管道,对应的是双向链接 print('客户端',client_addr) while True:#通信循环 try: msg=conn.recv(1024) print('客户端的消息:',msg) conn.send(msg+b'SB') except Exception: break conn.close() #操作系统把无用的链接回收掉 phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>:').strip() phone.send(msg.encode('utf-8'))#发消息b'hello data=phone.recv(1024)#收消息 print(data.decode('utf-8')) phone.close()
6.3通信循环和连接循环
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('start...') while True: # 连接循环 conn,client_addr=phone.accept() print('客户端 ',client_addr) while True: # 通信循环 try: msg=conn.recv(1024) print('客户端的消息: ',msg) conn.send(msg+b'SB') except ConnectionResetError: break conn.close() phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 phone.connect(('127.0.0.1',8081)) # 拨电话,地址为服务端的ip和端口 while True: msg=input('>>>: ').strip() phone.send(msg.encode('utf-8')) # 发消息b'hello' data=phone.recv(1024) #收消息 print(data.decode('utf-8')) phone.close()
只能连接1个客户端,但是可以建立6个请求
6.4远程执行命令的程序
from socket import * import subprocess server=socket(AF_INET,SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,client_addr=server.accept() #(连接对象,客户端的ip和端口) print(client_addr) while True: try: cmd=conn.recv(1024) obj=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout=obj.stdout.read() stderr=obj.stderr.read() # 先发送数据的长度 total_size=len(stdout) + len(stderr) conn.send(total_size) # 发送真实的数据 conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() server.close()
from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8080)) # print(client) while True: cmd=input('>>>: ').strip() if not cmd:continue client.send(cmd.encode('utf-8')) # print('has send') res=client.recv(14744) # print('has recv') print(len(res)) print(res.decode('gbk')) client.close()
七.UDP协议
八.粘包现象
8.1什么是粘包?
pass
十.粘包问题的解决
10.1补充struct模块
pass
10.2粘包问题解决初级版
pass
10.3粘包问题解决终极版
流程是这样
服务端先做一个报头,把报头信息都丢到一个报头字典里面,字典序列化得到json串,json串encode转成bytes,得到bytes就可以发报头了
但不能立马发,先把报头长度发过去,报头长度被struct打包成了4个bytes,然后接收端先收4个bytes出来,然后可以解包出来报头的长度
发送端接下来发报头,我接收端直接可以根据报头的长度把报头收到,发送端再发真实的数据,我接收端根据报头里面提供的信息,你发多少我都能收完整.