网络编程
应用层: 它只负责产生相应格式的数据 ssh ftp nfs cifs dns http smtp pop3
传输层: 定义数据传输的两种模式:
TCP(传输控制协议:面向连接,可靠的,效率相对不高)
UDP(用户数据报协议:非面向连接,不可靠的,但效率高)
网络层: 连接不同的网络如以太网、令牌环网
IP (路由,分片) 、ICMP、 IGMP
ARP ( 地址解析协议,作用是将IP解析成MAC )
数据链路层: 以太网传输
物理层: 主要任务是规定各种传输介质和接口与传输信号相关的一些特性
tcp协议:三次握手四次挥手
socket(套接字):
tcp:
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b'hi') #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选)
import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
udp
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字 udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi',addr) # 对话(接收与发送) udp_sk.close() # 关闭服务器套接字
import socket ip_port=('127.0.0.1',9000) udp_sk=socket.socket(type=socket.SOCK_DGRAM) udp_sk.sendto(b'hello',ip_port) back_msg,addr=udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'),addr)
黏包问题:
黏包现象只发生在tcp协议中:
1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
解决黏包问题:
struct模块
该模块可以把一个类型,如数字,转成固定长度的bytes
import socket import struct sk=socket.socket() sk.bind(('127.0.0.1',9000)) sk.listen() conn,addr = sk.accept() while True: info = input("<<<") if info =="q": break conn.send(info.encode('utf-8')) msg = conn.recv(4) ret=struct.unpack('i',msg)[0] ret=conn.recv(ret) print(ret.decode('gbk')) conn.close() sk.close()
import socket import subprocess import struct sk = socket.socket() sk.connect(('127.0.0.1',9000)) while True: cmd=sk.recv(1024) if cmd == 'q': break res = subprocess.Popen(cmd.decode('utf-8'), shell=True, stderr=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stderr = res.stderr.read() stdout = res.stdout.read() ret=len(stderr)+len(stdout) ret=struct.pack('i',ret) sk.send(ret) sk.send(stderr) sk.send(stdout) sk.close()
上传下载文件:
import socket import os import json import struct buffer=1024 sk=socket.socket() sk.bind(('127.0.0.1',8880))#把地址绑定到套接字 sk.listen()#监听链接 conn,addr = sk.accept() #接受客户端链接 head_len = conn.recv(4) head_len = struct.unpack('i',head_len)[0] json_head = conn.recv(head_len).decode('utf-8') head = json.loads(json_head) file_size = head['file_size'] with open(head['file_name'],'wb')as f: while file_size: if file_size >= buffer: c=conn.recv(buffer) f.write(c) file_size -= buffer else: c=conn.recv(file_size) f.write(c) break conn.close() sk.close()
import socket import os import json import struct sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8880)) buffer = 1024 head = {'file_size': None, 'file_path' : r'C:\Users\tom\Pictures\2016-10', 'file_name': 'IMG_0116.JPG'} filepath = os.path.join(head['file_path'], head['file_name']) file_size = os.path.getsize(filepath) head['file_size'] = file_size head_json = json.dumps(head)#字典转字符串 head_bytes = head_json.encode('utf-8')#转bytes head_len = len(head_bytes) pack_len = struct.pack('i',head_len) sk.send(pack_len) #先发报头的长度,4个bytes sk.send(head_bytes) #再发报头的字节格式 with open(filepath,'rb') as f: while file_size : if file_size > buffer: c=f.read(buffer) sk.send(c) file_size-=buffer else: c = f.read(file_size) sk.send(c) break sk.close()