socket
socket.gethostbyname(hostname)
socket.gethostbyaddr(addr)
socket.getservbyname(name) 查询端口号(如name=’www’, 返回80)
socket.getserbyport(80) 返回’www’
127...* 是本地ip
10...* 172.16-31.. 192.168.. 为私有子网所预留。
子网掩码255.255.255.0 可以表述为***.***.***.***/24 (***=11111111,8位)
tcp
sock = socket.socket(xxx…) (参数参考https://www.cnblogs.com/wumingxiaoyao/p/7047658.html)( 一般要写SO_REUSERADDR以防同一端口最近关闭的连接还未关闭导致错误,因为关闭后会有CLOSE-WAIT和TIME-WAIT 状态)
sock.accept() 会创建一个连接套接字 (对应客户端发送的sock.connect())
sock.listen() 会创建一个监听套接字
sock.sendall() 实现了完整数据块传输,recvall需要自己写
sock.getsockname()
sock.bind(interface,port) interface取””空字符串表示接受任意网络接口的请求(0.0.0.0表示接受任意,py简化了)
sock.shutdown(xxx) 半开连接的操作
sock.makefile() 直接进行文件读写
tcp客户端服务端
#!/usr/bin/env python3
import argparse, socket
def recvall(sock, length):
data = b''
while len(data) < length:
more = sock.recv(length - len(data))
if not more:
raise EOFError('was expecting %d bytes but only received'
' %d bytes before the socket closed'
% (length, len(data)))
data += more
return data
def server(interface, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((interface, port))
sock.listen(1)
print('Listening at', sock.getsockname())
while True:
print('Waiting to accept a new connection')
sc, sockname = sock.accept()
print('We have accepted a connection from', sockname)
print(' Socket name:', sc.getsockname())
print(' Socket peer:', sc.getpeername())
message = recvall(sc, 16)
print(' Incoming sixteen-octet message:', repr(message))
sc.sendall(b'Farewell, client')
sc.close()
print(' Reply sent, socket closed')
def client(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
print('Client has been assigned socket name', sock.getsockname())
sock.sendall(b'Hi there, server')
reply = recvall(sock, 16)
print('The server said', repr(reply))
sock.close()
if __name__ == '__main__':
choices = {'client': client, 'server': server}
parser = argparse.ArgumentParser(description='Send and receive over TCP')
parser.add_argument('role', choices=choices, help='which role to play')
parser.add_argument('host', help='interface the server listens at;'
' host the client sends to')
parser.add_argument('-p', metavar='PORT', type=int, default=1060,
help='TCP port (default 1060)')
args = parser.parse_args()
function = choices[args.role]
function(args.host, args.p)
DNS
socket.getaddrinfo
socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]]) 可解析得到IPv6地址。 返回创建一个套接字并发起连接所需的所有信息,返回的元组(family, socktype, proto, canonname, sockaddr)依次为:地址族、类型、协议代号、规范名、地址信息。用前三项作为socket构造参数,第五项为传入地址,可构造出一个连接connect()
flag:AI_V4MAPPED:返回IPv4映射到IPv6格式的IPv6地址.(http://www.ip2location.com/articles/ip2location-ipv4-mapped-ipv6-address)
- bind:为服务器绑定端口。 将host取None,返回合适的通配符地址,可用于bind。
- connect/sendto:连接。设置AI_ADDRCONFIG标记,讲所有无法连接的地址过滤掉。
使用getaddrinfo
#!/usr/bin/env python3
# Foundations of Python Network Programming, Third Edition
# https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter04/www_ping.py
# Find the WWW service of an arbitrary host using getaddrinfo().
import argparse, socket, sys
def connect_to(hostname_or_ip):
try:
infolist = socket.getaddrinfo(
hostname_or_ip, 'www', 0, socket.SOCK_STREAM, 0,
socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME,
)
except socket.gaierror as e:
print('Name service failure:', e.args[1])
sys.exit(1)
info = infolist[0] # per standard recommendation, try the first one
socket_args = info[0:3]
address = info[4]
s = socket.socket(*socket_args)
try:
s.connect(address)
except socket.error as e:
print('Network failure:', e.args[1])
else:
print('Success: host', info[3], 'is listening on port 80')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Try connecting to port 80')
parser.add_argument('hostname', help='hostname that you want to contact')
connect_to(parser.parse_args().hostname)
dns.resolver() 可进行DNS查询(https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter04/dns_mx.py)