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\r\n\r\n" % 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("\r\n")


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 * '\0'
    # 将数据发送给服务器
    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 '\tTime=%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网络编程攻略》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值