>  기사  >  웹 프론트엔드  >  TCP 고정 패킷 문제를 해결하는 두 가지 방법

TCP 고정 패킷 문제를 해결하는 두 가지 방법

little bottle
little bottle앞으로
2019-04-30 11:21:003955검색

이 글에서는 TCP 끈적한 문제를 해결하는 방법에 대해 주로 설명합니다. 첫 번째는 콘텐츠 크기와 콘텐츠를 각각 두 개의 통신으로 전송하는 것입니다. 두 번째는 콘텐츠 크기와 콘텐츠를 한 번의 통신으로 직접 전송하는 것입니다. 더 알고 싶은 친구들은 이 글을 자세히 읽어보시면 도움이 되실 겁니다.

1부: TCP 소켓 통신의 기본 원리 소개

원리 분석 다이어그램:

1 소켓 통신 프로세스는 그림과 같습니다. 먼저 클라이언트는 다음을 통해 콘텐츠를 보냅니다. send() 메소드를 클라이언트 컴퓨터의 커널 영역으로 보낸 다음 운영 체제가 기본 경로를 통해 서버의 커널 영역으로 콘텐츠를 보낸 다음 서버 프로그램이 커널에서 데이터를 검색합니다. recv() 메소드를 통해 서버의 영역.
2 따라서 send 메소드는 서버에 직접 컨텐츠를 전송하지 않고, recv 메소드는 클라이언트에서 서버 프로그램 메모리로 전송한 컨텐츠를 직접 수신하지 않고 해당 커널 영역을 작동시키는 것으로 이해할 수 있습니다. 자신의 기계.

2부: 고정 패킷의 이유(tcp에만 해당)

고정 패킷이 발생하는 두 가지 상황은 다음과 같습니다.

1 1: 데이터가 연속적으로 전송되면 tcp 프로토콜의 nagle 알고리즘으로 인해 더 작은 패킷이 발생합니다. 컨텐츠를 큰 컨텐츠로 쪼개어 한번에 서버로 보내게 되어 끈적한 패킷이 발생함 2 3 2: 큰 컨텐츠를 보낼 때 서버 측의 recv(buffer_size) 메소드의 buffer_size가 작기 때문에, 전체 콘텐츠를 한 번에 완전히 수신할 수 없으므로 다음 요청이 도착할 때 수신된 콘텐츠는 여전히 지난번에 완전히 수신되지 않은 콘텐츠이므로 끈적이는 현상이 발생합니다.

즉, 수신자는 수신이 완료되기 전에 얼마나 많은 데이터를 수신해야 하는지 알 수 없으므로 패킷이 끈적해집니다.

관련 튜토리얼: TCP/IP 비디오 튜토리얼

3부: 위의 두 가지 끈적임 현상을 해결하는 방법은 무엇입니까?

아이디어 1: 첫 번째 고정 패킷 생성 방법의 경우 두 개의 send()에서 recv()를 직접 사용하여 연속 전송을 방지할 수 있습니다. 코드를 보여줄 필요가 없습니다.

아이디어 2: 고정 패킷의 원인은 수신자의 무제한 수신이므로 발신자는 데이터를 전송하기 전에 전송된 콘텐츠의 크기를 수신자에게 알릴 수 있습니다. 코드 예시는 다음과 같습니다.

 방법 1: 두 개의 통신으로 콘텐츠 크기와 콘텐츠를 전송합니다.

  서버 측 코드:

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import subprocess

server = socket(AF_INET, SOCK_STREAM)
server.bind(("127.0.0.1", 8000))
server.listen(5)

while True:
    conn, addr = server.accept()
    print("创建了一个新的连接!")
    while True:
        try:
            data = conn.recv(1024)
            if not data: break
            res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            err = res.stderr.read()
            if err:
                cmd_msg = err
            else:
                cmd_msg = res.stdout.read()
            if not cmd_msg: cmd_msg = "action success!".encode("gbk")
            length = len(cmd_msg)
            conn.send(str(length).encode("utf-8"))
            conn.recv(1024)
            conn.send(cmd_msg)
        except Exception as e:
            print(e)
            break

클라이언트 측 코드:

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *

client = socket(AF_INET, SOCK_STREAM)
client.connect(("127.0.0.1", 8000))
while True:
    inp = input(">>:")
    if not inp: continue
    if inp == "quit": break
    client.send(inp.encode("utf-8"))
    length = int(client.recv(1024).decode("utf-8"))
    client.send("ready!".encode("utf-8"))
    lengthed = 0
    cmd_msg = b""
    while lengthed < length:
        cmd_msg += client.recv(1024)
        lengthed = len(cmd_msg)
    print(cmd_msg.decode("gbk"))

 방법 2: 한 번의 커뮤니케이션으로 콘텐츠 크기와 콘텐츠를 직접 전송

  서버 측:

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import subprocess
import struct

server = socket(AF_INET, SOCK_STREAM)
server.bind(("127.0.0.1", 8000))
server.listen(5)

while True:
    conn, addr = server.accept()
    print("创建了一个新的连接!")
    while True:
        try:
            data = conn.recv(1024)
            if not data: break
            res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            err = res.stderr.read()
            if err:
                cmd_msg = err
            else:
                cmd_msg = res.stdout.read()
            if not cmd_msg: cmd_msg = "action success!".encode("gbk")
            length = len(cmd_msg)
            conn.send(struct.pack("i", length))
            conn.send(cmd_msg)
        except Exception as e:
            print(e)
            break
 

클라이언트 측 :

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import struct

client = socket(AF_INET, SOCK_STREAM)
client.connect(("127.0.0.1", 8000))
while True:
    inp = input(">>:")
    if not inp: continue
    if inp == "quit": break
    client.send(inp.encode("utf-8"))
    length = struct.unpack("i",client.recv(4))[0]
    lengthed = 0
    cmd_msg = b""
    while lengthed < length:
        cmd_msg += client.recv(1024)
        lengthed = len(cmd_msg)
    print(cmd_msg.decode("gbk"))

둘 다 위의 방법으로 끈끈한 패키지 문제를 해결할 수 있습니다.

위 내용은 TCP 고정 패킷 문제를 해결하는 두 가지 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제