socket实现文件上传和下载
#!/usr/bin/env python # coding:utf-8 import socket import struct import json buffer = 1024 sk = socket.socket() sk.bind(('127.0.0.1',8888)) sk.listen() conn,addr = sk.accept() ret = conn.recv(4) len_operate_c = struct.unpack('i',ret)[0] operate_c = conn.recv(len_operate_c) operate_c = operate_c.decode('utf-8') if operate_c == 'upload': res = conn.recv(4) len_head = struct.unpack('i',res)[0] head = conn.recv(len_head).decode('utf-8') head = json.loads(head) filesize = head['filesize'] filename = head['filename'] with open (filename,'wb') as f: while filesize: if filesize >= buffer: content = conn.recv(buffer) f.write(content) filesize -= buffer else : content = conn.recv(filesize) f.write(content) filesize = 0 conn.close() sk.close()
#!/usr/bin/env python # coding:utf-8 def get_filename(file_path): return os.path.basename(file_path) import socket import os import json import struct buffer = 1024 sk = socket.socket() sk.connect(('127.0.0.1',8888)) operate = ['download','upload'] for k,j in enumerate(operate,1) : print(k,j) num = int(input('请输入你的选项: ')) operate_c = operate[(num-1)] len_operate_c = len(operate_c) print(len_operate_c) res = struct.pack('i',len_operate_c) sk.send(res) sk.send(operate_c.encode('utf-8')) if operate_c == 'upload' : head = {'filename':None,'filesize':None,} file_path = input("请输入要上传的文件绝对路径 :") filename = get_filename(file_path) head['filename'] = filename filesize = os.path.getsize(file_path) head['filesize']=filesize json_head = json.dumps(head) len_head = len(json_head) ret = struct.pack('i',len_head) sk.send(ret) sk.send(json_head.encode('utf-8')) with open (file_path,'rb') as f: while filesize: if filesize >= buffer : content = f.read(buffer) sk.send(content) filesize -= buffer else : content = f.read(filesize) sk.send(content) filesize = 0 sk.close()
网络编程:实现不同机器上的程序通信
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
基于TCP简单socket通信
server端
import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr = sk.accept() ret = conn.recv(1024) conn.send(b'hi') print(ret) conn.close() sk.close()
client端
import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) sk.send(b'hello') res = sk.recv(1024) print(res) sk.close()
服务端长连接
socket端
import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() # conn,addr = sk.accept() while 1: conn,addr = sk.accept() ret = conn.recv(1024) ret = ret.decode('utf-8') if ret: conn.send(b'hi') print(ret)
client端
import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) sk.send(bytes('你好',encoding='utf8')) res = sk.recv(1024) print(res) sk.close()
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sk = socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
参数一:地址簇
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6
socket.AF_UNIX 只能够用于单一的Unix系统进程间通信
参数二:类型
socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDP
基于UDP简单socket通信
import socket sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) sk.bind(('127.0.0.1',8080)) msg,(host,port) = sk.recvfrom(1024) print(msg) sk.sendto(b'hello',(host,port)) sk.close()
import socket sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ip_port=('127.0.0.1',8080) sk.sendto(b'hi',ip_port) ret,addr = sk.recvfrom(1024) print(ret) print(addr) sk.close()
udp的server不需要监听,也不需要建立连接
在启动服务之后,只能被动地等待客户端发过来的消息,
客户端发送消息的同时还会自带地址信息
消息回复的时候,不仅需要发送消息,还需要把对方地址填上
使用tcp,出现数据乱,不丢包
本质问题:不知道客户端发送数据包的大小
优化算法,连续发送多个send,小的数据包被合并
使用udp,出现丢包现象,因为udp是尽最大努力交付的协议
hmac验证客户端的合法性
import hmac,os import socket secret_key=b'egg' def conn_auth(conn): print('开始验证新链接的合法性') msg=os.urandom(32) conn.sendall(msg) h=hmac.new(secret_key,msg) digest=h.digest() respone=conn.recv(len(digest)) return hmac.compare_digest(respone,digest) def server_socket(): sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() while 1: conn,addr = sk.accept() res = conn_auth(conn) print(res) server_socket()
import socket import hmac secret_key=b'egg' def auth_conn(conn): msg=conn.recv(32) h=hmac.new(secret_key,msg) digest=h.digest() conn.sendall(digest) def client(): sk = socket.socket() sk.connect(('127.0.0.1',8080)) auth_conn(sk) sk.close() client()
socketserver,在socket的基础上进行封装,可以实时同多个客户端通信
import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "127.0.0.1", 9999 # 设置allow_reuse_address允许服务器重用地址 socketserver.TCPServer.allow_reuse_address = True # 创建一个server, 将服务地址绑定到127.0.0.1:9999 server = socketserver.TCPServer((HOST, PORT),Myserver) # 让server永远运行下去,除非强制停止程序 server.serve_forever()
import socket HOST, PORT = "127.0.0.1", 9999 data = "hello" # 创建一个socket链接,SOCK_STREAM代表使用TCP协议 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((HOST, PORT)) # 链接到客户端 sock.sendall(bytes(data + " ", "utf-8")) # 向服务端发送数据 received = str(sock.recv(1024), "utf-8")# 从服务端接收数据 print("Sent: {}".format(data)) print("Received: {}".format(received))