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 至少分以下几步:

  1. First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests.   
  2. Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
  3. Then call the handle_request() orserve_forever() method of the server object to process one or many requests.
  4. Finally, call server_close() to close the socket.

示例代码:

0911 Socket网络编程的更多相关文章

  1. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  2. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  3. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  4. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  5. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  6. Socket网络编程-基础篇

    Socket网络编程 网络通讯三要素: IP地址[主机名] 网络中设备的标识 本地回环地址:127.0.0.1 主机名:localhost 端口号 用于标识进程的逻辑地址 有效端口:0~65535 其 ...

  7. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

  8. windows下的socket网络编程

    windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了, ...

  9. windows下的socket网络编程(入门级)

    windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...

随机推荐

  1. WAMP 403 Forbidden禁止访问 的解决办法

    修改httpd.conf文件 # onlineoffline tag - don't remove Require local To # onlineoffline tag - don't remov ...

  2. 初学java之事件响应(结合接口来设置在同一个界面上!)

    package wahaha; public class test_1 { public static void main( String args[] ) { WindowActionEvent w ...

  3. 在唯一密钥属性“name”设置为“ScriptHandlerFactory”时,无法添加类型为“add”的重复集合项

    出错原因:同一根目录下有两个相同的WebConfig文件 解决办法:删除子其中一个webConfig文件. 详细:

  4. SQL Server 自定义函数(1)把某一列多行的值拼接成一个字符串

    ) SET @resultstr='' SELECT @resultstr=@resultstr+'|'+[BaseImage] FROM dbo.life_fc PRINT @resultstr 示 ...

  5. Java网络通信

    一.基本概念 1.网络程序: 能够接受另一台计算机发送过来的数据或者能够向另一台计算机发送数据的程序叫做网络程序. 2.IP 能够在网络中唯一标示一台主机的编号就是IP 3.端口号 16位数字表示 4 ...

  6. Java三大特征之------多态

    1.定义 指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行为方式. 2.存在条件 2.1存在父子关系 2.2子类中存在重写方法 2.3父类类型的变量指向子类对象 ...

  7. jQuery学习小结2——动画

    一.基础动画 方法名 说明 show([speed,[easing],[fn]])hide([speed,[easing],[fn]]) speed:三种预定速度之一的字符串("slow&q ...

  8. spring bean初始化顺序

    转载:http://blog.csdn.net/heyutao007/article/details/50326793 常用的设定方式有以下三种:通过实现 InitializingBean/Dispo ...

  9. Linux学习之CentOS--CentOS6.4下Mysql数据库的安装与配置【转】

      如果要在Linux上做j2ee开发,首先得搭建好j2ee的开发环境,包括了jdk.tomcat.eclipse的安装(这个在之前的一篇随笔中已经有详细讲解了Linux学习之CentOS(七)--C ...

  10. 所思所想 关于asp.net界面业务分离

    1.体会:使用ASP.NET控件来做前段是有很大的局限性的 2.使用拼接HTML的方式来写代码虽然不符合模式,但是有很大的灵活性 3.如果使用拼接字符串的方式来生成前台的代码,使用NV的话完全可以实现 ...