zoukankan      html  css  js  c++  java
  • Python—socket编程

    一、何为socket编程

    应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。

    生成套接字的两个参数,一个是选择IP协议,另一个是选择UDP或者是TCP.

    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #创建一个套接字, family=AF_INET type=NI_DGRAM
    # 创建一个TCP套接字
    tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    

    这里family的意思是选择哪种协议,AF_INET代表的是IPv4,SOCK_DGRAM创建的是UDP协议。

    二、UDP套接字的收发流程

    1.创建一个UDP套接字

    2.套接字收发数据

    3.关闭套接字

    例子的代码如下:(需要打开网路调试助手进行辅助)

    def main():
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #创建一个套接字, family=2 即family=AF_INET type=16 即type=NI_DGRAM
        send_content = 666
        # 发送数据的内容
        # send_content = send_content.encode('gbk')
        host_addr = ("169.254.190.219", 8080)
        udp_socket.sendto(send_content, host_addr)
        udp_socket.close()
    
    
    
    
    # 套接字发送数据
    def main():
        udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        desc_addr = ("169.254.190.219", 8080)
        udp_socket.bind(("", 9999))
        while True:
            send_content = input("请输入要发送的数据:")
            if send_content == "q":
                break
            send_content=send_content.encode('gbk')
            udp_socket.sendto(send_content, desc_addr)
    
    
    
    
    # 套接字接收数据
    def main():
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        rec_addr =  ("169.254.190.219", 9999)
        udp_socket.bind(rec_addr)
        rec_data = udp_socket.recvfrom(1024)
        print(rec_data)
        rec_content = rec_data[0].decode('gbk')
        print("接收的内容为:{}\n发送地址为:{}  端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
    
    
    
    
        udp_socket.close()
    # 套接字无限循环接收消息
    def main():
        udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        rec_addr = ("169.254.190.219", 9999)
        udp_socket.bind(rec_addr)
        while True:
            rec_data = udp_socket.recvfrom(1024)
            rec_content = rec_data[0].decode('gbk')
            if rec_content == "再见":
                break
            print("接收的内容为:{}\n发送地址为:{}  端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
    
    
    
    
    if __name__ == "__main__":
        main()
    

    在这里有几个注意事项:

    1.在发送中文的时候,我们应该使用encode(“gbk”)进行编码,而不使用utf-8的原因是Windows默认的字体编码是GBK模式。

    2.在接收中文的时候也应该使用decode进行解码。

    3.发送的数据如果没有编码的话,默认只能发送字节类型的数据。

    三、如何使用UDP套接字又接收又发送消息呢?

    如果我们想要使用udp套接字又发送消息又接收消息的话,我们可以定义一个发送消息的函数和一个接收消息的函数,其余部分可以在主函数当中完成。

    首先,我们需要绑定一个ip地址发送数据,其次,我们还需要一个IP地址来接收发送的数据。当然,聊天器的版本并不高,返回的值也是我们所输入的值,当然,如果箱套聊天器变得更加有趣,我们可以对其进行进行升级。这个时候其实只要加入一些判断语句就可以实现哦。比如,我们可以在输入全部都是英文的时候发送“乖乖,你发的都是些什么内容呀,我的智商太低完全看不懂哦”

    import socket
    
    
    
    
    '''
    这是一个自己跟自己聊天的聊天器
    第一版:
    1.要绑定一个ip地址发送数据
    2.要绑定一个ip地址来接收发送的数据
    '''
    def sendaddr(udp_socket):
        send_addr = ("169.254.190.219",9999)
        # udp_socket.bind(send_addr)
        send_content = input("请输入要输入的内容:")
        udp_socket.sendto(send_content.encode('gbk'),send_addr)
    
    
    
    
    def recaddr(udp_socket):
        rec_data = udp_socket.recvfrom(1024)
        rec_content = rec_data[0].decode('gbk')
        if rec_content == "exit":
            exit()
        print("接收的内容为:{}\n发送地址为:{}  端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
    
    
    
    
    def main():
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    
    
    
        udp_socket.bind(("169.254.190.219", 9999))
    
    
    
    
        while True:
            sendaddr(udp_socket)
            recaddr(udp_socket)
        udp_socket.close()
    
    
    
    
    
    
    
    
    if __name__ == "__main__":
        main()
    

    四、TCP套接字的创建流程

    创建一个客户端的流程

    1.创建一个套接字

    2.连接服务器

    3.发送或者是接收数据

    4.关闭套接字

    创建tcp客户端套接字的代码:

    import socket
    '''
    创建TCP客户端的步骤:
    1 创建套接字
    2 连接服务端
    3 接收或者是发送数据
    4 关闭套接字
    '''
    
    
    
    
    # def main():
    #     tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #     server_addr = ("169.254.190.219",8080)
    #
    #     # 连接服务器
    #     tcp_client.connect_ex(server_addr)
    #
    #     # 发送数据
    #     send_content = "haha"
    #     tcp_client.send(send_content.encode("gbk"))
    #
    #     # 接收数据
    #     recv_data = tcp_client.recv(1024)
    #     print(recv_data.decode("gbk"))
    #     # 关闭套接字
    #     tcp_client.close()
    #
    # if __name__ == "__main__":
    #     main()
    

    五、创建服务端的流程

    1、创建一个套接字

    2.绑定地址和端口

    3.将主动改为被动

    4.等待客户连接,创建出一个新的套接字

    5.关闭套接字

    代码如下:

    '''
    创建TCP服务端:
    1 创建套接字
    2 绑定地址
    3 主动变被动
    4 等待客户端连接
    5 发送或接收数据
    6 关闭套接字
    '''# def main():
    #     # 创建套接字
    #     tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #
    #     # 绑定地址
    #     server_addr = ("169.254.190.219",8080)
    #     tcp_server.bind(server_addr)
    #
    #     # 主动变被动
    #     tcp_server.listen(128)
    #
    #     # 等待客户连接
    #     new_client_server, client_addr = tcp_server.accept()
    #     print(client_addr)
    
    
    #
    #     # 接收数据
    #     recv_data = new_client_server.recv(1024)
    #     print(recv_data.decode('gbk'))
    #     #
    #     # 关闭套接字
    #     new_client_server.close()
    #     tcp_server.close()
    # if __name__ == "__main__":
    #     main()
    

    六、如何让一个服务端为多个客户服务

    在日程生活中,我们不可能只为单一的客户服务,有可能有多个人同时排队服务。那这种情况下要怎么办呢?

    简单的逻辑:

    我们要循环主动变被动的过程,每一个客户都会生成一个新的套接字。

    代码如下:

    def main():
        # 创建套接字
        tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    
    
        # 绑定地址和端口
        server_addr = ("169.254.190.219", 8080)
        tcp_server.bind(server_addr)
    
    
    
    
        # 实现为多个客户端服务
        while True:
            # 变主动为被动
            tcp_server.listen(128)
            new_client_server, client_addr = tcp_server.accept()
            # 为一个客户端多次服务
            while True:
                recv_data = new_client_server.recv(1024)
                if recv_data.decode('gbk'):
                    print(recv_data.decode("gbk"))
                    new_client_server.send("消息已经收到".encode('gbk'))
                else:
                    break
            new_client_server.close()
    
    
    
    
        tcp_server.close()
    
    
    
    
    if __name__ == "__main__":
        main()
    

    七、使用TCP套接字模拟文件下载器

    客户端

    如果要使用套接字来模拟文件下载器的话,那么我们客户端大致主要完成的工作:

    1.创建套接字

    2.连接服务器

    3.发送要下载的文件名

    4.接收返回的数据

    5.保存从服务器接收的数据

    6.关闭套接字

    实现代码:

    # @日期:2020-01-10
    # @作者:清欢
    
    
    
    
    import socket
    '''文件下载器
    1.创建一个套接字
    2.连接服务器
    3.发送要下载的文件名
    4.接收服务端返回的数据
    5.保存数据
    6.关闭套接字
    '''
    def save_data(circle):
        with open("cilcle_copy.py","w",encoding="utf-8") as f:
            f.write(circle.decode())
    
    
    
    
    def main():
        # 创建套接字
        tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    
    
        # 连接服务器
        server_addr = ("169.254.190.219", 8080)
       tcp_client.connect(server_addr)
    
    
    
    
    
    
        # 发送要下载的数据名
        load_name = input("请输入要下载的文件名")
        tcp_client.send(load_name.encode())
    
    
    
    
        # 接收返回的数据
        Circle = tcp_client.recv(1024)
        save_data(Circle)
        #
    
    
    
    
    if __name__ == '__main__':
        main()
    

    服务端

    如果要完成文件下载器,服务端需要做的工作的大致流程:

    1.创建套接字

    2.绑定地址和IP

    3.化主动为被动,等待客户端连接

    4.创建客户的新的套接字

    5.接收客户端发过来的文件名

    6.读取文件的内容并返回给客户端

    7.关闭套接字

    # 练习
    # 清欢
    
    
    
    
    import socket
    '''
    文件下载器的服务端:
    1 创建套接字
    2 绑定地址和端口
    3 变主动为被动
    4 等待接收客户端发过来的文件名
    5 读取文件信息
    6 将文件信息发送给客户端
    7 关闭套接字
    '''
    
    
    
    
    def main():
        # 创建套接字
        tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    
    
        # 绑定地址和端口
        server_addr = ("169.254.190.219",8080)
        tcp_server.bind(server_addr)
    
    
    
    
        # 变主动为被动
        tcp_server.listen(128)
    
    
    
    
        # 等待客户连接
        new_client_server, client_addr = tcp_server.accept()
    
    
    
    
        # 接收顾客发过来的文件名
        recv_content = new_client_server.recv(1024).decode()
    
    
    
    
        # 读取文件内容
        if recv_content:
            with open(recv_content, 'rb') as f:
                file_content = f.read()
                new_client_server.send(file_content)
        else:
            print("输入为空")
        new_client_server.close()
        tcp_server.close()
    
    
    
    
    if __name__ == '__main__':
        main()
    

    TCP与UDP的区别

    1、TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接

    2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

    3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

    4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

    5、TCP对系统资源要求较多,UDP对系统资源要求较少。

  • 相关阅读:
    MySQL 如何只导出 指定的表 的表结构和数据 ( 转 )
    速度之王 — LZ4压缩算法(三)
    lz4,pigz,gzip 3者比较
    用php实现百度网盘图片直链的代码分享
    hibernate的oracle配置(转)
    过滤器
    dom4j创建格式化的xml文件
    jstl表达式
    jsp内置对象和el表达式
    jsp 三大指令和动作标签
  • 原文地址:https://www.cnblogs.com/lxwphp/p/15452998.html
Copyright © 2011-2022 走看看