まず、スティックパッケージ
1本のスティックパック現象
ベースのソケットTCPプロトコル、クライアントの受け入れ終了時刻は、(間隔が比較的長く、以降のデータが残っているデータの前に一緒に固執する場合)次を受け続けたときに、送信データ、少量のデータの連続送信(非常に短い時間間隔)、これらのデータは、バックログを一緒に送信されます。
2.スティックパック現象
- 受信者は、(クライアントによって送信されたデータの一部を受信するサーバは、サーバの小部分のみ次回受信またはバッファから最後の残りのデータを閉じるために時間がかかり、複数のパケットで、その結果、タイムリーなパケットバッファを受信しません生成スティック包装)
- 送信側のみスティックパッケージをもたらす、バッファが一杯などで送出する必要がある(データが小さい場合、データの送信時間間隔が短い、スティックパッケージを生成するために一緒に結合)
3.結果のスティックパッケージ原因
- TCPプロトコルは、データストリームに基づいて、関係なく、基礎となるセグメントスライスは、TCPプロトコルによるデータメッセージの送信が、カーネルバッファに提示されるメッセージ全体を構成するデータセグメントの種類を限定するものではないものを送信するまで、完了していませんバッファ当事者は、TCPセグメントを送信する前に十分なデータを持っています
- データ伝送がソケットによって受信されたデータよりも大きい場合、余分なデータがバッファに配置され、受信側前にバッファに置かれたデータは、次の代わりに、送信側から送信された最新の、それが受信し続ける、一度データRECVを受信しますデータ
4.バッファ
各ソケットが作成された後、二つのバッファは、入力バッファと出力バッファを割り当てられています。
ネットワーク内の書き込み()/(送信)すぐにデータを送信するが、バッファにデータを書き込み、その後、ターゲットマシンにTCPプロトコルによってバッファからデータを送信しません。データがバッファに書き込まれると、機能に関係なく、彼らがターゲットマシン、それらがネットワークに送信されているどんなにに達していないかどうかの、これらは、TCPプロトコルが何を担当している、成功を返すことができます。
TCPプロトコルの独立した書き込み()/送信()関数は、データがネットワークだけに書き込まれたバッファに送信することができる、それがバッファ内のバックログに続けることができ、データは一度だけネットワークに送信され何度も、書かれていますネットワーク条件が優勢に応じて、現在のスレッドがないように制御するプログラマによってアイドルおよび他の多くの要因です。
READ()/ RECV()関数の代わりにネットワークから直接読み取るので、入力バッファからデータを読み取り、真です。
次のようにこれらのI / Oバッファ特性を要約することができます。
1.I各個々のTCPソケット内に存在する/ Oバッファ、
ソケットを作成するときに2.I / Oバッファが自動的に生成され、
バッファに残った場合でも3.ソケットを閉じて出力を転送し続けますデータ;
ソケットは、入力データバッファに失われます。4.閉じます。
第二に、スティックのパッケージ・ソリューション
1.低バージョン
サーバー
import socket
import subprocess
import struct
server_side = socket.socket()
server_side.bind(("127.0.0.1", 8848))
server_side.listen(5)
while 1:
conn, addr = server_side.accept()
while 1:
try:
cmd = conn.recv(1024)
if cmd.decode("utf-8") == 'q':
break
obj = subprocess.Popen(cmd.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
result = obj.stdout.read() + obj.stderr.read()
# 制作报头
total_size = len(result)
# 将不固定长度的int数据类型的报头,转化成固定长度的4bytes
total_size_bytes = struct.pack("i", total_size)
# 发送报头
conn.send(total_size_bytes)
# 发送数据
conn.send(result)
except ConnectionResetError:
break
conn.close()
server_side.close()
クライアント
import socket
import struct
client_side = socket.socket()
client_side.connect(("127.0.0.1", 8848))
while 1:
to_send = input("请输入你要执行的命令:")
if to_send.upper() == "Q":
client_side.send("q".encode("utf-8"))
break
client_side.send(to_send.encode("utf-8"))
# 接收报头
head_bytes = client_side.recv(4)
# 反解报头
total_size = struct.unpack("i", head_bytes)[0]
# 循环接收数据
data = b""
while len(data) < total_size:
data += client_side.recv(1024)
print(data.decode("gbk"))
client_side.close()
2.究極
サーバー
import socket
import subprocess
import json
import struct
phone = socket.socket()
phone.bind(("127.0.0.1", 8848))
phone.listen(5)
conn, addr = phone.accept()
while 1:
try:
cmd = conn.recv(1024)
obj = subprocess.Popen(cmd.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
result = obj.stdout.read() + obj.stderr.read()
result = result.decode("gbk").encode("utf-8")
# 1.制作报头
head_dict = {"md5": "df",
"file_name": "新建文件夹",
"file_size": len(result)}
# 2. 将报头字典转化成json字符串
head_dict_json = json.dumps(head_dict)
# 3. 将json字符串转化成bytes
head_dict_json_bytes = head_dict_json.encode("utf-8")
# 4. 获取报头的长度
head_len = len(head_dict_json_bytes)
# 5. 将报头长度转化成固定的4个bytes
head_len_bytes = struct.pack("i", head_len)
# 6. 发送固定的4个字节
conn.send(head_len_bytes)
# 7. 发送报头
conn.send(head_dict_json_bytes)
# 8. 发送原数据
conn.send(result)
except ConnectionResetError:
break
conn.close()
phone.close()
クライアント
import socket
import struct
import json
phone = socket.socket()
phone.connect(("127.0.0.1", 8848))
while 1:
cmd = input("请输入指令")
phone.send(cmd.encode("utf-8"))
# 1. 接收报头长度
head_len_bytes = phone.recv(4)
# 2. 将报头数字转化成int类型
head_len = struct.unpack("i", head_len_bytes)[0]
# 3. 接收bytes类型的报头字典
head_dict_json_bytes = phone.recv(head_len)
# 4. 将bytes类型的字典转化成json字符串
head_dict_json = head_dict_json_bytes.decode("utf-8")
# 5. 将json字符串转化成字典
head_dict = json.loads(head_dict_json)
# 6. 循环接收原数据
total_data = b''
while len(total_data) < head_dict["file_size"]:
total_data += phone.recv(1024)
print(total_data.decode("utf-8"))
phone.close