zoukankan      html  css  js  c++  java
  • Python的套接字、IPv4和简单的客户端/服务器编程

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import socket
    from binascii import hexlify
    import sys
    # 对用户输入的命令行参数进行解析
    import argparse
    
    # 先$ pip install ntplib 安装需要的python库文件
    import ntplib
    from time import ctime
    import struct
    
    # python中每个函数之间要隔2行
    
    # 发送数据缓冲区的大小
    SEND_BUF_SIZE = 4096
    # 接受数据缓冲区的大小
    RECV_BUF_SIZE = 4096
    
    NTP_SERVER = "0.uk.pool.ntp.org"
    TIME1970 = 2208988800L
    
    
    def print_local_machine_infor():
        """打印本地主机名和本地主机的ip地址"""
        host_name = socket.gethostname()
        host_ip_address = socket.gethostbyname(host_name)
    
        print "Host name: %s" % host_name
        print "Host ip address: %s" % host_ip_address
    
    
    def get_remote_machine_infor(remote_host_name="www.python.org"):
        """获取远程服务器的ip地址"""
        try:
            print "Remote ip address: %s" % socket.gethostbyname(remote_host_name)
        except socket.error, err_msg:
            print "%s: %s" % (remote_host_name, err_msg)
    
    
    def convert_ip4_address(ip_address):
        # 将一个字符串IP地址转换为一个32位的网络字节序列(ascii码转二进制)
        packed_ip_address = socket.inet_aton(ip_address)
        # 将32位网络字节序列转换成字符串形式的ip地址(二进制转ascii码)
        unpacked_ip_address = socket.inet_ntoa(packed_ip_address)
    
        # 将二进制数据的网络字节序列hexlify转换成16进制显示
        print "Ip Address: %s => Packed: %s, Unpacked: %s" 
            % (ip_address, hexlify(packed_ip_address), unpacked_ip_address)
    
    
    def find_service_name(protocol_name, port_number):
        """根据网络协议和端口号,获取服务名称"""
        print "Port: %s => service name: %s" % (port_number, socket.getservbyport(port_number, protocol_name))
    
    
    def convert_integer(port_number):
        """网络端口之间序列的转换"""
        # 32-bit--将数据从网络字节序和主机字节序之间进行转换
        print "Original: %s => Long  host byte order: %s, Network byte order: %s" 
              % (port_number, socket.ntohl(port_number), socket.htonl(port_number))
        # 16-bit--将数据从网络字节序和主机字节序之间进行转换
        print "Original: %s => Short  host byte order: %s, Network byte order: %s" 
              % (port_number, socket.ntohs(port_number), socket.htons(port_number))
    
    
    def set_tcp_socket_timeout(wait_time):
        """设置tcp套接字的超时等待时间"""
        # 创建流式tcp套接字
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 打印套接字的默认的超时等待时间
        print "Default socket timeout: %s" % s.gettimeout()
    
        # 设置套接字的超时等待时间
        s.settimeout(wait_time)
        print "Current socket timeout: %s" % s.gettimeout()
    
    
    def send_data_to_server():
        # 构建命令行参数解释器
        parser = argparse.ArgumentParser(description='Socket Error Examples')
        # 添加命令行的可选输入参数
        parser.add_argument('--host', action="store", dest="host", required=False)
        parser.add_argument('--port', action="store", dest="port", type=int, required=False)
        parser.add_argument('--file', action="store", dest="file", required=False)
    
        # 替换输入手动输入的命令行
        given_args = parser.parse_args(["--host=www.python.org", "--port=80", "--file=Hello World"])
        # 获取命令行输入的主机名
        host = given_args.host
        # 获取命令行输入的端口号
        port = given_args.port
        # 获取命令行输入的发送数据
        filename = given_args.file
    
        # 创建tcp网络套接字
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except socket.error, e:
            # 打印创建网络套接字的错误
            print "Error creating socket: %s" % e
            # 退出进程
            sys.exit(1)
    
        # 向指定的网络服务器发起网络连接
        try:
            s.connect((host, port))
        except socket.gaierror, e:
            print "Address-related error connecting to server: %s" % e
            sys.exit(1)
        except socket.error, e:
            print "Connection error: %s" % e
            sys.exit(1)
    
        try:
            # 向指定的服务器发送数据请求
            s.sendall("GET %s HTTP/1.0
    
    " % filename)
        except socket.error, e:
            print "Error sending data: %s" % e
            sys.exit(1)
    
        # 循环输入服务器返回的数据
        while 1:
            # 接受请求服务器返回的数据
            try:
                buf = s.recv(2048)
            except socket.error, e:
                print "Error receiving data: %s" % e
                sys.exit(1)
            # 判断服务器返回的数据是否为null
            if not len(buf):
                break
            # 将指定服务器返回的数据打印出来
            sys.stdout.write(buf)
        # 换行
        sys.stdout.write("
    ")
    
    
    def modify_buff_size():
        # 创建流式tcp套接字
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 获取套接字默认发送数据缓冲区的大小
        bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
        print "Orig Send Buffer size [Before]:%d" % bufsize
    
        bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
        print "Orig Recv Buffer size [Before]:%d" % bufsize
    
        # 设置网络套接字为非延迟模式
        sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
    
        # 设置网络套接字的发送数据缓冲区的大小
        sock.setsockopt(
            socket.SOL_SOCKET,
            socket.SO_SNDBUF,
            SEND_BUF_SIZE)
        # 设置网络套接字的接受数据缓冲区的大小
        sock.setsockopt(
            socket.SOL_SOCKET,
            socket.SO_RCVBUF,
            RECV_BUF_SIZE)
    
        # 打印设置以后的网络套接字的发送数据缓冲区的大小
        bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
        print "Send Buffer size [After]:%d" % bufsize
    
        # 打印设置以后的网络套接字的接受数据缓冲区的大小
        bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
        print "Recv Buffer size [After]:%d" % bufsize
    
    
    def reuse_socket_addr():
        # 创建tcp流式套接字
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 获取网络套接字默认的地址重用状态值
        old_state = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
        print "Old sock state: %s" % old_state
    
        # 设置网络套接字的地址重用状态的值为1即重用套接字地址
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 获取网络套接字的地址新的重用状态值
        new_state = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
        print "New sock state: %s" % new_state
    
        # 端口
        local_port = 8282
    
        # 创建新的套接字
        srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置网络套接字的地址为可重用的
        srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定网络套接字
        srv.bind(("127.0.0.1", local_port))
        # 进行网络套接字的监听
        srv.listen(1)
        print ("Listening on port: %s " % local_port)
    
        while True:
            # 接受客户端的网络连接
            try:
                connection, addr = srv.accept()
                print 'Connected by %s:%s' % (addr[0], addr[1])
            except KeyboardInterrupt:
                break
            except socket.error, msg:
                print '%s' % (msg,)
    
    
    def test_socket_modes():
        # 创建tcp网络套接字
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置网络模式为阻塞模式
        s.setblocking(1)
        # 设置超时等待时间
        s.settimeout(0.5)
    
        # 绑定ip地址和端口号
        s.bind(("127.0.0.1", 0))
    
        # 获取网路套接字的信息("ip地址", 端口号)
        socket_address = s.getsockname()
        # 打印网络套接字的名称
        print "Trivial Server lauched on socket: %s" % str(socket_address)
    
        # 进行网络套接字的监听,等待客户端的连接
        while 1:
            s.listen(1)
    
    
    def print_ntp_time():
        # 创建NTPClient实例对象
        ntp_client = ntplib.NTPClient()
        # 向NTP服务器发送时间请求
        response = ntp_client.request('pool.ntp.org')
        # 打印获取的时间
        print "ntp time: "+str(ctime(response.tx_time))
    
    
    def sntp_client():
        # 创建udp套接字
        client = socket.socket( socket.AF_INET, socket.SOCK_DGRAM)
        # 构建发送的数据包
        data = 'x1b' + 47 * ''
        # 将数据发送给服务器
        client.sendto(data, (NTP_SERVER, 123))
        # 获取服务返回的数据和ip地址(元组)
        data, address = client.recvfrom(1024)
        if data:
            print 'Response received from:', address
        # 解包服务返回的数据即时间
        t = struct.unpack('!12I', data)[10]
        # 减去从1970年1月1日对应的时间戳
        t -= TIME1970
    
        # 打印获取到的时间信息
        print '	Time=%s' % ctime(t)
    
    
    # 若当前模块,直接执行时,执行下面的代码
    if __name__ == '__main__':
    
        # 打印本地主机的名称和ip地址
        print_local_machine_infor()
    
        # 获取远程服务器的ip地址
        get_remote_machine_infor()
    
        # 进行ip地址的转换
        convert_ip4_address("192.168.0.1")
    
        # 通过端口号和协议,获取服务名称
        for obj in [("tcp", 80), ("tcp", 25), ("tcp", 53)]:
            find_service_name(obj[0], obj[1])
    
        # 网络端口的字节序的转换
        convert_integer(80)
    
        # 设置tcp套接字的超时等待时间
        set_tcp_socket_timeout(10)
    
        # 向指定的服务发送数据
        send_data_to_server()
    
        # 修改网路套接字的接受数据和发送数据的缓冲区的大小
        modify_buff_size()
    
        # 打印ntp网络时间
        print_ntp_time()
    
        # 获取当前时间
        sntp_client()
    
        # 创建阻塞模式的服务器套接字
        #test_socket_modes()
    
        # 重用套接字地址
        reuse_socket_addr()


    简单的网路连接服务端

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import socket
    import argparse
    
    host = 'localhost'
    data_payload = 2048
    backlog = 5 
    
    
    def echo_server(port):
        """ 简单的网络连接服务器 """
        # 创建流式TCP网络套接字
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 设置可以重用网络套接字地址
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
        # 构建绑定网络套接字的信息对象
        server_address = (host, port)
        print "Starting up echo server  on %s port %s" % server_address
    
        # 绑定ip地址和端口
        sock.bind(server_address)
        # 进行网络套接字的监听
        sock.listen(backlog)
    
        while True: 
            print "Waiting to receive message from client"
            # 接受客户端的网络连接
            client, address = sock.accept()
            # 接受客户端发送来的数据
            data = client.recv(data_payload)
    
            # 向客户端发送数据
            if data:
                print "Data: %s" % data
                client.send(data)
                print "sent %s bytes back to %s" % (data, address)
    
            # 关闭网络套接字
            client.close() 
       
    if __name__ == '__main__':
    
        # 构建命令行参数解释器
        parser = argparse.ArgumentParser(description='Socket Server Example')
        # 添加非可选参数--port(端口号)
        parser.add_argument('--port', action="store", dest="port", type=int, required=False)
    
        # 解析用户输入的命令行参数
        given_args = parser.parse_args(["--port=8777"])
        # 获取网络连接的端口号
        port = given_args.port
    
        # 创建网络连接的服务器
        echo_server(port)


    简单的网络连接客户端

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import socket
    import argparse
    
    host = 'localhost'
    
    
    def echo_client(port):
        """ 简单网络连接客户端 """
        # 创建TCP流式网络套接字
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 构建连接服务器的信息对象(ip地址,端口号)
        server_address = (host, port)
        print "Connecting to %s port %s" % server_address
    
        # 向服务器发起网络连接
        sock.connect(server_address)
    
        try:
            # 发送给服务器的数据
            message = "Test message. This will be echoed"
            print "Sending %s" % message
    
            # 向服务器发送数据信息
            sock.sendall(message)
    
            amount_received = 0
            # 期望收到服务器返回的数据长度
            amount_expected = len(message)
            # 循环获取服务器返回给客户端的数据
            while amount_received < amount_expected:
                # 获取服务器返回的数据
                data = sock.recv(16)
                amount_received += len(data)
                print "Received: %s" % data
        except socket.errno, e:
            print "Socket error: %s" % str(e)
        except Exception, e:
            print "Other exception: %s" % str(e)
        finally:
            print "Closing connection to the server"
            # 关闭网络套接字
            sock.close()
    
    
    if __name__ == '__main__':
    
        # 构建命令行参数解释器对象
        parser = argparse.ArgumentParser(description='Socket Server Example')
        # 添加非可选的参数--port(端口号)
        parser.add_argument('--port', action="store", dest="port", type=int, required=False)
    
        # 解析用户输入的命令行参数
        given_args = parser.parse_args(["--port=8777"])
        # 获取用户输入的网络端口号
        port = given_args.port
    
        # 创建网络连接客户端
        echo_client(port)
    

    参考:《python网络编程攻略》

  • 相关阅读:
    TCP/IP学习笔记:组播
    使用WITH AS 优化SQL
    帮盖尔优化SQL子查询优化的经典案例
    帮盖尔优化SQL
    子查询里面有树形查询,子查询选择使用in/exists需要特别留意
    [Linux] 服务器性能调优(CPU绑定)
    TCP/IP学习笔记:RIP
    TCP/IP学习笔记:路由与BGP
    利用Merge代替复杂的UPDATE语句
    android开机启动流程说明
  • 原文地址:https://www.cnblogs.com/csnd/p/11800636.html
Copyright © 2011-2022 走看看