漫天飞雪

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
-------------------------------------------------------------------------------------------------------------------


tcp套接字通信的进阶实现如下:
# 基于tcp套接字‘一次性通信’-------------------------------------------1------------------------------------------
模拟电话通信
1:用打电话的流程快速描述socket通信
2:服务端和客户端加上基于一次链接的循环通信
3:客户端发送空,卡主,证明是从哪个位置卡的
存在的问题:
1.必须是服务端先启动,然后客户端再启动
2.客户端发送完成后就断开链接,只发送、接收一次
3.客户端再次请求发送的话就会报错
# 服务端
from socket import *
# 基于tcp通信的套接字
phone=socket(AF_INET,SOCK_STREAM)#建立tcp流式协议
phone.bind(('127.0.0.1',8080))#绑定ip和端口
phone.listen(5)#监听连接数请求
conn,addr=phone.accept()#存放客户端ip和port的数据元组
data=conn.recv((1024))#接收请求信息
conn.send(data.upper())#发送求情返回的信息
conn.close()#关闭客服端套接字
phone.close()#关闭服务器套接字
客服端
from socket import *
phone=socket(AF_INET,SOCK_STREAM)#建立tcp流式协议
phone.connect(('127.0.0.1',8080))#建立链接
phone.send('hell0,fuwuduan'.encode('utf-8'))#编码,因为只能发送bytes类型的数据
data=phone.recv(1024)#客服端接收来至服务端信息
print(data)
phone.close()#关闭客服端套接字
# 基于tcp套接字‘循环通信’-------------------------------------------2------------------------------------------
基于tcp通信的套接字循环通信
存在的问题:
1.必须是服务端先启动,然后客户端再启动
2.虽然是实现了通信的持续进行,但是客服端关闭后服务端就会报错
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
# # 服务端
from socket import *

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8080))
sever.listen(5)
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
data = conn_client.recv((1024))
print(data)
conn_client.send(data.upper())
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()

# 客服端
from socket import *
client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8080)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
msg = input('输入信息:').strip()
client.send(msg.encode('utf-8')) # 编码,因为只能发送bytes类型的数据
data = client.recv(1024) # 客服端接收来至服务端返回的信息
print(data)
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字
# 基于tcp套接字‘循环通信’-------------------------------------------3------------------------------------------

基于tcp通信的套接字循环通信
存在的问题:
1.实现了通信的循环通信,但是只是单链接的,需要实现多链接循环的请求通信


# 服务端
from socket import *

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8080))
sever.listen(5)
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
try:
data = conn_client.recv((1024))
if len(data) == 0: break # 针对linux系统
print(data)
conn_client.send(data.upper())
except ConnectionResetError:#添加异常报错接收机制,这样就会拦截了因客服端关闭触发的客服端异常断开链接的报错
break
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()
# 客服端
from socket import *
client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8080)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
msg = input('输入信息:').strip()
client.send(msg.encode('utf-8')) # 编码,因为只能发送bytes类型的数据
data = client.recv(1024) # 客服端接收来至服务端返回的信息
print(data)
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字
# 基于tcp套接字‘链接循环通信’-------------------------------------------4------------------------------------------

基于tcp通信的套接字实现链接循环通信

# 服务端
from socket import *

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8081))
sever.listen(5)
while True:
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
try:
data = conn_client.recv((1024))
if len(data) == 0: break # 针对linux系统
print(data)
conn_client.send(data.upper())
except ConnectionResetError:#添加异常报错接收机制,这样就会拦截了因客服端关闭触发的客服端异常断开链接的报错
break
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()

# 客服端
from socket import *
client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8081)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
msg = input('输入信息:').strip()
if len(msg) == 0: continue
client.send(msg.encode('utf-8')) # 编码,因为只能发送bytes类型的数据
data = client.recv(1024) # 客服端接收来至服务端返回的信息
print(data)
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字


----------------------------------------------出现粘包问题---------------------------------------------------------------------
小贴士:
运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,
并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,
并运行一个外部的程序。具体使用请参见百度搜索获得相关详细信息。

tcp套接字实现通信功能需求

基于tcp通信的套接字实现ssh远程执行命令
存在的问题:
1.请注意客服端cmd_res = client.recv(1024),如果接收的数据字节超过了1024,就会出现粘包,个人理解就是输出未完全接收全,
就会导致后面的cmd执行时,客服端接收的数据任然存在上一次cmd的结果,出现混乱现象
思路:
1.可以调节客服端接收的字节数,但是在不知接收数据情况下,怎么办呢?麻爪子了吧,哈哈哈

# 服务端
from socket import *
import subprocess

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8081))
sever.listen(5)
while True:
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
try:
cmd = conn_client.recv((1024))
if len(cmd) == 0: break # 针对linux系统
obj=subprocess.Popen(cmd.decode('utf-8'), #解码bytes类型数据
shell=True, #程序将通过shell来执行
stdout=subprocess.PIPE,#标准输出
stderr=subprocess.PIPE #标准错误输出
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
print(len(stdout)+len(stderr))
conn_client.send(stdout+stderr)
except ConnectionResetError:#添加异常报错接收机制,这样就会拦截了因客服端关闭触发的客服端异常断开链接的报错
break
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()

# 客服端
from socket import *
client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8081)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
cmd = input('输入信息:').strip()
if len(cmd) == 0: continue
client.send(cmd.encode('utf-8')) # 编码,因为只能发送bytes类型的数据
cmd_res = client.recv(102400) # 客服端接收来至服务端返回的信息
print(cmd_res.decode('gbk'))#如果不加上gbk进行解码的话,都是字节型的数据,看不懂得大胸弟
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字
----------------------------------------------出现粘包问题---------------------------------------------------------------------

tcp套接字实现通信功能需求

基于tcp通信的套接字实现ssh远程执行命令
存在的问题:
1.请注意客服端cmd_res = client.recv(1024),如果接收的数据字节超过了1024,就会出现粘包,个人理解就是输出未完全接收全,
就会导致后面的cmd执行时,客服端接收的数据任然存在上一次cmd的结果,出现混乱现象
思路:
1.可以调节客服端接收的字节数,但是在不知接收数据情况下,怎么办呢?麻爪子了吧,哈哈哈

# 服务端
from socket import *
import subprocess

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8081))
sever.listen(5)
while True:
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
try:
cmd = conn_client.recv((1024))
if len(cmd) == 0: break # 针对linux系统
obj=subprocess.Popen(cmd.decode('utf-8'),#解码bytes类型数据
shell=True,
stdout=subprocess.PIPE,#标准输出
stderr=subprocess.PIPE#标准错误输出
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
print(len(stdout)+len(stderr))
conn_client.send(stdout+stderr)
except ConnectionResetError:#添加异常报错接收机制,这样就会拦截了因客服端关闭触发的客服端异常断开链接的报错
break
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()

# 客服端
from socket import *
client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8081)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
cmd = input('输入信息:').strip()
if len(cmd) == 0: continue
client.send(cmd.encode('utf-8')) # 编码,因为只能发送bytes类型的数据
cmd_res = client.recv(102400) # 客服端接收来至服务端返回的信息
print(cmd_res.decode('gbk'))
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字


----------------------------------------------解决粘包问题---------------------------------------------------------------------
小贴士:
struct模块
在网络通信当中,大多传递的数据是以二进制流(binary data)存在的。当传递字符串时,不必担心太多的问题,而当传递诸如int、
char之类的基本数据的时候,就需要有一种机制将某些特定的结构体类型打包成二进制流的字符串然后再网络传输,而接收端也应该
以通过某种机制进行解包还原出原始的结构体数据。python中的struct模块就提供了这样的机制,该模块的主要作用就是对python基
本类型值与用python字符串格式表示的C struct类型间的转化。
可用于打包,解包,详细情况,有兴趣的话可以‘google一下’

基于tcp通信的套接字实现ssh远程执行命令,粘包问题解决

# 服务端
from socket import *
import subprocess
import struct
import json

sever = socket(AF_INET, SOCK_STREAM)
sever.bind(('127.0.0.1', 8081))
sever.listen(5)
while True:#链接循环
# ---------------------------------建立链接------------------------------
conn_client, addr = sever.accept() # 存放客户端ip和port的数据元组
# ---------------------------------发送数据------------------------------
while True: # 通信循环
try:
cmd = conn_client.recv(1024)
if len(cmd) == 0: break # 针对linux系统
obj = subprocess.Popen(cmd.decode('utf-8'), # 解码bytes类型数据
shell=True,
stdout=subprocess.PIPE, # 标准输出
stderr=subprocess.PIPE # 标准错误输出
)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
# 1.先制作固定长度的报头
header = {
'filename': 'a.txt',
'md5': 'adasdsadasd',
'total_size': len(stdout) + len(stderr)
}
# 将字典转化成序列化数据json
header_json = json.dumps(header)
# 将json类型转化成bytes类型
header_bytes = header_json.encode('utf-8')

# 2.报头制作好之后发送4个bytes的报头长度
conn_client.send(struct.pack('i', len(header_bytes)))

# 3.再发送报头
conn_client.send(header_bytes)

# 4.最后发送真实的数据
conn_client.send(stdout)
conn_client.send(stderr)
except ConnectionResetError: # 添加异常报错接收机制,这样就会拦截了因客服端关闭触发的客服端异常断开链接的报错
break
# ---------------------------------断开链接------------------------------
conn_client.close()
sever.close()

# 客服端
from socket import *
import struct
import json

client = socket(AF_INET, SOCK_STREAM) # 建立tcp流式协议
# ---------------------------------建立链接------------------------------
client.connect(('127.0.0.1', 8081)) # 建立链接

# ---------------------------------发送数据------------------------------
while True: # 通信循环
cmd = input('输入信息:').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8')) # 编码,因为只能发送bytes类型的数据

# 1.先接收4bytes解析出来的报头长度
header_size = struct.unpack('i', client.recv(4))[0]

# 2.在接收报头,获取报头中的header_dic字典
header_bytes = client.recv(header_size)
# 将报头的bytes类型转化成json类型
header_json = header_bytes.decode('utf-8')
# 再将json类型的数据反序列化成原来数据,拿到报头字典
header_dic = json.loads(header_json)
# 获取数据大小
total_size = header_dic['total_size']

# 3.接收服务端返回的真正的数据
cmd_res = b''
recv_size = 0
while recv_size < total_size:
data = client.recv(1024)
recv_size += len(data)
cmd_res += data
print(cmd_res.decode('gbk'))
# ---------------------------------断开链接------------------------------
client.close() # 关闭客服端套接字
posted on 2018-12-27 09:02  漫天飞雪世情难却  阅读(154)  评论(0编辑  收藏  举报