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下编程了,这次因为需要做一个跨平台的网络程序,就先 ...
随机推荐
- 索引器(C# 编程指南)
原文地址:https://msdn.microsoft.com/zh-cn/library/6x16t2tx(VS.80).aspx 索引器允许类或结构的实例按照与数组相同的方式进行索引.索引器类似于 ...
- js 返回上一页和刷新
1. Javascript 返回上一页history.go(-1), 返回两个页面: history.go(-2); 2. history.back(). 3. window.history.forw ...
- 简化工作流程 10款必备的HTML5开发工具
利用HTML5工具不仅可以帮助设计师和开发者创建更具吸引力的网站,还能增加网站的可用性和可访问性.本文收集了10款HTML5开发工具让你在网页中搭建特效.动画.视频.音频等诸多功能,为你节省更多开发时 ...
- WebService是什么
Webservice的一个最基本的目的就是提供在各个不同平台的不同应用系统的协同工作能力. 其实WebService并不是什么神秘的东西,它就是一个可以远程调用的类,或者说是组件. 为什么要使用Web ...
- Sudoku Solver [LeetCode]
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- node.js 对接公众平台
http://www.tfan.org/wp-content/uploads/使用-Nodejs-和-MongoDB-开发高性能微信公众平台应用.pdf
- TCP的三次握手
第一次握手 客户端调用connect,向服务端发送连接请求报文.该报文是一个特殊报文,报文首部同步位SYN=1,同时确认位ACK=0,seq=x表示确认字段的值为x,该字段值由客户端选择,表示客户端向 ...
- Java 多线程中run() 与 start() 的不同
区别:调用start方法实现多线程,而调用run方法没有实现多线程 Start: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调 ...
- JavaScript 字符串和日期内容整理
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Operating System Concepts 项目:生产者-消费者问题 线程
一. 实验目的 实现一个c程序,该程序能模拟解决有限缓冲问题,其中消费者和生产者产生和消耗随机数 二.实验内容 缓冲区 元数据类型为buffer_item,大小为1000的数组,按环形队列处理 生产者 ...