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
BaseRequestHandler
class 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下编程了,这次因为需要做一个跨平台的网络程序,就先 ...
随机推荐
- ERROR 1130: Host 'root@localhost' is not allowed to connect to MySQL server
连接mysql时遇到的错误. 原因:该用户没有权限连接访问mysql数据库 解决方法:网站上搜了好多,试了都没有用.最终在登陆的信息页面用root用户登陆时不输入root密码即可.
- 为什么要使用SLF4J而不是Log4J
每一个Java程序员都知道日志对于任何一个Java应用程序,尤其是服务端程序是至关重要的,而很多程序员也已经熟悉各种不同的日志库如java.util.logging.Apache log4j.lo ...
- Qt之QSequentialAnimationGroup
简述 QSequentialAnimationGroup类提供动画的串行组. QSequentialAnimationGroup是一个串行运行动画的QAnimationGroup,在另一个动画播放结束 ...
- OSVERSIONINFO
OSVERSIONINFO结构 OSVERSIONINFO结构包含了操作系统的版本信息,包括操作系统的主版本号.副版本号.创建号.以及操作系统平台ID号和关于操作系统的其他描述信息.其定义为: typ ...
- jsp-------------之分页技术(一)
jsp分页技术之: 如下图:百度的喵 看上图中卡哇伊的小苗的爪子下面的数字,就是分页啦!那我们如何做出这样一个效果呢? 下面我们来逐一分解: jsp分页技术一 : (算法) /* int pageS ...
- DataTable 中Distinct操作
DataTable dt = ds.Tables[]; DataView dataView = dt.DefaultView; DataTable dtDistinct = dataView.ToTa ...
- iOS:控制器间的数据传递
在iOS开发中遇到的控制器间的数据传递主要有两种情况:顺传递与逆传递.顺传递是指数据的传递方向和控制器的跳转方向相同(如图1):逆传递是指数据的传递方向和控制器的跳转方向相反(如图2).这里分别介绍这 ...
- Java开发 Eclipse使用技巧(转)
1.如何设置默认的代码目录为src,默认的输出目录为bin? window->Preferences->java->Build Path中,右侧选择Folders就可以 2.如何为快 ...
- Objective-C(NSString、BOOL、多文件开发)
NSString 表示oc当中的字符串类 %@是oc当中对象的格式符 printf不能打印oc当中的对象 通过stringWithFormat:这个类方法,打印格式化的字符串 例 int a = 10 ...
- Android WebView的使用
WebView是View的一个子类,使用它可以在App中嵌入H5页面,可以跟js互相调用. webview有两个方法:setWebChromeClient和setWebClient setWebCli ...