• 网络编程


    1 .简述socket 通信原理

     

     

    如上图,socket通信建立在应用层与TCP/IP协议组通信(运输层)的中间软件抽象层,它是一组接口,在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议组隐藏在Socket接口后面,对于用户来说,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议。

    所以,经常对用户来讲,socket就是ip+prot 即IP地址(识别互联网中主机的位置)+port是程序开启的端口号

     socket通信如下:

    客户端

    # _*_ coding: utf-8 _*_
    import socket
     
    ip_port = ('127.0.0.1',9696)
    link = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    link.connect(ip_port)
    print("开始发送数据")
    cmd = input("client请输入要发送的数据>>>>").strip()
    link.send(cmd.encode('utf-8'))
    recv_data = link.recv(1024)
    print("这是受到的消息:",recv_data)
    link.close()

    服务端

    # _*_ coding: utf-8 _*_
    import socket
     
    ip_port = ('127.0.0.1',9696)
    link = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    link.bind(ip_port)
    link.listen(5)
     
    conn,addr = link.accept()
    #这里,因为我们知道自己写的少,所以1024够用
    recv_data = conn.recv(1024)
    print("这是受到的消息:",recv_data)
    cmd = input("server请输入要发送的数据>>>>").strip()
    conn.send(cmd.encode('utf-8'))
    conn.close()
    link.close()
    2,粘包的原因和解决方法?
    

      

    2. 粘包的原因和解决方法?

      TCP是面向流的协议,发送文件内容是按照一段一段字节流发送的,在接收方看来不知道文件的字节流从和开始,从何结束。

      UDP是面向消息的协议,每个UDP段都是一个消息,

    直接原因:

        所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
     
    根本原因:
        发送方引起的粘包是由TCP协议本身造成的,TCP为了提高传送效率,发送方往往要收集到足够多的数据
    才发送一个TCP段,若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成到一个TCP
    段后一次发送过去,这样接收方就受到了粘包数据。
     

    如果需要一直收发消息,加一个while True即可。但是这里有个1024的问题,即粘包,

      粘包的根源在于:接收端不知道发送端将要发的字节流的长度,所以解决粘包问题的方法就是围绕如何让发送端在发送数据前,把自己将要发送的字节流大小让接收段知道,然后接收端来一个死循环,接收完所有的数据即可。

      粘包解决的具体做法:为字节流加上自定义固定长度报头,报头中包含字节流长度,然后依次send到对端,对端在接受时,先从缓存中取出定长的报头,然后再取真是数据。

    客户端

    # _*_ coding: utf-8 _*_
    import socket
    import struct
    import json
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',8080)) #连接服务器
    while True:
        # 发收消息
        cmd = input('请你输入命令>>:').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8')) #发送
        #先收报头的长度
        header_len = struct.unpack('i',phone.recv(4))[0]  #吧bytes类型的反解
        #在收报头
        header_bytes = phone.recv(header_len) #收过来的也是bytes类型
        header_json = header_bytes.decode('utf-8')   #拿到json格式的字典
        header_dic = json.loads(header_json)  #反序列化拿到字典了
        total_size = header_dic['total_size']  #就拿到数据的总长度了
        #最后收数据
        recv_size = 0
        total_data=b''
        while recv_size<total_size: #循环的收
            recv_data = phone.recv(1024) #1024只是一个最大的限制
            recv_size+=len(recv_data) #有可能接收的不是1024个字节,或许比1024多呢,
            # 那么接收的时候就接收不全,所以还要加上接收的那个长度
            total_data+=recv_data #最终的结果
        print('返回的消息:%s'%total_data.decode('gbk'))
    phone.close()
      

    服务端

    # _*_ coding: utf-8 _*_
    import socket
    import subprocess
    import struct
    import json
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8080)) #绑定手机卡
    phone.listen(5) #阻塞的最大数
    print('start runing.....')
    while True: #链接循环
        coon,addr = phone.accept()# 等待接电话
        print(coon,addr)
        while True: #通信循环
            # 收发消息
            cmd = coon.recv(1024) #接收的最大数
            print('接收的是:%s'%cmd.decode('utf-8'))
            #处理过程
            res = subprocess.Popen(cmd.decode('utf-8'),shell = True,
                                              stdout=subprocess.PIPE, #标准输出
                                              stderr=subprocess.PIPE #标准错误
                                    )
            stdout = res.stdout.read()
            stderr = res.stderr.read()
            # 制作报头
            header_dic = {
                'total_size': len(stdout)+len(stderr),  # 总共的大小
                'filename': None,
                'md5': None
            }
            header_json = json.dumps(header_dic) #字符串类型
            header_bytes = header_json.encode('utf-8')  #转成bytes类型(但是长度是可变的)
            #先发报头的长度
            coon.send(struct.pack('i',len(header_bytes))) #发送固定长度的报头
            #再发报头
            coon.send(header_bytes)
            #最后发命令的结果
            coon.send(stdout)
            coon.send(stderr)
        coon.close()
    phone.close()
    3. TCP/IP协议详情

    TCP和UDP协议在传输层


    4. 简述3次握手,四次挥手?

    三次握手:

        client发送请求建立通道;
        server收到请求并同意,同时也发送请求建通道;
        client收到请求并同意,建立完成
      
    四次挥手:
        client发送请求断开通道;
        server收到请求并同意,同时还回复client上一条消息;
        server也发送请求断开通道;
        client受到消息结束
     
     
  • 相关阅读:
    在列表中添加序号列
    在C#中使用正则表达式
    Git
    Linux 配置Java环境
    讯飞语义理解 JAVA SDK
    分屏显示
    Gdiplus
    重启进程
    MFC 常用功能属性
    MFC 打印
  • 原文地址:https://www.cnblogs.com/wlike/p/12048125.html
Copyright © 2020-2023  润新知