网络编程
网络编程
什么socket?
TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。
使用TCP的应用:Web浏览器;电子邮件、文件传输程序。
UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大
努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。
软件
客户端:CS架构, client -> server
浏览器:BS架构, browser -> server
为什么要网络通信发送的是字节?而不是字符串?
py3, send/recv 都是字节
py2, send/recv 都是字符串
服务端:
accept,阻塞:等待客户端来连接。
recv, 阻塞:等待客户端发来数据。
客户端:
connect,阻塞:一直在连接,直到连接成功才往下运行其他代码。
recv, 阻塞:等待服务端发来数据。
服务端:
1 import socket 2 3 server = socket.socket() 4 5 server.bind(('127.0.0.1',8001)) 6 7 server.listen(5) 8 9 while True: 10 conn,addr = server.accept() 11 # 字节类型 12 try: 13 while True: 14 data = conn.recv(1024) # 阻塞 15 if data == b'exit': 16 break 17 response = data + b' SB' 18 conn.send(response) 19 except ConnectionResetError:#防止客户端终端后 服务端异常 window环境下使用 20 break 21 22 conn.close()
客户端:
1 import socket 2 3 sk = socket.socket() 4 5 sk.connect(('127.0.0.1',8001)) 6 7 while True: 8 name = input("请输入姓名:") 9 sk.send(name.encode('utf-8')) # 字节 10 11 if name == 'exit': 12 break 13 14 response = sk.recv(1024) # 字节 15 print(response.decode('utf-8')) 16 17 sk.close()
socket粘包
socket的粘包为在数据量小与时间间隔短的情况下 优化算法使数据减少IO以达到提高效率,减少网络IO的一种方式
socket下的send与recv并不是一对一的 可以一对多 多对一即可
粘包主要是接收端不知所接收的大小(即不知数据的开头与结尾) 只要明确数据的大小 即可解决粘包导致的缺点
一般可以使用struck来达到效果
send : 只需要copy data send不是直接操作网卡的 本质上是数据由用户程序copy到操作系统缓存 操作系统来调用网卡传输
recv: 1. wait data 2. copy data 时间较长
struct用法
1 import struct 2 res=struct.pack("i","") 3 print(res) 4 print(len(res)) 5 obj=struct.unpack("i",res) 6 print(obj[0])import struct 7 res=struct.pack("i","") 8 print(res) 9 print(len(res)) 10 obj=struct.unpack("i",res) 11 print(obj[0])
subprocess用法
import subprocess res=subprocess.Popen("dir", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) print(res.stdout.read().decode("gbk"))
SSH Server
1 import socket 2 import subprocess 3 4 server = socket.socket() 5 6 server.bind(('127.0.0.1',8008)) 7 8 server.listen(5) 9 10 while True: 11 print("server is working.....") 12 conn,addr = server.accept() 13 # 字节类型 14 while True: 15 # 针对window系统 16 17 try: 18 cmd = conn.recv(1024).decode("utf8") # 阻塞 19 if cmd.encode("utf-8") == b'exit': 20 break 21 res=subprocess.Popen(cmd, 22 shell=True, 23 stderr=subprocess.PIPE, 24 stdout=subprocess.PIPE, 25 ) 26 # print("stdout",res.stdout.read()) 27 # print("stderr",res.stderr.read().decode("gbk")) 28 out=res.stdout.read() 29 err=res.stderr.read() 30 31 print("out响应长度",len(out)) 32 print("err响应长度",len(err)) 33 if err: 34 import struct 35 header_pack = struct.pack("i", len(err)) 36 conn.send(header_pack) 37 conn.send(err) 38 else: 39 #构建报头 40 import struct 41 header_pack=struct.pack("i",len(out)) 42 print("header_pack",header_pack) 43 # # 发送报头 44 conn.send(header_pack) 45 # 发送数据 46 conn.send(out) 47 48 except Exception as e: 49 break 50 51 52 conn.close()
SSH Client
1 import socket 2 import struct 3 sk = socket.socket() 4 5 sk.connect(('127.0.0.1',8008)) 6 7 while 1: 8 cmd = input("请输入命令:") 9 sk.send(cmd.encode('utf-8')) # 字节 10 if cmd=="": 11 continue 12 if cmd == 'exit': 13 break 14 15 header_pack=sk.recv(4) 16 data_length=struct.unpack("i",header_pack)[0] 17 print("data_length",data_length) 18 ''' 19 b'xxx/xxx/xxx/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 20 21 22 ''' 23 24 recv_data_length=0 25 recv_data=b"" 26 27 while recv_data_length<data_length: 28 data=sk.recv(1024) 29 recv_data_length+=len(data) 30 recv_data+=data 31 32 print(recv_data.decode("gbk")) 33 34 35 sk.close()
socketserver可以实现并发的网络通信
server
1 import socketserver 2 3 class Myserver(socketserver.BaseRequestHandler): 4 def handle(self):# handel之内的逻辑由程序员编写,request等同于socket对象conn 5 # 字节类型 6 while 1: 7 # 针对window系统 8 try: 9 print("等待信息") 10 data = self.request.recv(1024) # 阻塞 11 # 针对linux 12 if len(data) == 0: 13 break 14 if data == b'exit': 15 break 16 response = data + b'SB' 17 self.request.send(response) 18 except Exception as e: 19 break 20 21 self.request.close() 22 23 24 # 1 创建socket对象 2 self.socket.bind() 3 self.socket.listen(5) 25 # server=socketserver.ForkingUDPServer(("127.0.0.1",8899),Myserver) 26 server=socketserver.ThreadingTCPServer(("127.0.0.1",8899),Myserver) # socket建立,bind,listen方法 27 28 server.serve_forever()#类似于accept方法
client
1 import socket 2 3 sk = socket.socket() 4 5 sk.connect(('127.0.0.1',8899)) 6 7 while 1: 8 name = input(">>>>:") 9 sk.send(name.encode('utf-8')) # 字节 10 11 response = sk.recv(1024) # 字节 12 print(response.decode('utf-8'))