zoukankan      html  css  js  c++  java
  • TCP

    tcp:tcp使用较多.直接使用较少,使用 封装之后上层的库 较多. 不会有人从头开始写一个tcp的协议,
    然后做个什么软件的,造轮子这事情,差不多就得了.知道原理,会使用别人造的库就行.出错了能够找到错误的原因,处理掉就好.

    面试常问:tcp和udp的区别

    tcp:Transmission Control Protocol 传输控制协议

    1.>面向连接(就是打电话的时候先拨号的操作)

    2.>可靠的(ACK应答)

    3.>基于字节流 stream的方式

    面向连接:在通信之前确认双方在线.--> 在通信之前需要先建立连接<拨号>

    字节流:无界限,没有量词来界定这个消息的体量,都是连接在一起的.
    没有消息边界,对方多次发送的消息,我一次就接收.不是每次都接收一部分.从接收的数据中看不到数据是哪一次发送的. 简称tcp的 "粘包" 问题.

    特点:面向连接,可靠,基于字节流

    优点:可靠,稳定

    缺点:慢,占用系统资源高

    步骤:创建连接,数据传送,

    不适用广播,一对一的单播

    为啥可靠?原因:
    1.>发送应答:每发一次都必须得到对方的应答(ACK)

    2.>超时重传:一定的时间内没有收到回复,就认为这个数据包已经出错或者丢失,发送方会再次发这个数据包

    3.>错误校验:奇偶校验,循环冗余校验等等

    4.>流量控制与阻塞管理:发送方有一个动态调整的发送速度的机制.

    5.>有序编号

    udp中无序,可能重复,有可能乱序.

    最大特点有了connect()方法


    socket就是一个手机,这么理解即可

    1.创建socket(买个手机)
    2.建立连接(拨号)
    3.发送数据(通话)
    4.关闭socket(挂掉)

    tcp客户端:

    """
    socket就是一个手机,这么理解即可
    
    1.创建socket(买个手机)
    2.建立连接(拨号)
    3.发送数据(通话)
    4.关闭socket(挂掉)
    
    """
    
    import socket
    
    # 创建
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 连接
    tcp_client_socket.connect(('192.168.14.26', 8089))
    
    while True:
    
        # 发送数据
        send_data = input('输入发送给服务器的数据:')
        tcp_client_socket.send(send_data.encode())  # 参数是一个字节流bytes类型的数据
    
        # 接收返回 ,面向连接的(地址肯定是连接的对方的地址)不再需要对方的地址,只需要对方发送的数据
        # 阻塞等待的接收返回
        # recv()返回值的含义:
        # recv()正常情况下是接收到的数据<bytes类型>
        # 如果对方断开连接,返回值就是b''<空字节>,不是对方发送的数据,是系统提示对方断开的标志
        recv_data = tcp_client_socket.recv(1024)  # recv()返回一个数据(bytes类型)即可,没有地址信息
        # print(recv_data.decode('gbk'))  # 解码解得是调试助手发来的数据,而调试助手发送的时候是gbk的编码格式
        # 断开连接输出:b''  <空字节>
        # print(recv_data)  # 解码解得是调试助手发来的数据,而调试助手发送的时候是gbk的编码格式
        # recv_data != None and recv_data !=''
        if recv_data:  # 如果recv_data不为空,为真
            print(recv_data.decode('gbk'))
        else:  # 为空,终止
            print('服务器断开连接')
            break
    # 关闭
    tcp_client_socket.close()

    tcp服务器:

    """
    tcp服务器:
    1.>socket()买个手机
    
    2.>bind()绑定10086
    
    3.>listen()安装客户服务系统,设定等待服务区的大小,从等待区域中取出一个客户(和客户建立连接)
    
    4.>accept()并转接到分机,具体的同事使用分机和客户交流
    
    5.>close()分机挂机
    
    总计挂机
    
    总机不会挂机
    分机会挂机
    实际在交流信息的时候是和分机交流
    总机只是和客户建立连接,分到等待区
    
    服务器分为两种socket,一种专门来接受客户的连接请求,一种才是和客户进行数据交流
    
    服务器是被动的
    """
    import socket
    
    # 创建服务器socket
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定,如果不绑定,别人就找不到这个地址了
    tcp_server_socket.bind(('', 9999))  # ip为空,意味着绑定了这台主机上面的所有网卡,一台机子上面不是只有一个网卡,至少是2个网卡
    
    # 监听等待  安装客户服务系统 --->1.将socket设置为被动socket<被动接受连接  默认是主动连接>  2.设置等待服务区的大小为128
    tcp_server_socket.listen(128)
    print('服务器已建立连接')
    # 转到分机接收     从等待服务区取出一个客户端来服务
    # 返回值是一个元组,两个元素,第一个元素是客户端socket<分机>,第二个是客户端的(ip,port)<地址>
    tcp_client_socket, client_info = tcp_server_socket.accept()  # 无参数,只有返回值,返回值是socket和 address_info
    print('接受到客户%s的连接请求' % str(client_info))
    
    while True:
        # 使用分机和客户端进行交流    ----> 数据收发
        recv_data = tcp_client_socket.recv(1024)
        if recv_data:
            print('接收到的客户数据:', recv_data.decode())
        else:  # b''
            print('客户端下线了')
            break
    
        # 服务器返回给客户信息
        tcp_client_socket.send('are you OK?'.encode())
    
    # 分机关闭
    tcp_client_socket.close()
    # 总机关闭
    tcp_server_socket.close()
    
    # 只有客户端才需要知道服务器的ip和端口信息,服务器不需要知道客户的信息,再建立了连接之后会收到的
    """<对象>"""
    
    """一定是先开服务器,后开客户端"""

    tcp服务器升级版:

    """
    tcp服务器:
    1.>socket()买个手机
    
    2.>bind()绑定10086
    
    3.>listen()安装客户服务系统,设定等待服务区的大小,从等待区域中取出一个客户(和客户建立连接)
    
    4.>accept()并转接到分机,具体的同事使用分机和客户交流
    
    5.>close()分机挂机
    
    总计挂机
    
    总机不会挂机
    分机会挂机
    实际在交流信息的时候是和分机交流
    总机只是和客户建立连接,分到等待区
    
    服务器分为两种socket,一种专门来接受客户的连接请求,一种才是和客户进行数据交流
    
    服务器是被动的
    """
    import socket
    
    # 创建服务器socket
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定,如果不绑定,别人就找不到这个地址了
    tcp_server_socket.bind(('', 9999))  # ip为空,意味着绑定了这台主机上面的所有网卡,一台机子上面不是只有一个网卡,至少是2个网卡
    
    # 监听等待  安装客户服务系统 --->1.将socket设置为被动socket<被动接受连接  默认是主动连接>  2.设置等待服务区的大小为128
    tcp_server_socket.listen(128)
    print('服务器已建立连接')
    
    # 就是领导接活,下面的小弟只管干活
    while True:
        # 转到分机接收     从等待服务区取出一个客户端来服务
        # 返回值是一个元组,两个元素,第一个元素是客户端socket<分机>,第二个是客户端的(ip,port)<地址>
        tcp_client_socket, client_info = tcp_server_socket.accept()  # 无参数,只有返回值,返回值是socket和 address_info
        print('接受到客户%s的连接请求' % str(client_info))
    
        while True:
            # 使用分机和客户端进行交流    ----> 数据收发
            recv_data = tcp_client_socket.recv(1024)
    
            # 服务器返回给客户信息,  接收到的是gbk的编码数据流,需要解码后再次编码为utf-8
            tcp_client_socket.send(recv_data.decode('gbk').encode())
            if recv_data:
                print('接收到的客户数据:', recv_data.decode('gbk'))
            else:  # b''
                print('客户端下线了')
                break
    
        # 分机关闭
        tcp_client_socket.close()
        # # 总机关闭
        # tcp_server_socket.close()
    
        # 我需要被别人找到,就要使用bind()
    
        # 想要接受连接,必须先listen()
        # 收发数据都是client_socket
        # accept() 接受:被动的
        # close() 断开连接请求
        # 0字节长度 ---> 对方断开连接了
        # 解阻塞:由卡死到不卡的状态变化.

    文件下载器-客户端:

    """
    客户端:  1.连接服务器(ip,port)
            2.下载文件的名字
    服务器接收到客户端需要下载的文件名字,搜索文件,传给客户端
    客户端写入到自己的文件中.
    
    
    """
    # 1. 输入服务器ip,端口
    # 2. 建立socket 连接服务器
    # 3. 输入文件名
    # 4. 发送文件名给服务器
    # 5. 使用socket接收来自服务器的数据(保存在文件中)
    # 6. 如果收到b'',说明服务器断开连接-已经下载好
    # 7. 关闭socket
    
    
    import socket
    
    server_ip = input('输入server的ip:')
    server_port = int(input('输入server的port:'))
    
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client_socket.connect((server_ip, server_port))
    
    file_name = input('输入下载的文件名:')
    
    client_socket.send(file_name.encode())
    
    # 文本方式打开   str类型  需要解码  图片无法解码,所以直接使用二进制方式打开即可
    with open("download" + file_name, 'wb') as file:
        while True:
            file_data = client_socket.recv(4096)  # ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。原因是服务器出错了
            # 如果对方断开连接,我们就接收到b''
            if not file_data:
                print('服务器断开连接,说明文件传输完成')
                break
    
            # 否则就将收到的数据直接写入带文件中
            file.write(file_data)
    
    client_socket.close()

    文件下载器-服务器:

    """
    服务器:
    # 1. 创建服务器socket
    # 2. bind() listen
    # 3. 接受客户端连接请求,取出一个客户端关联的socket
    # 4. 使用关联的socket和客户端进行通信
    #    收客户端需要下载的文件名,发送文件名对应的数据
    # 5. 发送完成,断开连接<就是关闭了client_socket
    # 关闭服务器socket
    
    
    """
    
    
    import socket
    
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置选项  SO_REUSEADDR:二次利用,释放地址,重新利用地址
    # 忽略2msl等待时间,直接进行这个地址的再次利用
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(('', 9991))
    server_socket.listen(128)
    
    while True:
        client_socket, client_info = server_socket.accept()
        # print('接收到连接请求%s' % client_info)  #  TypeError: not all arguments converted during string formatting
        # print('接收到%s连接请求' % str(client_info))  # 记得这里的client_info是一个元组类型,不能使用%号来连接,客户端那边也会报错
        print('接收到连接请求:', client_info)  # 记得这里的client_info是一个元组类型,不能使用%号来连接,客户端那边也会报错
    
        file_name = client_socket.recv(256).decode()  # 文件名一般很短,256字节长度可以了
    
        # 打开本地文件,读取数据
        try:
            # 捕获如果没有这个文件的异常
            file = open(file_name, 'rb')
        except Exception as e:
            pass
        else:
            # 读取
            file_data = file.read()
            # 发送
            client_socket.send(file_data)
            # 关闭文件
            file.close()
        finally:
            # 关闭socket
            client_socket.close()
    
    server_socket.close()
  • 相关阅读:
    关于width属性max/min-content和fit-content
    director.js实现前端路由
    第一篇博文
    AtCoder Beginner Contest 120 题解
    AtCoder Beginner Contest 121 题解
    AtCoder Beginner Contest 115 题解
    Python中list的复制及深拷贝与浅拷贝探究
    Python中print()函数不换行的方法
    高斯消元法的C++简单实现
    Python中list作为默认参数的陷阱
  • 原文地址:https://www.cnblogs.com/huaibin/p/12097758.html
Copyright © 2011-2022 走看看