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. Android系统启动过程-uBoot+Kernel+Android

    摘要:本文是参考大量网上资源在结合自己查看源代码总结出来的,让自己同时也让大家加深对Android系统启动过程有一个更加深入的了解!再次强调,本文的大多数功劳应归功于那些原创者们,同时一些必要的参考链 ...

  2. VMware Workstation 12 Pro虚拟机下载(含序列号)

    VMware Workstation 12 Pro 官网下载地址:http://www.vmware.com/products/workstation/workstation-evaluation V ...

  3. --专访雷果国: 从1.5K到18K 一个程序员的5年成长之路--

    导语:今年三月份,在CSDN博客和新浪微博上有一篇<从1.5K到18K,一个程序员的5年成长之路>被众人分享和传阅,这篇博文首先介绍了作者自学之初薄弱的基础,然后通过流水账形式分享了那个从 ...

  4. mysql的小知识点(关于数据库的导入导出 对于windows)

    对于,一个存在的数据,我们该如何去打包成.sql属性的文件呢? 直接进行这两条语句: D:\Program Files\MySQL\mysql\bin>mysqldump -u root -p ...

  5. hdu------(4302)Holedox Eating(树状数组+二分)

    Holedox Eating Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  6. IOS开发设计思路

    我在做 iOS 开发的时候,发现自己在写程序的时候,常常处于两种状态的切换,我把这两种状态称为软件开发的上帝模式与农民模式.我先给大家介绍一下这两种模式的特点. 上帝模式 处于上帝模式时,我需要构思整 ...

  7. SAP连接HANA数据库

    既然都用HANA了,为什么还要在SAP端,连接HANA数据库,做数据库处理..... 因为HANA数据库,没个用户在STADIO上建的数据库表...只能这个用户使用,而做Universe 设计的时候, ...

  8. Objective-C:Foundation框架-常用类-NSObject

    NSObject是所有类的基类,其常见用法有: #import <Foundation/Foundation.h> @interface Person : NSObject - (void ...

  9. 盘点十大最流行的Linux服务器发行版

    随着Linux不断发展,Linux所支持的文件系统类型也在迅速扩充.很多的数据中心服务器上都运行着Linux,可以节省大量的许可证费用及维护费用.但伴随着Linux新版本的发行,其中每一个不同版本的L ...

  10. shell 下的$符合

    $n        $1 the first parameter,$2 the second...$#        The number of command-line parameters.$0  ...