您的位置:首页 > 编程语言 > Python开发

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

2017-03-18 22:28 344 查看
#!/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网络编程攻略》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: