Python中的Socket 与 ScoketServer 通信及遇到问题解决方法


Posted in Python onApril 01, 2019

Socket有一个缓冲区,缓冲区是一个流,先进先出,发送和取出的可自定义大小的,如果取出的数据未取完缓冲区,则可能存在数据怠慢。其中【recv(1024)】表示从缓冲区里取最大为1024个字节,但实际取值大小是不确定的,推荐其值小于等于8192。

黏包问题:

Socket发送两条连续数据时,可能最终会拼接成一条进行发送

解决方法一:

两条数据间进行延时发送,如【tiem.sleep(0.5) #延时0.5s】

解决方法二:

每次发送后等待对方确认接收信息数据,发送一条后就立即接收等待

解决方法三:

设定接收数据大小,发送端每次发送需要发送的数据的数据大小,接收端通过设置【recv(xx)】只接收确定的大小

Socket基本使用:

简单的服务器:

import socket
sser=socket.socket()#得到socket对象
sser.bind(("0.0.0.0",2699))#建立监听
sser.listen(3)
print("等等客户端连接")
conn,addr=sser.accept() #等待连接,会一直处于阻塞,返回连接对象和对方地址
print("有客户端已经连接,IP地址和端口为:",addr)
#接收数据,会一直阻塞,建议低于8192
#使用连接对象操作
rdata=conn.recv(1024)
print(rdata.decode("gbk"))
conn.send("服务器返回,收到数据".encode("gbk"))#发送数据,使用连接对象操作
#关闭连接
sser.close()

简单的客户端:

import socket
sclient=socket.socket()#得到socket对象
#连接服务器
#失败会报错:ConnectionRefusedError
sclient.connect(("192.168.1.135",2699))
sclient.send("东小东".encode("gbk"))#发送数据
#接收数据,会一直阻塞,建议低于8192
rdata=sclient.recv(1024)
print(rdata.decode("gbk"))
#关闭连接
sclient.close()

Soket进阶:

服务器进阶:

实现客户循环连接及数据循环收发和判断客户端是否断开

import socket
sser=socket.socket()#得到socket对象
sser.bind(("0.0.0.0",2699))#建立监听
sser.listen(3)
while True:
  print("等等客户端连接")
  conn,addr=sser.accept() #等待连接,会一直处于阻塞,返回连接对象和对方地址
  print("有客户端已经连接,IP地址和端口为:",addr)
  conn.send(("服务器欢迎你:%s\r\n"%(str(addr))).encode("gbk")) # 发送数据,使用连接对象操作
  while True:
    #接收数据,会一直阻塞
    #使用连接对象操作
    rdata=conn.recv(1024)
    if not rdata: break #判断客户端是否断开,断开则收到空数据
    print(rdata.decode("gbk"))
    conn.send("服务器返回,收到数据\r\n".encode("gbk"))#发送数据,使用连接对象操作
#关闭连接
sser.close()

客户端进阶:

实现循环收发和判断服务器是否断开

import socket
sclient=socket.socket()#得到socket对象
#连接服务器
#失败会报错:ConnectionRefusedError
sclient.connect(("192.168.1.135",2699))
while True:
 #接收数据,会一直阻塞
 rdata=sclient.recv(1024)
 if not rdata: break # 判断服务器是否断开,断开则收到空数据
 print(rdata.decode("gbk"))
 sclient.send(("客户端收到数据:%s\r\n"%rdata.decode("gbk")).encode("gbk")) # 发送数据
#关闭连接
sclient.close()

注意:

发送数据不可发送空字符,否则会卡住,解决方法为判断输入的是否为空值,空值则进行数据发送

strx=input("输入:").strip()#得到控制台输入值
if(len(strx)==0):continue #如果为空字符,则跳出本次循环
print(strx) #打印
sclient.send(strx.encode("gbk")) # 发送数据

发送大数据:

先发送总体数据大小,socket另一端判断实际接收的数据大小与总数据大小进行比较,循环recv()进行数据接收

 简单的ssh实现:

服务端:

import os
import socket
sser=socket.socket()#得到socket对象
sser.bind(("0.0.0.0",2697))#建立监听
sser.listen(3)
while True:
  print("等等客户端连接")
  conn,addr=sser.accept() #等待连接,会一直处于阻塞,返回连接对象和对方地址
  print("有客户端已经连接,IP地址和端口为:",addr)
  conn.send(("服务器欢迎你:%s\r\n"%(str(addr))).encode("gbk")) # 发送数据,使用连接对象操作
  while True:
    #接收数据,会一直阻塞
    rdata=conn.recv(1024)
    if not rdata: break #判断客户端是否断开,断开则收到空数据
    sendtox=os.popen(rdata.decode("gbk")).read() #执行命令
    conn.send(str(len(sendtox)).encode("gbk")) #发送执行命令的结果长度
    #如果长度大于0 则发送命令结果数据
    if len(sendtox)>0:
    if conn.recv(10).decode("gbk")=="1":
     conn.sendall(sendtox.encode("gbk"))#发送最终数据
#关闭连接
sser.close()

客户端:

import socket
sclient=socket.socket()#得到socket对象
#连接服务器
#失败会报错:ConnectionRefusedError
sclient.connect(("192.168.43.21",2697))
# 接收数据,会一直阻塞
rdata = sclient.recv(1024)
print(rdata.decode("gbk"))
while True:
 strx = input("请输入命令:").strip() # 得到控制台输入值
 if (len(strx) == 0): continue # 如果为空字符,则跳出本次循环
 sclient.send(strx.encode("gbk")) # 发送数据
 rdata = sclient.recv(10)
 if not rdata: break # 判断服务器是否断开,断开则收到空数据
 #判断命令是否执行成功,0为失败
 dataall=int(rdata.decode("gbk"))
 if dataall==0:
  continue
 sclient.send("1".encode("gbk")) # 发送确认接收数据命令
 #循环接收数据
 datanew=0
 while dataall !=datanew:
  rdata=sclient.recv(1024).decode("gbk")
  datanew+=len(rdata)
  print(rdata)
#关闭连接
sclient.close()

发送文件:

发送文件,使用read()读取文件数据后,可循环调用send()发送数据,或者使用sendall()一次性发送所有数据,socket另一端接收可循环recv()进行数据接收,且每次接收的数据大小是不确定的。文件传输需要验证发送和接受的数据是否完全一致,可以通过数据大小加md5双重验证,发送端:md5在每次发送一条数据时进行update(),在数据发送完成后再发送md5值;接受端:md5在每次接收到一条数据后进行update(),在文件接收完成后再接收发送端发送的md5值,将两值进行比较,相同则表示传输无丢包,但加入md5校验,将会影响传输速率。

发送文件数据:先发送总体数据大小,socket另一端判断实际接收的数据大小与总数据大小进行比较,循环recv()进行数据接收

示例:客户端发送文件名,服务器判断文件是否存在,如果不存在或者是空文件则不进行传输,服务器进行文件发送,客户端实现文件接收

服务器

import os
import socket
sser=socket.socket()#得到socket对象
sser.bind(("0.0.0.0",2697))#建立监听
sser.listen(3)
while True:
  print("等等客户端连接")
  conn,addr=sser.accept() #等待连接,会一直处于阻塞,返回连接对象和对方地址
  print("有客户端已经连接,IP地址和端口为:",addr)
  conn.send(("服务器欢迎你:%s\r\n"%(str(addr))).encode("gbk")) # 发送数据,使用连接对象操作
  while True:
    #接收数据,会一直阻塞
    rdata=conn.recv(1024)
    if not rdata: break #判断客户端是否断开,断开则收到空数据
    filesize=0
    filenamex=rdata.decode("gbk")
    if os.path.isfile(filenamex): #判断是否是文件
     filesize=os.stat(filenamex).st_size #得到文件大小
    conn.send(str(filesize).encode("gbk")) #不是文件则发送0,是文件则是实际大小
    #如果文件大小大于0 则发送文件
    if filesize>0:
    if conn.recv(10).decode("gbk")=="1": #等待确认接收命令
     #一行一行发送数据
     f=open(filenamex,"rb")
     for linex in f:
      conn.sendall(linex)#发送最终数据
#关闭连接
sser.close()

客户端

import socket
sclient=socket.socket()#得到socket对象
#连接服务器
#失败会报错:ConnectionRefusedError
sclient.connect(("192.168.43.21",2697))
# 接收数据,会一直阻塞
rdata = sclient.recv(1024)
print(rdata.decode("gbk"))
while True:
 filenamex = input("请输入文件名:").strip() # 得到控制台输入值
 if (len(filenamex) == 0): continue # 如果为空字符,则跳出本次循环
 sclient.send(filenamex.encode("gbk")) # 发送数据
 rdata = sclient.recv(10)
 if not rdata: break # 判断服务器是否断开,断开则收到空数据
 #判断命令是否执行成功,0为失败
 dataall=int(rdata.decode("gbk"))
 if dataall==0:
  print("文件不存在或者为空")
  continue
 sclient.send("1".encode("gbk")) # 发送确认接收数据命令
 #打开文件
 f=open(filenamex,"wb")
 #循环接收数据
 datanew=0
 while dataall !=datanew:
  rdata=sclient.recv(1024)
  datanew+=len(rdata)
  f.write(rdata)
 print("文件(%s)接收完毕"%filenamex)
 f.close() #关闭文件
#关闭连接
sclient.close()

ScoketServer

服务端实现多并发效果,可以同时接入多个客户端

import socketserver
#建立一个类,必须继承 socketserver.BaseRequestHandler 类
class DongSocket(socketserver.BaseRequestHandler):
 #必须重写handle方法
 def handle(self):
  print("建立新连接,对方地址为:{}".format(self.client_address))
  while True:
   try:
    self.datax=self.request.recv(1024).decode("gbk") #接收数据
    print("接收的数据为:%s"%self.datax)
    self.request.send(("服务器返回数据:%s"%self.datax).encode("gbk"))
   except Exception as e:
    print("断开,再见:{}".format(self.client_address))
    break
#参数:(("ip",端口),自定义类)
#ss=socketserver.TCPServer(("0.0.0.0",2351),DongSocket) #与之前的socket服务器效果一致,同时只能连接一个客户端
ss=socketserver.ThreadingTCPServer(("0.0.0.0",2351),DongSocket) #同时可以连接多个客户端,多并发
ss.serve_forever()

总结

以上所述是小编给大家介绍的Python中的Socket 与 ScoketServer 通信及遇到问题解决方法 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python文件夹与文件的操作实现代码
Jul 13 Python
Python使用py2exe打包程序介绍
Nov 20 Python
python使用多线程不断刷新网页的方法
Mar 31 Python
python统计日志ip访问数的方法
Jul 06 Python
python中异常报错处理方法汇总
Nov 20 Python
PyQt5每天必学之日历控件QCalendarWidget
Apr 19 Python
Python文件如何引入?详解引入Python文件步骤
Dec 10 Python
Python跳出多重循环的方法示例
Jul 03 Python
Django中自定义admin Xadmin的实现代码
Aug 09 Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
Mar 20 Python
详解用Python爬虫获取百度企业信用中企业基本信息
Jul 02 Python
python 如何将两个实数矩阵合并为一个复数矩阵
May 19 Python
python assert的用处示例详解
Apr 01 #Python
使用Python操作FTP实现上传和下载的方法
Apr 01 #Python
Python提取特定时间段内数据的方法实例
Apr 01 #Python
如何使用Python进行OCR识别图片中的文字
Apr 01 #Python
Python datetime和unix时间戳之间相互转换的讲解
Apr 01 #Python
详解Python网络框架Django和Scrapy安装指南
Apr 01 #Python
详解python的argpare和click模块小结
Mar 31 #Python
You might like
PHP explode()函数用法、切分字符串
2012/10/03 PHP
PHP遍历并打印指定目录下所有文件实例
2014/02/10 PHP
javascript 写类方式之一
2009/07/05 Javascript
使用JQuery进行跨域请求
2010/01/25 Javascript
JS中令人发指的valueOf方法介绍
2013/02/22 Javascript
js获取客户端网卡的IP地址、MAC地址
2014/03/26 Javascript
javaScript中slice函数用法实例分析
2015/06/08 Javascript
JS判断是否长按某一键的方法
2016/03/02 Javascript
Bootstrap每天必学之折叠
2016/04/12 Javascript
JS与jQuery实现隔行变色的方法
2016/09/09 Javascript
超全面的JavaScript开发规范(推荐)
2017/01/21 Javascript
关于使用axios的一些心得技巧分享
2017/07/02 Javascript
js变量声明var使用与不使用的区别详解
2019/01/21 Javascript
vue+iview动态渲染表格详解
2019/03/19 Javascript
element跨分页操作选择详解
2020/06/29 Javascript
js定时器出现第一次延迟的原因及解决方法
2021/01/04 Javascript
[33:28]完美世界DOTA2联赛PWL S3 PXG vs GXR 第三场 12.19
2020/12/24 DOTA
快速入门python学习笔记
2017/12/06 Python
网易2016研发工程师编程题 奖学金(python)
2019/06/19 Python
Python文件操作中进行字符串替换的方法(保存到新文件/当前文件)
2019/06/28 Python
基于pytorch的保存和加载模型参数的方法
2019/08/17 Python
详解Python3迁移接口变化采坑记
2019/10/11 Python
Python箱型图绘制与特征值获取过程解析
2019/10/22 Python
html5 学习简单的拾色器
2010/09/03 HTML / CSS
HTML5在线预览PDF的示例代码
2017/09/14 HTML / CSS
公积金转移接收函
2014/01/11 职场文书
一年级小学生评语
2014/04/22 职场文书
2014年学校国庆主题活动方案
2014/09/16 职场文书
解除劳动合同协议书
2014/09/17 职场文书
2014年工商所工作总结
2014/12/09 职场文书
安装工程师岗位职责
2015/02/13 职场文书
博物馆观后感
2015/06/05 职场文书
护士岗前培训心得体会
2016/01/08 职场文书
《称赞》教学反思
2016/02/17 职场文书
MySQL 百万级数据的4种查询优化方式
2021/06/07 MySQL
每日六道java新手入门面试题,通往自由的道路
2021/06/30 Java/Android