0911 Socket网络编程
1.实现ftp上传、下载功能
1.1 循环接收数据直到接收完毕
server端接收client发送的命令(比如说ifconfig),然后server端将命令执行结果反馈给客户端,这时候有个问题,server端是一次性的把数据发给client了,但是client怎么接收全部呢?比如client.recv(1024)调大接收的值行吗?增加接收的次数行吗?
调大接收的值,多大合适,每次server端发送的数据大小都不同;
增加接收的次数,那增加到接收几次合适呢,也是不定值。
循环接收buffer缓冲里的数据,一直到buffer里没有数据,这样也不行,因为buffer里可能存储着好多条命令的执行结果,一次性接收过来,显示在client端可能就是杂乱的数据了。除非server和client是一对一的,而且是只能发一条命令接收一条结果再发送一条命令,这样单线程的走。
所以解决办法是,server在发送数据前先将要发的数据总大小发送给client,然后client接收这个总大小的字节即可接收完全部数据。
#!/usr/bin/env python
#coding:utf-8 import socket,os server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('localhost',9543))
server.listen() while True:
conn,addr = server.accept()
while True:
data = conn.recv(10240)
if not data:break
result = os.popen(data.decode()).read()
if result == '': #命令不存在的话result会为空
result = 'command not found.' conn.send(str(len(result.encode('UTF-8'))).encode('UTF-8')) #这里把result.encode(),是因为如果result里包含中文的话,会有点问题。
#a = '期望'
#len(a) 结果是2,计算的是字符数量
#len(a.encode()) 结果是6,计算的是字节数量。
#发过去的大小,一个中文算一个数量,client接收到后,是按字节计算的,所以一个中文算3个数量,为了统一,就在发送长度的时候直接encode一下。
conn.recv(1024)
conn.send(result.encode('UTF-8'))
server.close() import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('localhost',9543)) while True:
u_input = input('>')
if len(u_input) == 0:continue
client.send(u_input.encode('UTF-8'))
data_size = client.recv(1024).decode()
client.send('OK'.encode())
receive_size = 0
print(data_size)
print(type(data_size))
while receive_size != int(data_size): #只要已接收的字符小于server发送过来的字符数量,就一直接收。#如果server端发送字节长度时没有encode,同时发送的内容包含中文,当内容接收完毕后,就会出现receive_size 大于 data_size(包含中文越多相差值越大),因为一个中文在data_size那算一个数量,但是在receive_size那算三个数量。
data = client.recv(1024)
receive_size += len(data)
print(data.decode())
else:
print('total length is :',receive_size) client.close()
1.2 粘包的概念与解决
server:
conn.send(''.encode())
conn.send(''.encode())
server端连续发送两个数据 client:
client.recv(1024)
client.recv(1024)
client端接收server发送的两个数据 因为server端的两次发送时紧挨着,所以在windows上可能出现粘包,在linux上肯定会出现粘包。
粘包就是把两次send的内容一起放到了buffer里,client第一次recv时就能取到所有数据,就会client收到的结果造成混乱。 #解决粘包:
#方法一,不推荐:可以在两次send中间插一个time.sleep(0.5),这样两个包就会分开发了,不会黏在一起;但是每次都会停顿0.5秒,能明显感觉到延迟;比如股票这种强调速度的应用,用sleep根本不行。 #方法二:在两次send中间插入一个recv
server:
conn.send(str(len(result.encode('UTF-8'))).encode('UTF-8'))
conn.recv(1024) #接收client一个消息后,再继续发送第二个send。
conn.send(result.encode('UTF-8')) client:
data_size = client.recv(1024).decode()
client.send('OK'.encode()) #接收到第一条内容后,给server发送一个消息,让server代码继续执行
data = client.recv(1024) #方法三:
client端只接收该接收的部分,比如server给client发了一个文件(大小为2048字节),紧接着又发了一个md5值(32字节),那客户端可以先client.recv(2048),然后client.recv(32),这样肯定不会收错了,需要注意的是如果内容包含中文,必须先对内容编码(encode)再len计算内容长度。
1.3 下例示范一个简单的ftp应用
import socket
import time
import hashlib
import os server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('localhost',956))
server.listen() while True:
conn,addr = server.accept()
while True:
cmd,filename = conn.recv(1024).decode().split()
if len(cmd) == 0 or len(filename) == 0: #命令或文件为空就退出
break
if os.path.isfile(filename): #判断是否存在文件
filesize = os.stat(filename).st_size #获取文件长度
print(filesize)
conn.send(str(filesize).encode())
conn.recv(1024)
m = hashlib.md5()
with open(filename) as f:
for line in f:
m.update(line.encode()) #计算一行md5
conn.send(line.encode())
server_md5 = m.hexdigest() #获取最终的md5值
conn.send(server_md5.encode())
server.close() import socket
import hashlib client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('localhost',956)) while True:
u_input = input('>')
if len(u_input) == 0:
continue
cmd,filename = u_input.split()
if cmd.startswith('get'):
client.send(u_input.encode())
file_size = int(client.recv(1024).decode()) #接收文本大小
print(file_size)
client.send('ok'.encode())
received_size = 0
m = hashlib.md5()
with open(filename + '.new','w') as f:
while received_size < file_size:
if file_size - received_size > 1024:
size = 1024
else:
size = file_size - received_size #如果剩余需要接收的字节小于1024,就只接收剩余大小的字节,防止接收到粘包数据。
data = client.recv(size)
received_size += len(data) #将已接收的大小求和
m.update(data)
f.write(data.decode())
else:
print('receitotal size is :%s' % received_size)
client_md5 = m.hexdigest() server_md5 = client.recv(1024).decode() print('client_md5:%s' % client_md5)
print('server_md5:%s' % server_md5)
else:
print('get please.')
continue
client.close()
2.SocketServer
socket很好用,但是无法实现并发,所以就有了SocketServer,SocketServer是对socket的再封装,可实现网络并发处理。
创建一个socketserver 至少分以下几步:
- First, you must create a request handler class by subclassing the
BaseRequestHandlerclass and overriding itshandle()method; this method will process incoming requests. - Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
- Then call the
handle_request()orserve_forever()method of the server object to process one or many requests. - Finally, call
server_close()to close the socket.
示例代码:
0911 Socket网络编程的更多相关文章
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- Python Socket 网络编程
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
- Python全栈【Socket网络编程】
Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...
- python之Socket网络编程
什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...
- Python之路【第七篇】python基础 之socket网络编程
本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket 网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...
- Socket网络编程-基础篇
Socket网络编程 网络通讯三要素: IP地址[主机名] 网络中设备的标识 本地回环地址:127.0.0.1 主机名:localhost 端口号 用于标识进程的逻辑地址 有效端口:0~65535 其 ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
- windows下的socket网络编程
windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了, ...
- windows下的socket网络编程(入门级)
windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...
随机推荐
- 在Windows8.1中通过IIS发布网站产生HTTP Error 503错误的解决方案
1.解决IIS下网站Bin目录中32位DLL不能使用,如图所示 2.解决通过IIS浏览网站,出现Http503的问题,如图所示
- Log 日志级别
一直对于程序中的日志级别有点模糊,今天专门百度学习下.遂成此文: 日志记录器(Logger)是日志处理的核心组件.log4j具有5种正常级别(Level).: 1.static Le ...
- TCP与UDP
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议:可靠.保证正确性:顺序到达:流量控制.拥塞控制:重传机制.窗口机制:对系统资源.时间要求多:流模式S ...
- 229. Majority Element II -- 找出数组中出现次数超过 ⌊ n/3 ⌋ 次的数
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorit ...
- Rudolph javascript 监听简单对象属性的变化 -- 回调函数的应用
http://www.oschina.net/code/snippet_1590754_46481 //简单对象的属性的变化监控 //通过setAttr改变属性的值 var o = { 'a':2, ...
- mvc伪静态<三> IIS配置
上一篇已经已经讲述了mvc伪静态的代码实现. 下面以IIS 7.5为例演示一下IIS如何配置才能在服务器显示.html的伪静态 一.进入IIS,选择处理程序映射 二添加脚本映射 三根据你的处理程序的版 ...
- 11 自定制shell提示符
shell提示符 huiubantu@ubuntu:~$ shell提示符保存在PS1变量中 包括用户名,主机名,当前工作目录 可以通过echo命令查看PS1的内容 huiubantu@ubuntu ...
- .NET GC机制学习笔记
学习笔记内容来自网络资料摘录http://www.cnblogs.com/springyangwc/archive/2011/06/13/2080149.html 1.GC介绍 Garbage Col ...
- git在公司内部的使用实践(转)
从2011.10月左右,开始在后台组推行git版本控制,到现在也差不多半年了,也形成了一套基于git flow的副官模式工作流程: 版本定义: 版本号使用x.x.x进行定义,第一个x代表大版本只有在项 ...
- 扫盲如何在ECLIPSE中使用条件断点
有时候在编码的时候我们希望知道代码变量符合某个条件时,才中断点,其他的情况不中断点. 解决办法1: 我们写个代码 判断,符合条件在符合条件处进行断点,这个方法很麻烦,需要去修改代码,不要是还需 ...