zoukankan      html  css  js  c++  java
  • 网络TCP——Python

    TCP简介

    TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

    TCP通信需要经过创建连接、数据传送、终止连接三个步骤。

    TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,"打电话""

    TCP与UDP的不同点

    • 面向连接(确认有创建三方交握,连接已创建才作传输。)
    • 有序数据传输
    • 重发丢失的数据包
    • 舍弃重复的数据包
    • 无差错的数据传输
    • 阻塞/流量控制

    TCP通信模型

    udp通信模型

    TCP客户端和TCP服务器

    tcp客户端

    tcp服务器

     tcp的客户端要比服务器端简单很多

    示例代码:

    from socket import *
    
    # 创建socket
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
    # 目的信息
    server_ip = input("请输入服务器ip:")
    server_port = int(input("请输入服务器port:"))
    
    # 链接服务器
    tcp_client_socket.connect((server_ip, server_port))
    
    # 提示用户输入数据
    send_data = input("请输入要发送的数据:")
    
    tcp_client_socket.send(send_data.encode("gbk"))
    
    # 接收对方发送过来的数据,最大接收1024个字节
    recvData = tcp_client_socket.recv(1024)
    print('接收到的数据为:', recvData.decode('gbk'))
    
    # 关闭套接字
    tcp_client_socket.close()
     

    在程序中,如果想要完成一个tcp服务器的功能,需要的流程如下:

    1. socket创建一个套接字
    2. bind绑定ip和port
    3. listen使套接字变为可以被动链接
    4. accept等待客户端的链接
    5. recv/send接收发送数据

    一个很简单的tcp服务器如下:

    from socket import *
    
    # 创建socket
    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    
    # 本地信息
    address = ('', 7788)
    
    # 绑定
    tcp_server_socket.bind(address)
    
    # 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
    tcp_server_socket.listen(128)
    
    # 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
    # client_socket用来为这个客户端服务
    # tcp_server_socket就可以省下来专门等待其他新客户端的链接
    client_socket, clientAddr = tcp_server_socket.accept()
    
    # 接收对方发送过来的数据
    recv_data = client_socket.recv(1024)  # 接收1024个字节
    print('接收到的数据为:', recv_data.decode('gbk'))
    
    # 发送一些数据到客户端
    client_socket.send("thank you !".encode('gbk'))
    
    # 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
    client_socket.close()

    tcp注意点

    1. tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
    2. tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
    3. tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
    4. 当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
    5. 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
    6. listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
    7. 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信
    8. 关闭accept返回的套接字意味着这个客户端已经服务完毕
    9. 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线

    案例:文件下载器

    服务器 参考代码如下:

    客户端 参考代码如下:

    from socket import *
    import sys
    
    
    def get_file_content(file_name):
        """获取文件的内容"""
        try:
            with open(file_name, "rb") as f:
                content = f.read()
            return content
        except:
            print("没有下载的文件:%s" % file_name)
    
    
    def main():
    
        if len(sys.argv) != 2:
            print("请按照如下方式运行:python3 xxx.py 7890")
            return
        else:
            # 运行方式为python3 xxx.py 7890
            port = int(sys.argv[1])
    
    
        # 创建socket
        tcp_server_socket = socket(AF_INET, SOCK_STREAM)
        # 本地信息
        address = ('', port)
        # 绑定本地信息
        tcp_server_socket.bind(address)
        # 将主动套接字变为被动套接字
        tcp_server_socket.listen(128)
    
        while True:
            # 等待客户端的链接,即为这个客户端发送文件
            client_socket, clientAddr = tcp_server_socket.accept()
            # 接收对方发送过来的数据
            recv_data = client_socket.recv(1024)  # 接收1024个字节
            file_name = recv_data.decode("utf-8")
            print("对方请求下载的文件名为:%s" % file_name)
            file_content = get_file_content(file_name)
            # 发送文件的数据给客户端
            # 因为获取打开文件时是以rb方式打开,所以file_content中的数据已经是二进制的格式,因此不需要encode编码
            if file_content:
                client_socket.send(file_content)
            # 关闭这个套接字
            client_socket.close()
    
        # 关闭监听套接字
        tcp_server_socket.close()
    
    
    if __name__ == "__main__":
        main()
    from socket import *
    
    
    def main():
    
        # 创建socket
        tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
        # 目的信息
        server_ip = input("请输入服务器ip:")
        server_port = int(input("请输入服务器port:"))
    
        # 链接服务器
        tcp_client_socket.connect((server_ip, server_port))
    
        # 输入需要下载的文件名
        file_name = input("请输入要下载的文件名:")
    
        # 发送文件下载请求
        tcp_client_socket.send(file_name.encode("utf-8"))
    
        # 接收对方发送过来的数据,最大接收1024个字节(1K)
        recv_data = tcp_client_socket.recv(1024)
        # print('接收到的数据为:', recv_data.decode('utf-8'))
        # 如果接收到数据再创建文件,否则不创建
        if recv_data:
            with open("[接收]"+file_name, "wb") as f:
                f.write(recv_data)
    
        # 关闭套接字
        tcp_client_socket.close()
    
    
    if __name__ == "__main__":
        main()
  • 相关阅读:
    CodeForces 681D Gifts by the List (树上DFS)
    UVa 12342 Tax Calculator (水题,纳税)
    CodeForces 681C Heap Operations (模拟题,优先队列)
    CodeForces 682C Alyona and the Tree (树上DFS)
    CodeForces 682B Alyona and Mex (题意水题)
    CodeForces 682A Alyona and Numbers (水题,数学)
    Virtualizing memory type
    页面跳转
    PHP Misc. 函数
    PHP 5 Math 函数
  • 原文地址:https://www.cnblogs.com/zeon/p/13581656.html
Copyright © 2011-2022 走看看