一,发生粘包

服务器端

 from socket import *
phone=socket(AF_INET,SOCK_STREAM) #套接字
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #解决端口占用
phone.bind(('127.0.0.1',8080)) #绑定端口和Ip到套接字
phone.listen(5)
conn,client_addr=phone.accept() #等待tcp接受 # data1=conn.recv(10)
# print('data1: ',data1)
# data2=conn.recv(4)
# print('data2:',data2)
#接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,
#服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

客户端

 from socket import *
import time
phone=socket(AF_INET,SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) # phone.send('helloworld'.encode('utf-8'))
# phone.send('egon'.encode('utf-8'))
#发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

二,用struct模块解决粘包问题

为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据

 #_*_coding:utf-8_*_
#http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html
__author__ = 'Linhaifeng'
import struct
import binascii
import ctypes values1 = (1, 'abc'.encode('utf-8'), 2.7)
values2 = ('defg'.encode('utf-8'),101)
s1 = struct.Struct('I3sf')
s2 = struct.Struct('4sI') print(s1.size,s2.size)
prebuffer=ctypes.create_string_buffer(s1.size+s2.size)
print('Before : ',binascii.hexlify(prebuffer))
# t=binascii.hexlify('asdfaf'.encode('utf-8'))
# print(t) s1.pack_into(prebuffer,0,*values1)
s2.pack_into(prebuffer,s1.size,*values2) print('After pack',binascii.hexlify(prebuffer))
print(s1.unpack_from(prebuffer,0))
print(s2.unpack_from(prebuffer,s1.size)) s3=struct.Struct('ii')
s3.pack_into(prebuffer,0,123,123)
print('After pack',binascii.hexlify(prebuffer))
print(s3.unpack_from(prebuffer,0)) 关于struct的详细用法

服务器端

 import socket
import subprocess
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8088)) #绑定手机卡
phone.listen(5) #开机 print('starting...')
while True: #链接循环
conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
print('-------->',conn,client_addr) #收,发消息
while True:#通信循环
try:
cmd=conn.recv(1024)
print(cmd)
if not cmd:break #针对linux
#执行cmd命令,拿到cmd的结果,结果应该是bytes类型
#。。。。
res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=res.stdout.read()
stderr=res.stderr.read()
print(stdout) #先发报头(转成固定长度的bytes类型)
header = struct.pack('i',len(stdout)+len(stderr))
print(header)
conn.send(header)
#再发送命令的结果
conn.send(stdout)
conn.send(stderr)
except Exception:
break
conn.close() #挂电话
phone.close() #关机

客户端

 import socket
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.connect(('127.0.0.1',8088)) #绑定手机卡 #发,收消息
while True:
cmd=input('>>: ').strip()
if not cmd:continue phone.send(cmd.encode('utf-8'))
#先收报头
header_struct=phone.recv(4)
print(header_struct)
unpack_res = struct.unpack('i', header_struct)
total_size=unpack_res[0]
print(total_size) #再收数据
recv_size=0 #10241=10240+1
total_data=b''
while recv_size < total_size:
recv_data=phone.recv(1024)
print(recv_data)
recv_size+=len(recv_data)
print(recv_size)
total_data+=recv_data
print(total_data)
# else:
print(total_data.decode('gbk'))
phone.close()

三,大文件粘包问题

服务器端

 import socket
import subprocess
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8082)) #绑定手机卡
phone.listen(5) #开机 print('starting...')
while True: #链接循环
conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
print('-------->',conn,client_addr) #收,发消息
while True:#通信循环
try:
cmd=conn.recv(1024)
if not cmd:break #针对linux
#执行cmd命令,拿到cmd的结果,结果应该是bytes类型
#。。。。
res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=res.stdout.read()
stderr=res.stderr.read()
#制作报头
header_dic = {
'total_size': len(stdout)+len(stderr),
'filename': None,
'md5': None} header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
#发送阶段
#先发报头长度
conn.send(struct.pack('i',len(header_bytes)))
#再发报头
conn.send(header_bytes) #最后发送命令的结果
conn.send(stdout)
conn.send(stderr)
except Exception:
break
conn.close() #挂电话
phone.close() #关机

客户端

 import socket
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.connect(('127.0.0.1',8082)) #绑定手机卡 #发,收消息
while True:
cmd=input('>>: ').strip()
if not cmd:continue phone.send(cmd.encode('utf-8'))
#先收报头的长度
header_len=struct.unpack('i',phone.recv(4))[0] #再收报头
header_bytes=phone.recv(header_len)
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
total_size=header_dic['total_size'] #最后收数据
recv_size=0 #10241=10240+1
total_data=b''
while recv_size < total_size:
recv_data=phone.recv(1024)
recv_size+=len(recv_data)
total_data+=recv_data
print(total_data.decode('gbk'))
phone.close()

四,udp套接字

服务器端

 from socket import *
udp_server=socket(AF_INET,SOCK_DGRAM)
udp_server.bind(('127.0.0.1',8088)) while True:
msg,client_addr=udp_server.recvfrom(1024)
print('has recv %s' %msg)
udp_server.sendto(msg.upper(),client_addr)
print('has send')
udp_server.close()

客户端

 from socket import *
udp_client=socket(AF_INET,SOCK_DGRAM) while True:
msg=input('>>: ').strip()
udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8088))
print('has send')
# res,server_addr=udp_client.recvfrom(1024)
# print('====>',res.decode('utf-8')) udp_client.close()

udp 套接字不会发生粘包

服务器端

 from socket import *
udp_server=socket(AF_INET,SOCK_DGRAM)
udp_server.bind(('127.0.0.1',8089)) msg1,client_addr=udp_server.recvfrom(5)
print(msg1) msg2,client_addr=udp_server.recvfrom(5)
print(msg2)

客户端

 from socket import *
udp_client=socket(AF_INET,SOCK_DGRAM) udp_client.sendto('hello'.encode('utf-8'),('127.0.0.1',8089))
udp_client.sendto('world'.encode('utf-8'),('127.0.0.1',8089))

五,socketserver套接字

封装了socket,而且解决了Io阻塞问题

服务端

 # socketserver模块多进程,多线程
# 无论你开什么都是开线程,线程就有IO,这个模块帮你解决这个IO问题 # 基础版本,遇到问题,不能无限开线程,而且没有解决IO
# 线程开启跟进程开启一样
from socket import *
from threading import Thread
# s=socket(AF_INET,SOCK_STREAM)
# s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
# s.bind(('127.0.0.1',8090))
# s.listen(5)
# def talk(conn,addr):
# while True: #通信循环
# try:
# data=conn.recv(1024)
# if not data:break
# conn.send(data.upper())
# except Exception:
# break
# conn.close()
# if __name__ == '__main__':
# while True:#链接循环
# conn,addr=s.accept()
# p = Thread(target=talk,args=(conn,addr))
# p.start()
# s.close() # socketserver模块套接字,自动处理IO问题
import socketserver
class MyTCPhandler(socketserver.BaseRequestHandler): #必须继承这个类
def handle(self):
# print(self.request) 打印出来的就是conn
# print(self.client_address) 打印出来的就是addr
while True:
try:
data=self.request.recv(1024)
if not data:break
self.request.send(data.upper())
except Exception:
break
self.request.close()
if __name__ == '__main__':
server=socketserver.ThreadingTCPServer(('127.0.0.1',8082),MyTCPhandler) #多线程
# 三个参数,IP,端口,类
# server=socketserver.ForkingTCPServer(('127.0.0.1',8082),MyTCPhandler) #多进程
server.allow_reuse_address=True #重用地址
server.serve_forever() #永远运行,就是一直开着,相当于while True

客户端

 from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8082)) while True:
msg=input('>>: ').strip()
if not msg:continue
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode("utf-8"))

python开发socket套接字:粘包问题&udp套接字&socketserver的更多相关文章

  1. Python之路 - 网络编程之粘包

    Python之路 - 网络编程之粘包 粘包

  2. tcp粘包,udp丢包

    TCP是面向流的, 流, 要说明就像河水一样, 只要有水, 就会一直流向低处, 不会间断. TCP为了提高传输效率, 发送数据的时候, 并不是直接发送数据到网路, 而是先暂存到系统缓冲, 超过时间或者 ...

  3. python笔记8 socket(TCP) subprocess模块 粘包现象 struct模块 基于UDP的套接字协议

    socket 基于tcp协议socket 服务端 import socket phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 买 ...

  4. Python开发【socket篇】解决粘包

    客户端 import os import json import struct import socket sk = socket.socket() sk.connect(('127.0.0.1',8 ...

  5. python socket网络编程之粘包问题详解

    一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用 ...

  6. (网络编程)基于tcp(粘包问题) udp协议的套接字通信

    import   socket 1.通信套接字(1人1句)服务端和1个客户端 2.通信循环(1人多句)服务端和1个客户端 3.通信循环(多人(串行)多句)多个客户端(服务端服务死:1个客户端---&g ...

  7. python 全栈开发,Day35(TCP协议 粘包现象 和解决方案)

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...

  8. tcp套接字粘包解决办法

    粘包只会出现在tcp,udp传输不会产生粘包现象.解决粘包的原理就是服务器预先向客户端发送客户端即将获取文件的大小. 第一版解决方案: 服务器: # Author : Kelvin # Date : ...

  9. python全栈开发day28-网络编程之粘包、解决粘包,上传和下载的作业

    一.昨日内容回顾 1. tcp和udp编码 2. 自定义mysocket解决编码问题 二.今日内容总结 1.粘包 1)产生粘包原因: (1).接收方不知道消息之间的边界,不知道一次性要取多少字节的数据 ...

随机推荐

  1. SpannableString实现TextView的链接效果

    SpannableString实现TextView的链接效果 一.简介 TextView使用SpannableString设置复合文本TextView通常用来显示普通文本,但是有时候需要对其中某些文本 ...

  2. spring3: AOP 之代理机制

    Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理.CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理. JDK动态代理:使用java.lang.reflect ...

  3. Educational Codeforces Round 38

    http://codeforces.com/contest/938 A:sb题 //#pragma comment(linker, "/stack:200000000") //#p ...

  4. msbuild编译

    @echo offcd /d %~dp0 if exist output.log del /q /f output.logif exist success.txt del /q /f success. ...

  5. Prism5.0新内容(纯汉语版)

    Prism 5.0 包含很多新东西,新的快速入门示例,新的范例,更新的文档,Prism类库代码的改变.用来解决已有问题,回应社区所提的需求.(这句话跟 What's New in Prism Libr ...

  6. 20165210 Java第五次实验报告

    20165210 实验五 网络编程与安全 网络编程与安全一: 实验要求: 两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA ...

  7. 【设计模式】calendar的单例需求和实现

    calendar单例需求: 参数:有default的calendar file 1.如果无实例,无参数调用,取default,检查是否合法,存入实例 2.如果无实例,有参数调用,检查是否合法,存入实例 ...

  8. Leetcode 1020. Number of Enclaves

    dfs或者bfs class Solution: def dfs(self, A, rows, cols, i, j): if not (0 <= i < rows and 0 <= ...

  9. js类 的小例子

    class Flyer { constructor(fname, speed) { this.fname = fname; this.speed = speed; } fly(){ console.l ...

  10. Delphi Xe4 游戏开发的技术选型.

    asphyre 是支持 FireMonkey的. 利用Firemonkey的跨平台接口.实现 win,mac,ios. 其它方案估计就得靠 FPC 了. 好处是多了输出Andriod的可能. zeng ...