基于序列化技术(Protobuf)的socket文件传输
好像好久都没更博文了,没办法,最近各种倒霉事情,搞到最近真的没什么心情,希望之后能够转运吧。
言归正传,这次我要做的是基于序列化技术的socket文件传输来无聊练一下手。
一.socket文件传输
之前我所做的服务器和客户端的tcp/udp通信都是以字符串流来进行单工的,双工的传输,其实关于文件传输的原理也差不多,我的主要方法是通过文件迭代器遍历文件流,并将其读取转化为字符串流,然后将字符串流从服务器端发送,然后客户端在缓冲区中接收数据流,然后并把它写入文件当中,从而实现文件的传输,在下面程序当中,我仅仅是实现由服务器分发,客户端除了接收什么都不做的简单程序。
服务器端:
#!/usr/bin/env python
#-*- coding:utf-8 -*- from socket import *
from time import ctime
import os HOST = ''
PORT = 21567
BUFSIZ = 4096
ADDR = (HOST,PORT) tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5) filename = raw_input('Please input the file name:') while True:
print 'waiting for connection...'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from:',addr print '向客户端发送文件...'
f = open(filename,'r') for eachLine in f:
tcpCliSock.send('%s' % eachLine)
f.close()
tcpCliSock.close()
print 'Done!' tcpSerSock.close()
客户端:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from socket import * HOST = 'localhost'
PORT = 21567
BUFSIZ = 4096
ADDR = (HOST,PORT) tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR) filename = raw_input('Please input the filename you will write to:')
f = open(filename,'a') #以追加模式打开文件
print '正在写文件....'
while True:
data = tcpCliSock.recv(BUFSIZ)
if not data:
break
f.write(data) f.close()
print 'Done!'
tcpCliSock.close()
还有一种比较方便的方法是用框架SocketServer来实现文件传输的功能,相当于重新实现linux的scp命令。
服务器端:
#!/usr/bin/env python
#-*-coding:utf-8-*- import SocketServer addr = ('',21568) class DocHandler(SocketServer.StreamRequestHandler):
def handle(self):
doc_len = ord(self.rfile.read(1)) #文件的第一个字符代表文件名的长度
name = self.rfile.read(doc_len)
print "接收文件:%s" % name
f = open('../'+name,'w')
cont = self.rfile.read(4096)
while cont:
f.write(cont)
cont = self.rfile.read(4096)
f.close()
print "Done :%s" % name server = SocketServer.TCPServer(addr,DocHandler) #利用tcp传输
server.serve_forever()
客户端:
#!/usr/bin/env python
#-*- coding:utf-8 -*- from socket import *
import os.path addr = ('',21568) def get_header(name):
n_len = len(name)
assert n_len < 250
#assert语句,代表一个肯定的判定语句,如果为false,会抛出AssertError的异常
return chr(n_len) + name def send_file(name):
basename = os.path.basename(name)
header = get_header(basename)
cont = open(name).read()
s = socket(AF_INET,SOCK_STREAM)
s.connect(addr)
s.sendall(header)
s.sendall(cont)
s.close() if __name__ == '__main__':
filename = raw_input("请输入你要传输的文件名:")
send_file(filename)
二.序列化技术
所谓序列化技术,自己可以google一下。
这次我用的序列化技术的框架是google 的protocol buffer(简称protobuf),关于它的详细介绍,可以看看它的介绍,文档和API,它是一种和平台无关,语言无关的技术。
这次的程序我本来想用C++写的,但无奈环境搭建失败,用不了,只好再用python的。
首先为了避免重复劳动,我使用了它原来example的.proto文件,做一个关于名片传输的程序。
addressbook.proto
// See README.txt for information and build instructions. package tutorial; option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos"; message Person {
required string name = ;
required int32 id = ; // Unique ID number for this person.
optional string email = ; enum PhoneType {
MOBILE = ;
HOME = ;
WORK = ;
} message PhoneNumber {
required string number = ;
optional PhoneType type = [default = HOME];
} repeated PhoneNumber phone = ;
} // Our address book file is just one of these.
message AddressBook {
repeated Person person = ;
}
输入指令来生成addressbook_pb2.py:(注:如果是C++,则python换为cpp;如果是Java,则python换为java)
protoc -I=./ --python_out=./ addressbook.proto
然后先尝试弄个单机版出来吧。 根据官方的demo修改整合出来的。
add_person.py
#! /usr/bin/python # See README.txt for information and build instructions. import addressbook_pb2
import sys # This function fills in a Person message based on user input.
def PromptForAddress(person):
person.id = int(raw_input("Enter person ID number: "))
person.name = raw_input("Enter name: ") email = raw_input("Enter email address (blank for none): ")
if email != "":
person.email = email while True:
number = raw_input("Enter a phone number (or leave blank to finish): ")
if number == "":
break phone_number = person.phone.add()
phone_number.number = number type = raw_input("Is this a mobile, home, or work phone? ")
if type == "mobile":
phone_number.type = addressbook_pb2.Person.MOBILE
elif type == "home":
phone_number.type = addressbook_pb2.Person.HOME
elif type == "work":
phone_number.type = addressbook_pb2.Person.WORK
else:
print "Unknown phone type; leaving as default value." # Main procedure: Reads the entire address book from a file,
# adds one person based on user input, then writes it back out to the same
# file. filename = raw_input('Please input the file name:') address_book = addressbook_pb2.AddressBook() # Read the existing address book.
try:
f = open(filename, "rb")
address_book.ParseFromString(f.read())
f.close()
except IOError:
print sys.argv[1] + ": File not found. Creating a new file." # Add an address.
PromptForAddress(address_book.person.add()) # Write the new address book back to disk.
f = open(filename, "wb")
f.write(address_book.SerializeToString())
f.close()
list_person.py
#! /usr/bin/python # See README.txt for information and build instructions. import addressbook_pb2
import sys # Iterates though all people in the AddressBook and prints info about them.
def ListPeople(address_book):
for person in address_book.person:
print "Person ID:", person.id
print " Name:", person.name
if person.HasField('email'):
print " E-mail address:", person.email for phone_number in person.phone:
if phone_number.type == addressbook_pb2.Person.MOBILE:
print " Mobile phone #:",
elif phone_number.type == addressbook_pb2.Person.HOME:
print " Home phone #:",
elif phone_number.type == addressbook_pb2.Person.WORK:
print " Work phone #:",
print phone_number.number # Main procedure: Reads the entire address book from a file and prints all
# the information inside.
filename = raw_input("Please input the filename:")
address_book = addressbook_pb2.AddressBook() # Read the existing address book.
f = open(filename, "rb")
address_book.ParseFromString(f.read())
f.close() ListPeople(address_book)
运行过没有任何问题。
三.整合
好了,到了最后一步了, 实现的功能时,服务器端先要求你设定你自己要添加自己的名片信息,序列化,然后分发给客户端,客户端再把它反序列化,输出个人信息。
服务器端:
#!/usr/bin/env python
#-*- coding:utf-8 -*- from socket import *
from time import ctime
import os
import addressbook_pb2 HOST = ''
PORT = 21567
BUFSIZ = 4096
ADDR = (HOST,PORT) tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5) #添加联系人函数
def PromptForAddress(person):
person.id = int(raw_input("Enter person ID number: "))
person.name = raw_input("Enter name: ") email = raw_input("Enter email address (blank for none): ")
if email != "":
person.email = email while True:
number = raw_input("Enter a phone number (or leave blank to finish): ")
if number == "":
break phone_number = person.phone.add()
phone_number.number = number type = raw_input("Is this a mobile, home, or work phone? ")
if type == "mobile":
phone_number.type = addressbook_pb2.Person.MOBILE
elif type == "home":
phone_number.type = addressbook_pb2.Person.HOME
elif type == "work":
phone_number.type = addressbook_pb2.Person.WORK
else:
print "Unknown phone type; leaving as default value." filename = raw_input('Please input the file name:') address_book = addressbook_pb2.AddressBook() try:
f = open(filename,"rb")
address_book.ParseFromString(f.read())
f.close()
except IOError:
print filename + ": File not found. Creating a new file." #添加联系人信息
PromptForAddress(address_book.person.add()) #写进去
f = open(filename,"wb")
f.write(address_book.SerializeToString())
f.close() while True:
print 'waiting for connection...'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from:',addr print '向客户端发送文件...'
f = open(filename,'rb') for eachLine in f:
tcpCliSock.send('%s' % eachLine)
f.close()
tcpCliSock.close()
print 'Done!' tcpSerSock.close()
客户端:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from socket import *
import addressbook_pb2 HOST = 'localhost'
PORT = 21567
BUFSIZ = 4096
ADDR = (HOST,PORT) tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR) #输出信息函数
def ListPeople(address_book):
for person in address_book.person:
print "Person ID:", person.id
print " Name:", person.name
if person.HasField('email'):
print " E-mail address:", person.email for phone_number in person.phone:
if phone_number.type == addressbook_pb2.Person.MOBILE:
print " Mobile phone #:",
elif phone_number.type == addressbook_pb2.Person.HOME:
print " Home phone #:",
elif phone_number.type == addressbook_pb2.Person.WORK:
print " Work phone #:",
print phone_number.number filename = raw_input('Please input the filename you will write to:')
address_book = addressbook_pb2.AddressBook() f = open(filename,'ab') #以追加模式打开文件
print '正在写文件....'
while True:
data = tcpCliSock.recv(BUFSIZ)
if not data:
break
f.write(data) f.close()
print 'Done!' f = open(filename,"rb")
address_book.ParseFromString(f.read())
f.close() ListPeople(address_book) tcpCliSock.close()
搞定!请多多指教!
转载请注明出处:http://www.cnblogs.com/sysu-blackbear/
基于序列化技术(Protobuf)的socket文件传输的更多相关文章
- Java基于Socket文件传输示例(转)
		
最近需要进行网络传输大文件,于是对基于socket的文件传输作了一个初步的了解.在一位网友提供的程序基础上,俺进行了一些加工,采用了缓冲输入/输出流来包装输出流,再采用数据输入/输出输出流进行包装,加 ...
 - Java基于Socket文件传输示例
		
http://www.blogjava.net/sterning/archive/2007/10/13/152508.html 最近需要进行网络传输大文件,于是对基于socket的文件传输作了一个初步 ...
 - Linux网络编程:socket文件传输范例
		
基于TCP流协议的socket网络文件传输Demo: 实现:C语言功能:文件传输(可以传任何格式的文件) /********************************************** ...
 - Socket 文件传输
		
服务端 1.控件:TServerSocket 2.OnClientRead事件处理 procedure TMainForm.ssClientRead(Sender: TObject; Socket: ...
 - python socket文件传输实现
		
简单版 server(服务端) import socket import subprocess import struct import json import os share_dir = r'E: ...
 - Android连接热点的Socket文件传输
		
最近把测试丢过来的种种BUG解决后,终于有时间去研究研究Socket通信,再加上以前做的WiFi连接和热点开启,于是有了现在的这篇博文:创建热点发送文件,让另一台手机连接热点接收文件. 效果图: 两台 ...
 - python 3.7 利用socket文件传输
		
参考:https://www.cnblogs.com/VseYoung/p/socket_1.html 参考 https://blog.csdn.net/a19990412/article/detai ...
 - 基于UDT connect连接通信以及文件传输--客户端
		
上面一篇文章中提出了服务端的,其实这里没有严格意义的服务端和客户端之分,因为我在代码中是基于UDP的,不存在服务端与客户端,两个都是对等的,只是我这里进行一下简单的区分而已.在这里,客户端所进行的主要 ...
 - 基于UDT connect连接通信以及文件传输--服务端
		
网上与UDT相关的资料不多,与UDT相关的源码例子更少.最近在接触UDT,也是因为缺少相关的资料,导致学习起来甚感痛苦.下面将我自己这两天弄出来的代码贴出来,希望对在寻找相关资料的童鞋有一定的帮助.与 ...
 
随机推荐
- 使用VSCode调试单个PHP文件
			
突然发现是可以使用 VSCode 调试单个 PHP 文件的,今天之前一直没有弄成功,还以为 VSCode 是不能调试单文件呢.这里记录一下今天这个"突然发现"的过程. 开始,是在看 ...
 - redis在php中常用的语法(转)
			
String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 $redis-> ...
 - NO.3:自学tensorflow之路------MNIST识别,神经网络拓展
			
引言 最近自学GRU神经网络,感觉真的不简单.为了能够快速跑完程序,给我的渣渣笔记本(GT650M)也安装了一个GPU版的tensorflow.顺便也更新了版本到了tensorflow-gpu 1.7 ...
 - 科普贴 | 以太坊网络中的Gas Limit 和 Gas Price 是什么概念?
			
接触以太坊的同学都听过 Gas/ Gas Price/ Gas Limit,那么这些词汇究竟是什么意思? 还有,为什么有时候你的ETH转账会很慢?如何提高ETH转账速度? Ethereum平台 Vit ...
 - Sprint 1 Review & Daily Scrum - 11/18
			
今天我们组利用课后的时间对Sprint 1阶段进行了回顾,并对接下来的工作进行了安排. Sprint 1阶段我们开始定的计划是完成最基础的背单词功能,可以让用户可以完整地走一遍背单词流程.回顾上周,我 ...
 - Beta版本冲刺(四)
			
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组 ...
 - Spark 实践——基于 Spark MLlib 和 YFCC 100M 数据集的景点推荐系统
			
1.前言 上接 YFCC 100M数据集分析笔记 和 使用百度地图api可视化聚类结果, 在对 YFCC 100M 聚类出的景点信息的基础上,使用 Spark MLlib 提供的 ALS 算法构建推荐 ...
 - Windows下PyInstaller的使用教程
			
直接使用Python开发的软件时有许多不方便的地方,如需要安装特定的Python环境,需要安装依赖库.为了便于部署,需要将Python源代码编译成可执行文件,编译后的可执行文件就能脱离python环境 ...
 - php 的优缺点
			
1.优点:开源 免费性 快捷性 [程序开发快,运行快,技术本身学习快] 插件丰富,网上的解决方案有很多,而且还有庞大的开源社区可以提供帮助. 跨平台性强 效率高 图像处理 面向对象 [在php4 ...
 - DataGridView列标题居中,内容居中
			
//列标题居中 dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleC ...