socket:socket就是实现服务器和客户端数据的交换,服务器端接收并发送数据,客户端发送并接收数据,并且需要注意的是,在python3中,socket值接收字节。因为客户端在发送连接给服务器的时候,要转换为字节码;服务器端在返回给客户端的时候,也要转换为字节码。

如下所示:

服务器端:

import socket,os
server = socket.socket()
server.bind(("localhost",))
server.listen() while True:
conn,addr = server.accept()
print("new conn:",addr)
while True:
data = conn.recv()
if not data:
print("客户端已断开!")
break
print("执行指令:",data)
cmd_res = os.popen(data.decode()).read()
print("before send",len(cmd_res))
if len(cmd_res) == :
cmd_res = "cmd has no output....."
conn.send(cmd_res.encode('utf-8'))
print("send done") server.close()

上面是服务器端,使用os.popen()实现数据的处理,不过只能处理字符串,因此需要decode()成字符串格式,然后发送的时候要转换为字节码,encode()。

客户端:

import socket
client = socket.socket()
client.connect(("localhost",)) while True:
cmd = input(">>:").strip()
if len(cmd) == :
continue
client.send(cmd.encode('utf-8'))
'''服务器端发送为空,客户端是卡主的'''
cmd_res = client.recv() print(cmd_res.decode()) client.close()

首先启动服务器端,然后启动客户端,如下所示:

    服务器端发送数据:

>>:
cmd has no output.....
>>:dir
build_server.py get_ip.py socket_server.py 客户端创建过程.py
class_method.py lib s_server.py 类的方法.py
class的方法.py property属性.py static_method.py 人类.py
error_handle.py s_client.py 动态导入.py 上节内容
get_attr.py socket_client.py 反射.py >>:ls
build_server.py
class_method.py
class的方法.py
error_handle.py
get_attr.py
get_ip.py
lib
property属性.py
s_client.py
socket_client.py
socket_server.py
s_server.py
static_method.py
动态导入.py
反射.py
客户端创建过程.py
类的方法.py
人类.py
上节内容

    客户端接收数据:

new conn: ('127.0.0.1', )
执行指令: b''
before send
send done
/bin/sh: : : not found
执行指令: b'dir'
before send
send done
执行指令: b'ls'
before send
send done

当客户端卡顿的时候,说明服务器端是没有数据发送过来的,因为客户端不能接收空的数据服务器端也不能接收空的数据。这样就会造成卡顿的情况。

在接收的时候,会有一个缓存,缓存不满的时候,是不会发送数据的,客户端就接收不到数据。

由于缓存的存在,客户端接收数据有时候接收不完整,如何避免呢?要求服务器告诉客户端数据的大小,客户端根据数据的大小来接收数据。

收发一样大,告诉客户端接收数据的大小,如下:

服务器端:

import socket,os,time
server = socket.socket()
server.bind(("localhost",))
server.listen() while True:
conn,addr = server.accept()
print("new conn:",addr)
while True:
data = conn.recv()
if not data:
print("客户端已断开!")
break
print("执行指令:",data)
cmd_res = os.popen(data.decode()).read()
print("before send",len(cmd_res))
if len(cmd_res) == :
cmd_res = "cmd has no output....."
conn.send(str(len(cmd_res)).encode('utf-8')) #先发送数据的大小给客户端 第一个send()发送数据
time.sleep() #连续发送数据会造成粘包现象,因此要有区分,不然容易粘包,这里让程序休眠一秒,先另外一个接收执行
conn.send(cmd_res.encode('utf-8')) #第二个send()发送数据
print("send done") server.close()

在服务器端上,我们计算了发送给客户端的数据大小,先把数据的大小告知客户端,接收多大的数据,然后在发送真正的数据给客户端。在数据发送的时候,要防止粘包,因为send()两次同时发送,造成粘包的情况,因此让程序休眠一秒,time.sleep(1),让客户端先接收数据,过了一秒重新接收数据,这样就不会粘包。

    粘包情况如下;

>>:
命令结果大小: b'22cmd has no output.....'
Traceback (most recent call last):
File "/home/zhuzhu/第七天/s_client.py", line , in <module>
while received_size < int(cmd_res_size.decode()):
ValueError: invalid literal for int() with base : '22cmd has no output.....'

客户端发送数据的时候,服务器返回的时候,由于两个send()同时发送数据造成粘包的情况,会出现错误。两条数据发送的时候连接到一起,造成粘包。两次数据发送链接到一起,为什么造成粘包,是因为程序执行的太快,客户端接收数据很快,速度赶在下一次发送之前。

客户端:

import socket
client = socket.socket()
client.connect(("localhost",)) while True:
cmd = input(">>:").strip()
if len(cmd) == :
continue
client.send(cmd.encode('utf-8'))
'''服务器端发送为空,客户端是卡主的'''
cmd_res_size = client.recv() #接收命令结果的长度(服务器发送的)
print("命令结果大小:",cmd_res_size) received_size =
while received_size < int(cmd_res_size.decode()):
data = client.recv()
received_size += len(data) #每次收到的有可能小于1024,所以必须用len()判断
print(data.decode())
print(received_size)
else:
print("cmd res receive done......",received_size) # cmd_res = client.recv()
#
# print(cmd_res.decode()) client.close()

在客户端中,我们先接收服务器发来的数据的大小,然后开始接收数据,当数据长度小于接收长度时,继续接收,一直等到没有数据接收为止。

在客户端中,接收的数据不一定等于规定的长度。并且要统一格式,我们知道,汉字和英文的长度是不一致的,汉字是由3个字节组成,而因为是由两个字节组成的。

首先启动客户端,然后启动服务器端,如下:

客户端发送数据:
>>:
命令结果大小: b''
cmd has no output..... cmd res receive done......
>>:ls
命令结果大小: b''
build_server.py
class_method.py
class的方法.py
error_handle.py
get_attr.py
get_ip.py
lib
property属性.py
s_client.py
socket_client.py
socket_server.py
s_server.py
static_method.py
动态导入.py
反射.py
客户端创建过程.py
类的方法.py
人类.py
上节内容 cmd res receive done......
>>:dir
命令结果大小: b''
build_server.py get_ip.py socket_server.py 客户端创建过程.py
class_method.py lib s_server.py 类的方法.py
class的方法.py property属性.py static_method.py 人类.py
error_handle.py s_client.py 动态导入.py 上节内容
get_attr.py socket_client.py 反射.py cmd res receive done......

从接收数据可以看出,如果有中文的话,接收数据的长度是不一致的,就是由于中文的字节是3个,因此都要转换为统一格式,现在调整服务器端,让服务器发送数据的长度的时候也是按照字节的形式发送长度,如下:

import socket,os,time
server = socket.socket()
server.bind(("localhost",))
server.listen() while True:
conn,addr = server.accept()
print("new conn:",addr)
while True:
data = conn.recv()
if not data:
print("客户端已断开!")
break
print("执行指令:",data)
cmd_res = os.popen(data.decode()).read()
print("before send",len(cmd_res))
if len(cmd_res) == :
cmd_res = "cmd has no output....."
conn.send(str(len(cmd_res.encode('utf-8'))).encode('utf-8')) #先发送数据的大小给客户端
time.sleep() #连续发送数据会造成粘包现象,因此要有区分,不然容易粘包,这里让程序休眠一秒,先另外一个接收执行
conn.send(cmd_res.encode('utf-8'))
print("send done") server.close()

重新启动服务器,启动客户端发送数据,如下:

客户端输入指令:
>>:
命令结果大小: b''
cmd has no output..... cmd res receive done......
>>:ls
命令结果大小: b''
build_server.py
class_method.py
class的方法.py
error_handle.py
get_attr.py
get_ip.py
lib
property属性.py
s_client.py
socket_client.py
socket_server.py
s_server.py
static_method.py
动态导入.py
反射.py
客户端创建过程.py
类的方法.py
人类.py
上节内容 cmd res receive done......
>>:dir
命令结果大小: b''
build_server.py get_ip.py socket_server.py 客户端创建过程.py
class_method.py lib s_server.py 类的方法.py
class的方法.py property属性.py static_method.py 人类.py
error_handle.py s_client.py 动态导入.py 上节内容
get_attr.py socket_client.py 反射.py cmd res receive done......

从上面可以看出,当调整服务器端发送长度的方式之后,接收数据的长度和服务器告知客户端的长度是一致的。因此,在接收和发送数据的时候要以字节码方式统一计算长度,格式统一很重要,在socket中,计算长度统一格式为:字节码,发送和接收数据都是以字节码的形式操作。

socket网络编程,其实就是收发数据,只能收发字节的形式,要统一字节格式,要进行及时传唤,要告知客户端数据的大小。然后接收的时候,按照大小来接收。接收完成之后在继续进行执行程序。

粘包:两次发送数据粘到一起。

如何解决粘包:

  (1)sleep(),停留一秒,time.sleep(0.5);

服务器端:

import socket,os,time
server = socket.socket()
server.bind(("localhost",))
server.listen() while True:
conn,addr = server.accept()
print("new conn:",addr)
while True:
data = conn.recv()
if not data:
print("客户端已断开!")
break
print("执行指令:",data)
cmd_res = os.popen(data.decode()).read()
print("before send",len(cmd_res))
if len(cmd_res) == :
cmd_res = "cmd has no output....."
conn.send(str(len(cmd_res.encode('utf-8'))).encode('utf-8')) #先发送数据的大小给客户端
time.sleep() #连续发送数据会造成粘包现象,因此要有区分,不然容易粘包,这里让程序休眠一秒,先另外一个接收执行
conn.send(cmd_res.encode('utf-8'))
print("send done") server.close()

服务器两次发送数据的时间有间隔,这样就能避免数据发送粘包的情况。不过使用sleep()太low了。

(2)第一次发送之后,接收数据,接收客户端发来的第一次数据发送接收成功的消息,进行第二次发送,这样就能隔断数据的发送

服务器端:

import socket,os,time
server = socket.socket()
server.bind(("localhost",))
server.listen() while True:
conn,addr = server.accept()
print("new conn:",addr)
while True:
data = conn.recv()
if not data:
print("客户端已断开!")
break
print("执行指令:",data)
cmd_res = os.popen(data.decode()).read()
print("before send",len(cmd_res))
if len(cmd_res) == :
cmd_res = "cmd has no output....."
conn.send(str(len(cmd_res.encode('utf-8'))).encode('utf-8')) #先发送数据的大小给客户端
# time.sleep() #连续发送数据会造成粘包现象,因此要有区分,不然容易粘包,这里让程序休眠一秒,先另外一个接收执行
clicent_ack = conn.recv() #等待接收数据,让下面的发送send()暂时不执行,要收到客户端的数据大小进行响应。wait to confirm
print("ack from client:"
,clicent_ack)
conn.send(cmd_res.encode('utf-8'))
print("send done") server.close()

服务器端,要想防止粘包,则在两次发送数据直接增加一个第一次发送数据成功的确认,即接收成功发送数据的指令,如上面所示,conn.recv()其实也没有什么功能,就是隔断第二次发送的执行时间,让第二次发送数据在第一次执行完成之后再进行执行;

客户端:

import socket
client = socket.socket()
client.connect(("localhost",)) while True:
cmd = input(">>:").strip()
if len(cmd) == :
continue
client.send(cmd.encode('utf-8'))
'''服务器端发送为空,客户端是卡主的'''
cmd_res_size = client.recv() #接收命令结果的长度(服务器发送的)
print("命令结果大小:",cmd_res_size)
client.send("准备好接收了,loser,可以发了".encode('utf-8')) received_size =
while received_size < int(cmd_res_size.decode()):
data = client.recv()
received_size += len(data) #每次收到的有可能小于1024,所以必须用len()判断
print(data.decode())
print(received_size)
else:
print("cmd res receive done......",received_size) # cmd_res = client.recv()
#
# print(cmd_res.decode()) client.close()

客户端上,数据接收完成之后,发送一条指令,即让服务器接着发送第二条指令。第一条指令是发送数据的大小,第二条指令是发送数据;

上面就解决了粘包的情况。

其实,socket在发送和就是数据的时候都是同步的,要想隔断,只能进行成功验证,先隔断不让后面send()执行,只有第一次发送成功之后,并且通过验证,再来进行第二次执行。

day8--socket网络编程进阶的更多相关文章

  1. Python之旅Day8 socket网络编程

    socket网络编程 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可.soc ...

  2. Python面向对象进阶和socket网络编程-day08

    写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...

  3. Python面向对象进阶和socket网络编程

    写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self ...

  4. python------面向对象进阶 Socket网络编程

    一.Socket网络编程 1.七层模型,亦称OSI(Open System Interconnection)参考模型,是参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标准体系 ...

  5. 基于Socket网络编程

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...

  6. Socket网络编程(TCP/IP/端口/类)和实例

    Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次 ...

  7. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  8. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  9. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  10. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

随机推荐

  1. elementUI 表格设置表头样式

    eader-row-class-name 表头行的 className 的回调方法,也可以使用字符串为所有表头行设置一个固定的 className. Function({row, rowIndex}) ...

  2. Swift下使用Xib设计界面

    虽然Swift可以纯代码设计界面,不过不利用现有的可视化工具有时候有点效率低.下面是使用xib设计方法,部分代码来自网上. (1)新建View 2.新建View class 3.DemoView.sw ...

  3. Linux 创建 时间命名 文件

    创建以 时间 命名文件:: touch /logs/`date +%Y-%m-%d_%d_%H:%M`.log touch "$(date +%Y-%m-%d_%H:%M:%S.TXT)

  4. 【洛谷P1052【NOIP2005提高T2】】过河

    题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数 ...

  5. luogu P1268 树的重量

    一开始把这题想复杂了,,, 这里记\(di[i][j]\)表示\(i\)到\(j\)的距离 首先如果\(n=2\),答案显然为\(di[1][2]\) 如果\(n=3\) 懒得画图了盗图过来 那么3号 ...

  6. POJ3304 Segments 【线段直线相交】

    题意: 给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!. 思路: 计算几何.这道题要思考到两点: 1:把问题转化为是否存在一条直线 ...

  7. root权限使用vim不能修改权限

    1.背景: 有时候我们会发现使用root权限不能修改某个文件,大部分原因是曾经使用chattr将文件锁定了 2.chattr命令介绍: 用来改变文件属性,能防止root用户误删文件等作用 3.使用方法 ...

  8. Hyper-V虚拟机上安装一个图形界面的Linux系统

    这件事情呢,一直想干但又觉得太陌生和麻烦,无奈现在到了非装不可的时候,只好硬着头皮去装.在此之前,我不懂什么叫做虚拟机,linux也接触甚少.经过3天的折腾,终于装好了带有图形界面的linux(字符版 ...

  9. Python-百度经纬度转高德经纬度

    import math def bdToGaoDe(lon,lat): """ 百度坐标转高德坐标 :param lon: :param lat: :return: &q ...

  10. python 生成器与协程

    生成器在迭代中以某种方式生成下一个值并且返回和next()调用一样的东西. 挂起返回出中间值并多次继续的协同程序被称作生成器. 语法上讲,生成器是一个带yield语句的函数.一个函数或者子程序只返回一 ...