zoukankan      html  css  js  c++  java
  • TCP协议 三次握手,四次挥手,socket 粘包

    TCP协议 三次握手,四次挥手,socket 粘包

    TCP协议

    1.协议是建立双向的管道

    传输层的:

    ​ -TCP协议

    ​ -UDP协议

    1.1三次握手,建连结

    ​ 1.客户端向服务端发送建立连结的请求;

    ​ 2.服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求;

    ​ 3.客户端接收到服务发来的请求,返回连接成功给服务层,完成双向的连接。

    1.2反馈机制

    ​ 1.客户端往服务端发送请求,服务端必须返回响应;

    ​ 2.告诉客户端收到请求了,并且将服务端色数据一并返回给客户端。

    ​ C---->S:一次的请求,必须有一次的响应

    ​ 缺点:

    ​ -洪水攻击:

    ​ 指的通过伪造大量的请求,往对方的服务器发送请求;

    ​ 导致对方服务器想用跟不上,以至于瘫痪;

    ​ linux系统有个参数可以限制

    ​ -半连接池listen:限制用户的在同一个时间段内的访问数量。

    1.3四次挥手,断开连接

    ​ 1.客户端向服务端发送断开连接的请求;

    ​ 2.服务端返回收到请求的信息给客户端;

    ​ 3.服务端确认所有的数据发送完成以后,再发送同意断开来连接的请求给用户端;

    ​ 4.客户端返回收到断开的连接的请求,给服务端。

    socket

    -定义:

    ​ socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)

    -作用:

    ​ -socket可以实现 互联网协议的应用层以下的层的工作;

    ​ -提高开发效率

    ​ -怎么使用:

    ​ import socket

    ​ 写socket 套接字

    ​ Client

    ​ Server

    ​ 注意:

    ​ 端口:port 标识一台电脑计算机上的某一个软件

    ​ -0-1024禁止使用,操作系通在用

    ​ -软件的固定端口不要用:

    ​ django:8000

    ​ mysql:3306

    ​ flask:5000

    ​ redis:6379

    ​ tomcat:8080

    ​ mongodb:27017

    下面这个是个socket的最总版本

    先执行server 再去执行client

    '''
    注意:客户端先发一次发送,服务端的先一次接受,再发送信息  server
    '''
    import socket
    #买手机   socket 也是一个类
    server = socket.socket()
    #绑定手机卡
    server.bind(
        ('127.0.0.1',9528)
    )#####127.0.0.1 是本地的回环地址
    ####局域网内测试的是192.168.12.202 ,9527
    #半连接池
    server.listen(5)##按照今天举得例子,最多5个人坐椅子,一个人在享受服务,实际是6个人
    print('server is running....')
    #循环实现可接受多个用户访问
    #等待电话接入————>接入客户端
    #conn 指的是服务端往客户端的管道
    while True:
        conn,addr = server.accept()
        print(addr)
    
    #循环实现通信
        while True:
            try: #监听代码块是否有异常
                #接收对方讲话的内容
                #data客户端端发来的信息
                data = conn.recv(1024) #一次可以接收1024bytes
                if len(data) == 0:
                    break
                if data.decode('utf-8') =='q':
                    break
                print(data.decode('utf-8'))   ###这个是传过来的时候是编码用utf-8编码的,解码也要用这个解码
                send_data = input('服务端>>>:')
                #服务端往客户端发送信息
                conn.send(send_data.encode('utf-8'))
                #捕获异常的信息,并打印,报错信息
            except Exception as e:
                print(e)
                break
    
        #挂电话
        conn.close()
     
    
    下面这个是client
        # '''
    # 启动服务端后再启动客户端
    # '''
    import socket
    #买手机
    client = socket.socket()
    #拨号
    client.connect(
        ('127.0.0.1',9528)
    )#客户端的ip和port必须和服务器保持一致
    print('client is running....')
    
    #必须发送bytes类型的数据
    #必须讲给对方听
    while True:
        send_data = input('客户端>>>>:')
        client.send(send_data.encode('utf -8'))
        data = client.recv(1024)
    
        if data .decode('utf-8') == 'q':
            break
    
        if len(data) == 0:
            break
        print(data.decode('utf-8'))
    client.close()
    
    
    
    

    粘包问题

    出现的问题:

    1.无法确认对方发来的数据的大小

    2.在发送数据间隔短并且数量小的情况下,会将所有数据一次性发送

    解决办法

    -粘包(struct模块)

    ​ -无论那一端发送数据

    ​ -客户端:

    ​ 1.先制作报头,在发生

    ​ 2.发送真实的数据

    ​ -服务端

    ​ 1.接收报头,并解包获取真实的长度 recv(报头)

    ​ 2.根据真实的长度,接收真实的数据 recv(真实的数据长度)

    粘包的举例 电影

    先执行server 再去执行client

    下面这个server
    
    import socket
    import json
    import struct
    server = socket.socket()
    server.bind(
        ('127.0.0.1',9002)
    )
    server.listen(5)
    while True:
        conn,addr = server.accept()
        print(addr)
        while True:
            try:
                #获取客户传过来的报头
                header = conn.recv(4)
                #解包获取真实的数据长度
                json_len = struct.unpack('i',header)[0]
                #接收json的真实长度
                json_bytes_data = conn.recv(json_len)
                #将bytes类型转化成json数据
                json_data = json_bytes_data.decode('utf-8')
                #反序列化
                back_dic = json.loads(json_data)
                print(back_dic)
                print(back_dic.get('movie_len'))
    
                # movie_data = conn.recv(back_dic.get('movie_len'))
                # print(movie_data)
            except Exception as e:
                print(e)
                break
        conn.close()
        >>>>>>>>>>>>>>>>>>>>>
        ('127.0.0.1', 53140)
    {'movie_name': '太阳', 'movie_len': 100000}
    100000
    {'movie_name': '中国', 'movie_len': 100000}
    100000
        
        下面这个是client
        
        import socket
    import struct
    import json
    
    client = socket.socket()
    client.connect(
        ('127.0.0.1',9002)
    )
    while True:
        movie_name = input('请输入电影的名字:')
        #伪装的一个电影的真实长度
        movie_len = 100000
        send_dic = {
            'movie_name': movie_name,
            'movie_len': movie_len
        }
        #序列化
        json1 = json.dumps(send_dic)
        print(json1)
        print(json1.encode('utf-8'))
        print(len(json1.encode('utf-8')))
        json1_bytes = json1.encode('utf-8')
        #做一个报头
        header = struct.pack('i',len(json1_bytes))
        #先发送包头
        client.send(header)
        #再发送真实的数据
        client.send(json1_bytes)
    >>>>>>>>>>>>>>>>>>>>>>
    请输入电影的名字:太阳
    {"movie_name": "u592au9633", "movie_len": 100000}
    b'{"movie_name": "\u592a\u9633", "movie_len": 100000}'
    51
    请输入电影的名字:中国
    {"movie_name": "u4e2du56fd", "movie_len": 100000}
    b'{"movie_name": "\u4e2d\u56fd", "movie_len": 100000}'
    51
    
    

    与终端的相关联的举例

    下面这个是server

    import socket
    import subprocess
    
    server = socket.socket()
    server.bind(
        ('127.0.0.1',9000)
    )
    
    server.listen(5)
    while True:
        conn,addr = server.accept()
    
        while True:
            try:
                cmd = conn.recv(10)
    
                if len(cmd) == 0:
                    continue
                cmd = cmd.decode('utf-8')
                if cmd == 'q':
                    break
                #调用subprocess连接终端,对终端进行操作,并获取操作后正确或者错误的结果
                obj = subprocess.Popen(
                    cmd,shell = True,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE,
                )
                #结果交给result变量名
                result = obj.stdout.read()+obj.stderr.read()####stuout是正确的结果,stuerr是错误的结果,这个result 是正确的和错误的相加,无论对错都能打印一个结果
                print(len(result))
                #gbk
                print(result.decode('gbk'))  ###window系统 终端默认的编码是gbk
                conn.send(result)
    
            except Exception as e:
                print(e)
                break
                
                
      下面这个是client
    import socket
    client = socket.socket()
    client.connect(
        ('127.0.0.1',9000)
    )
    while  True:
        cmd = input('客户输入的内容:')
        client.send(cmd.encode('utf-8'))
        data = client.recv(19190)
        print(len(data))
        print(data.decode('gbk'))
    
    

  • 相关阅读:
    Locust:简介和基本用法
    linux more less 用法
    Pytest测试用例之setup与teardown方法
    app测试之monkey
    理解yield以及和return的区别
    Python 数据驱动工具:DDT
    requests 使用 proxies 代理时ValueError: check_hostname requires server_hostname
    from urllib.parse import urlparse 使用
    linux 三剑客 使用总结 grep sed awk
    企查查和天眼查哪个好用
  • 原文地址:https://www.cnblogs.com/bs2019/p/11997327.html
Copyright © 2011-2022 走看看