일 29 TCP 패킷 전송 끈적 문제

스틱 패키지 문제

참고 : TCP 패킷이 끈적 현상을 가지고, UDP는 한 번 추출에 의한 데이터의 얼마나 많은 바이트를 모르는,받는 사람이 뉴스 사이의 경계를 모르는 주로하기 때문에 스틱 팩 문제라는 패키지를 부착하지 마십시오.

  • TCP (전송 제어 프로토콜, 전송 제어 프로토콜) 연결형 스트림 지향 신뢰성 서비스이다. 수신기와 송신기 (클라이언트와 서버)의 최적화 방법 (월리 알고리즘)을 사용하여 전송하는 기타 더 효율적으로 수신 측 주소로 복수의 패킷을, 최종 전송하기 위해, 따라서 소켓 열한 쌍을 가져야 시간은 작은 간격의 데이터를 적은 양의 데이터는 데이터의 큰 블록을, 그 패킷으로 결합. 이러한 방법으로, 수신 측, 차이를 구별하고, 과학 풀기 메커니즘을 제공해야합니다 어렵다. 즉, 무 방향성 통신 메시지 스트림은 경계를 보호됩니다.
  • UDP (사용자 데이터 그램 프로토콜, 사용자 데이터 그램 프로토콜)는 비 연결, 메시지 지향 제공 효율적인 서비스입니다. UDP 각 UDP 각각의 UDP 패킷의 도착을 기록하는 체인 구조를 사용하여 다수의 모드에서 skbuff (소켓 버퍼)의 수신단 때문에 최적화 알고리즘의 병용 ,, 블록을 지원하지 않는다 수신 측에 대해,이 과정을 구별하기 쉬운 것을, 그래서 우리는, 패키지 (정보 소스 주소와 포트) 메시지 헤더가 있습니다. 그 메시지는 메시지 지향 통신 보호 경계입니다.
  • 메시지는 모든 사용자가 입력 한 경우에도, UDP 데이터 그램을 기반으로 움직이지 않게 프로그램을 방지하기 위해 클라이언트와 서버에서 처리 메커니즘 빈 메시지를 추가 요구하는 비어있을 수 없습니다 송수신 있도록 TCP는 스트림 기반 빈 내용 (직접 캐리지 리턴), 그것은 빈 메시지 아니었다, UDP 프로토콜은 약간의 실험은 메시지 헤더를 패키지 도움이 될 것입니다

네 경우 TCP의 송신 데이터

클라이언트 인해 바이트는 다음과 같은 네 가지 경우가있을 수 있도록, 불확실 읽기의 숫자로 서버, 서버에 두 개의 패킷 D1과 D2를 보내 가정하자.

  1. 회 서버는 두 개의 데이터 패킷을 각각 D1 및 D2를 판독하고, 패키지를 언 패킹 붙이지하는 단계;
  2. 서버는 TCP 스틱 패키지라고도 둘, D1 및 D2는 서로 결합되는 패킷을 수신한다;
  3. 두번 서버는 두 개의 데이터 패킷을 처음 읽을 패키지의 완전한 판독 패킷 D1 및 D2 부분 TCP 풀고이라 나머지 구성품 D2에 제 판독하는 단계;
  4. 회 서버는 두 개의 데이터 패킷 패키지 D1_1 D1 나머지 패키지 콘텐츠 D1_2 D1 전체 포장 백의 D2 내지 제 판독의 제 1 판독의 일부를 판독한다.

예외 : 현재 서버가 TCP 슬라이딩 윈도우가 매우 작 수신하고, 상기 데이터 패킷 D1과 D2가 비교적 큰 경우에는, 패킷 수신 D1 및 D2를 완료하기 위해 제 발생할 해당 서비스 포인트를 여러 번 끝날 가능성이 높다 중에 발생한 반복적으로 풀기.

두 경우 모두 스틱 패키지에서

1. 송신 측의 버퍼 (데이터 송신 시간 간격 데이터가 작고, 스틱 포장을 제조하기 위해 함께 조인하는 짧은) 스틱 포장 결과 송출 찰 때까지 기다릴 필요

수신자는 적시에 다수의 수신 된 패킷의 결과, 패킷 버퍼가 수신되지 않은 경우 (클라이언트에 의해 전송 된 데이터의 일부는, 서버는 서버의 다음번 작은 부분만을 수신하거나 버퍼에서 마지막 남은 데이터를 폐쇄 시간을 생성 스틱 패키지)

TCP는 신뢰할 수있는 전송이 왜, UDP는 신뢰할 수없는 전송입니다

  • TCP 데이터 전송을 기반으로 또 다른 문서는, nickl 교사를 참조 https://www.cnblogs.com/nickchen121/p/11027575.html TCP 데이터 전송에서, 보낸 사람이 먼저 자신의 캐시에 데이터를 전송, 그 피어로 전송되는 데이터 캐시 제어 프로토콜은 피어가 ACK = 1, 송신 측의 데이터 버퍼가 깨끗한 반환 피어 복귀 한 후 데이터를 다시, TCP는 신뢰할 수 = 0 인 ACK
  • UDP 전송 데이터는 피어는 확인 메시지 따라서 신뢰할 수없는 반환

(바이트 스트림) 및 RECV (1024)와 모두 발송을 보내

  • RECV 캐시로부터 1024 바이트의 데이터에 지정 수단 (1024)
  • 바이트 스트림은 그 발송을 함께 사이클 통화 전송되며, 마지막에 콘텐츠를 전송하기 위해 다음 캐시는 프로토콜에 의해 제어된다 헥실 쪽 캐시로 전송되는 바이트 스트림의 크기가 나머지 버퍼 공간보다 클 경우, 데이터가 손실 보내는 것이다 데이터가 손실되지 않습니다

문제를 해결하기 위해 패키지를 스틱

문제의 뿌리는 수신자가 송신자의 바이트 스트림의 길이가 전송 될 알고하지 않습니다, 그래서 솔루션 스틱 패키지는 데이터, 바이트 스트림 수신기 수 있도록 전송됩니다 자신의 전체 크기를 보내기 전에 보낸 사람을 얻는 방법, 주위에 끝, 죽음의 후 인출 수신주기는 모든 데이터를 받았습니다.

#服务端
import socket, subprocess

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(('127.0.0.1', 8000))
server.listen(5)

while True:
    conn, addr = server.accept()

    print('start...')
    while True:
        cmd = conn.recv(1024)
        print('cmd:', cmd)

        obj = subprocess.Popen(cmd.decode('utf8'),
                               shell=True,
                               stderr=subprocess.PIPE,
                               stdout=subprocess.PIPE)

        stdout = obj.stdout.read()

        if stdout:
            ret = stdout
        else:
            stderr = obj.stderr.read()
            ret = stderr

        ret_len = len(ret)

        conn.send(str(ret_len).encode('utf8'))

        data = conn.recv(1024).decode('utf8')

        if data == 'recv_ready':
            conn.sendall(ret)

    conn.close()

server.close()

#客户端
import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect(('127.0.0.1', 8000))

while True:
    msg = input('please enter your cmd you want>>>').strip()

    if len(msg) == 0: continue

    client.send(msg.encode('utf8'))
    length = int(client.recv(1024))

    client.send('recv_ready'.encode('utf8'))

    send_size = 0
    recv_size = 0

    data = b''

    while recv_size < length:
        data = client.recv(1024)
        recv_size += len(data)

    print(data.decode('utf8'))
    
    #此版比较low,程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗

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

具体版本详情请看 nick老师的博客 https://www.cnblogs.com/nickchen121/p/11032005.html

UDP 소켓 소켓 프로그래밍을 기반으로

  • UPD 프로토콜은 일반적으로 대용량의 데이터 전송을 위해 사용되지 않는다.

  • 데이터가 그의 방법에 전송되면, 데이터가 손실, 데이터가 손실되고, 그러한 결함 TCP 프로토콜이 없을 것 : 더 스틱 패키지 UDP 소켓 문제가 아니라 TCP 소켓을 대체, UPD 프로토콜은 결함이 있기 때문에이 없지만 그것은 일반적 무관 UPD 소켓 사용자 데이터 전송은, 예를 들면 채팅 QQ

    #服务器
    #_*_coding:utf-8_*_
    __author__ = 'nick'
    import socket
    ip_port = ('127.0.0.1', 8081)
    UDP_server_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  #买手机
    UDP_server_sock.bind(ip_port)
    
    while True:
        qq_msg, addr = UDP_server_sock.recvfrom(1024)
        print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %
              (addr[0], addr[1], qq_msg.decode('utf-8')))
        back_msg = input('回复消息: ').strip()
    
        UDP_server_sock.sendto(back_msg.encode('utf-8'), addr)
    
    # 客户端1
    #_*_coding:utf-8_*_
    __author__ = 'nick'
    import socket
    BUFSIZE = 1024
    UDP_client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    qq_name_dic = {
        '狗哥alex': ('127.0.0.1', 8081),
        '瞎驴': ('127.0.0.1', 8081),
        '一棵树': ('127.0.0.1', 8081),
        '武大郎': ('127.0.0.1', 8081),
    }
    
    while True:
        qq_name = input('请选择聊天对象: ').strip()
        while True:
            msg = input('请输入消息,回车发送: ').strip()
            if msg == 'quit': break
            if not msg or not qq_name or qq_name not in qq_name_dic: continue
            UDP_client_socket.sendto(msg.encode('utf-8'), qq_name_dic[qq_name])
    
            back_msg, addr = UDP_client_socket.recvfrom(BUFSIZE)
            print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %
                  (addr[0], addr[1], back_msg.decode('utf-8')))
    
    UDP_client_socket.close()
    
    #客户端2
    #_*_coding:utf-8_*_
    __author__ = 'nick'
    import socket
    BUFSIZE = 1024
    UDP_client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    qq_name_dic = {
        '狗哥alex': ('127.0.0.1', 8081),
        '瞎驴': ('127.0.0.1', 8081),
        '一棵树': ('127.0.0.1', 8081),
        '武大郎': ('127.0.0.1', 8081),
    }
    
    while True:
        qq_name = input('请选择聊天对象: ').strip()
        while True:
            msg = input('请输入消息,回车发送: ').strip()
            if msg == 'quit': break
            if not msg or not qq_name or qq_name not in qq_name_dic: continue
            UDP_client_socket.sendto(msg.encode('utf-8'), qq_name_dic[qq_name])
    
            back_msg, addr = UDP_client_socket.recvfrom(BUFSIZE)
            print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %
                  (addr[0], addr[1], back_msg.decode('utf-8')))
    
    UDP_client_socket.close()

동시성을 달성 socketserver 소켓 소켓 프로그래밍을 기반으로

추천

출처www.cnblogs.com/bladecheng/p/11099187.html