Python_套接字、IPv4和简单的客户端/服务器编程

《Python网络编程攻略》学习笔记

TCP用主机的IP地址加上主机的端口号作为TCP连接的端点,这种端点叫做套接字(socket)或插口

获取远程设备的IP地址

import socket
def get_remote_machine_info():
    remote_host = "www.python.org"
    try:
        print("IP address: %s" % socket.gethostbyname(remote_host)) #参数为远程设备的主机名
    except socket as err_msg:
        print("%s: %s" %(remote_host, err_msg))

if __name__ == "__main__":
    get_remote_machine_info()
    
# IP address: 151.101.228.223

将IPv4地址转换成不同的格式

import socket
from binascii import hexlify
def convert_ip4_address():
    for ip_addr in ["127.0.0.1", "192.168.0.1"]:
        packed_ip_addr = socket.inet_aton(ip_addr)
        unpacked_ip_addr = socket.inet_ntoa(packed_ip_addr)
        print("IP address: %s => packed : %s, Unpacked : %s" % (ip_addr, hexlify(packed_ip_addr).decode(), unpacked_ip_addr))

if __name__ == "__main__":
    convert_ip4_address()

# IP address: 127.0.0.1 => packed : 7f000001, Unpacked : 127.0.0.1
# IP address: 192.168.0.1 => packed : c0a80001, Unpacked : 192.168.0.1

通过指定的端口和协议找到服务名

import socket
def find_servert_name():
    protocolname = "tcp"
    for port in [80, 25]:
        # socket.getservbyport(port, protocolname)传入端口号和协议名返回服务名
        print("Port: %s => service name: %s" % (port, socket.getservbyport(port, protocolname)))
    print("Port: %s => service name: %s" % (53, socket.getservbyport(53, "udp")))

if __name__ == "__main__":
    find_servert_name()
# Port: 80 => service name: http
# Port: 25 => service name: smtp
# Port: 53 => service name: domain

主机字节序和网络字节序之间相互转换

import socket
def convert_integer():
    data = 1234
    # 32-bit
    # socket.ntohl(data)将32位整数从网络字节序转换为长整型主机字节顺序.
    # socket.htohl(data)将32位整数从长整型主机字节序转换为网络字节顺序。
    print("Original: %s => Long host byte order: %s, Network byte order: %s" % (data, socket.ntohl(data), socket.htonl(data)))
    #16-bit
    # socket.ntohs(data)将16位整数从网络字节序转换为短整型主机字节顺序.
    # socket.htohs(data)将16位整数从短整型主机字节序转换为网络字节顺序.
    print("Original: %s => Short host byte order: %s, Network byte order: %s" % (data, socket.ntohs(data), socket.htons(data)))

if __name__ == "__main__":
    convert_integer()

# Original: 1234 => Long host byte order: 3523477504, Network byte order: 3523477504
# Original: 1234 => Short host byte order: 53764, Network byte order: 53764

设定并获取默认的套接字超时时间

import socket
def test_socket_timeout():
    s = socket.socket()
    # gettimeout()获取套接字超时时间
    print("Default socket timeout: %s" % s.gettimeout())
    s.settimeout(100) #修改超时时间 (参数可以是秒数,非负浮点数,也可以是None)
    print("Current socket timeout: %s" % s.gettimeout())

if __name__ == "__main__":
    test_socket_timeout()

# Default socket timeout: None
# Current socket timeout: 100.0

修改套接字发送和接收的缓冲区大小

import socket

SEND_BUF_SIZE = 4096
RECV_BUF_SIZE = 4096
def modify_buff_size():
    sock = socket.socket()
    # 获取套接字发送的缓存区大小
    bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
    print("Buffer size [Default]: %d" % bufsize)

    # 修改套接字对象属性(参数:level,optname, value;optname是选项名,value是该选项名的值)
    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("Buffer size [Current]:%d" % bufsize)

if __name__ == "__main__":
    modify_buff_size()

# Buffer size [Default]: 8192
# Buffer size [Current]:4096

把套接字改为阻塞或非阻塞模式

默认情况下,TCP套接字处于阻塞模式中。也就是说,除非完成了某项操作,否则不会把控制权交给程序。

import socket
def test_socket_modes():
    sock = socket.socket()
    # 参数为1把套接字设为阻塞模式,参数为0把套接字设为非阻塞模式
    sock.setblocking(1)
    sock.settimeout(0.5)
    sock.bind(("127.0.0.1", 0))

    socket_address = sock.getsockname()
    print("在套接字上启动简易服务器: %s" % str(socket_address))
    while True:
        sock.listen(1)

if __name__ == "__main__":
    test_socket_modes()

# 在套接字上启动简易服务器: ('127.0.0.1', 3873)

重用套接字地址

扫描二维码关注公众号,回复: 3501593 查看本文章
import socket
import sys
def reuse_socket_addr():
    sock = socket.socket()

    old_state = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
    print("Old sock state: %s" % old_state)

    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_porl = 8282

    srv = socket.socket()
    srv.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    srv.bind( ("127.0.0.1", local_porl) )
    srv.listen()
    print("Listening on port: %s" %local_porl)
    while True:
        try:
            connection, addr = srv.accept()
            print("Connected by %s: %s" % (addr[0], addr[1]))
        except KeyboardInterrupt:
            break
        except socket.error as e:
            print( "%s" % e)

if __name__ == "__main__":
    reuse_socket_addr()

# Old sock state: 0
# New sock state: 1
# Listening on port: 8282
# Connected by 127.0.0.1: 4863 用一个客户端连接测试
# Connected by 127.0.0.1: 4864
# Connected by 127.0.0.1: 4865

编写一个简单的回显客户端/服务器应用

服务器端

import socket  
server = socket.socket()  
server.bind(("127.0.0.1", 9999)) #绑定IP和端口  
server.listen(5) #监听  
while True:  
    print("-------正在等待链接-------")  
    conn, addr = server.accept() #阻塞等待链接  
    print("--------正在链接中--------")  
    print(conn)  
    print(addr)  
    print("--------已经链接上了-------")  

    while True:  
        msg = conn.recv(1024)  
        if not msg: #如果客户端断开,即conn.recv接收为空,这时就断开,而外循环会等待下一个连接
            print("client has lost...")
            break   
        print("客户端发来的信息:", msg.decode())  

        conn.send(msg.upper()) #发信息给客户端  

conn.close()  
server.close() 

客户端

import socket  
client = socket.socket()  
client.connect(("127.0.0.1", 9999)) #链接IP和端口  
while True:  
    msg = input("输入你要发送的信息>>>:")  
    if (len( msg ) == 0): continue #如果用户直接回车发送空值,那就跳过本次循环

    client.send(msg.encode("utf-8")) #向服务器发送信息  
    
    data = client.recv(1024) #接收服务器发来的信息,一次接收1K  
    print("收到服务器发来的信息:", data.decode()) #打印data  
  
client.close() #关闭客户端

猜你喜欢

转载自blog.csdn.net/UserPython/article/details/80040551