1、网络编程两个主要的问题:
1、如何准确的定位网络上一台或多台主机(IP层进行定位)
2、找到主机后如何可靠高效的进行数据传输 (TCP层进行数据传输)
2、TCP/IP协议是一个协议集合
(ethernet 以太网,也就是一般所说的拉网线所用的网络接口协议)
3、Socket编程
网络通信三件套:IP地址 端口 协议
"""打印设备名和IPv4地址"""
host_name = socket.gethostname()
print("Host name : %s" % host_name) # 对应计算机名
print(socket.gethostbyname('localhost'))
print(socket.gethostbyname_ex('localhost'))
输出:
Host name : O87VDZIU6H0596N
127.0.0.1
('O87VDZIU6H0596N', [], ['127.0.0.1'])
localhost意为本地主机,指这台计算机,是给回路网络接口的标准主机名,对应的IP地址为127.0.0.1
"""获取远程设备的IP地址"""
def get_remote_machine_info():
remote_host ='qq.com'
try:
print("IP address: %s" %socket.gethostbyname(remote_host))
print(socket.gethostbyname_ex(remote_host))
except socket.error as err_msg:
print("%s :%s"%(remote_host,err_msg))
get_remote_machine_info()
输出:
IP address: 58.250.137.36
('qq.com', [], ['58.250.137.36', '125.39.52.26', '58.247.214.47'])
"""通过指定的端口和协议找到服务名"""
def find_service_name():
protocolname = 'tcp'
for port in [80,25]:
print("Port: %s => service name: %s " %(port,socket.getservbyport(port,protocolname)))
print("Port: %s => service name: %s " % (53, socket.getservbyport(53, 'udp')))
find_service_name()
输出:
Port: 80 => service name: http
Port: 25 => service name: smtp
Port: 53 => service name: domain
"""IP地址转换"""
def convert_ipv4_address():
for ip_addr in ['127.0.0.1','192.168.0.1']:
"""inet_aton一个字符串IP地址转换为一个32位的网络序列IP地址"""
"""inet_ntoa一个32位的网络序列IP地址转换为一个字符串IP"""
packed_ip_addr = socket.inet_aton(ip_addr)
unpacked_ip_addr = socket.inet_ntoa(packed_ip_addr)
"""hexlify作用是返回的二进制数据的十六进制表示"""
print("IP address: %s => packed: %s,unpacked: %s"%(ip_addr,hexlify(packed_ip_addr),unpacked_ip_addr))
print("IP address: %s => packed: %s,unpacked: %s" % (ip_addr, packed_ip_addr, unpacked_ip_addr))
convert_ipv4_address()
输出:
IP address: 127.0.0.1 => packed: b'7f000001',unpacked: 127.0.0.1
IP address: 127.0.0.1 => packed: b'\x7f\x00\x00\x01',unpacked: 127.0.0.1
IP address: 192.168.0.1 => packed: b'c0a80001',unpacked: 192.168.0.1
IP address: 192.168.0.1 => packed: b'\xc0\xa8\x00\x01',unpacked: 192.168.0.1
"""ntp"""
def print_time():
ntp_client = ntplib.NTPClient()
response = ntp_client.request('cn.ntp.org.cn')
"""访问对象中的tx_time成员,即是server的发射时间"""
"""ctime()函数把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式"""
print(ctime(response.tx_time))
print_time()
输出:
Wed Jan 8 21:15:05 2020
"""把套接字改成阻塞或非阻塞模式"""
import socket
def test_socket_modes():
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#1 阻塞模式
#0 非阻塞模式
s.setblocking(1)
s.settimeout(0.5)
s.bind(("127.0.0.1",0)) #输入元组
socket_address = s.getsockname()
print("Server launched on socket; %s" % str(socket_address))
while(1):
s.listen(1)
test_socket_modes()
3.1 Echo Server/Client
## echo_server.py 文件 ##
import socket
import sys
host = 'localhost'
backlog = 50
def echo_server(port):
"""A simple echo server"""
# create a TCP socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#enable reuse address/port
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server_address = (host,port)
print("Starting up echo server on %s port %s" %server_address)
sock.bind(server_address)
#listen to clients, backlog argument specifies the max no. of queued connections
sock.listen(backlog)
server, address = sock.accept()
while True:
print("Waiting to receive message from client")
#client,address = sock.accept()
#server,address = sock.accept()
#data = client.recv(2048)#此处的recv是指从client接收的数据,不要被这里的client变量误导了
data = server.recv(2048)
if data:
print("Data: %s" % data)
#client.send(data)
server.send(data)
print("Send %s bytes back to %s" % (data,address))
if data == "bye":
print("echo server stop")
#break
server.close()
#client.close()
#server.close()
echo_server(9999)
## echo_client.py ##
import socket
import sys
host = 'localhost'
def echo_client(port):
"""A simple echo client"""
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_address = (host,port)
print("Conecting to %s port %s" %server_address)
sock.connect(server_address)
try:
while(True):
#message = b"bye"
message = input()
message = message.encode('utf8')#注意:这一行写到下一行里就不行,而且这样就是生成byte类型
print("Sending: %s" % message)
sock.sendall(message)
amount_received = 0
amount_expected = len(message)
while amount_received <amount_expected:
data = sock.recv(2048)
amount_received += len(data)
print("Received: %s" % data)
except socket.error as e:
print("Socket error: %s" % str(e))
except Exception as e:
print("Other exception: %s" % str(e))
finally:
print("Closing connection to the server")
sock.close()
echo_client(9999)
3.2 File Server/Client
## file_server.py ##
import socket
import sys
host = 'localhost'
backlog = 50
def file_server(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (host, port)
print("Starting up file server on %s port %s" % server_address)
sock.bind(server_address)
sock.listen(backlog)
while True:
print("Waiting to receive message from client")
server, address = sock.accept()
data = server.recv(2048)
if data:
print('receive file')
with open('data/ft_test_server.txt','w') as fp:
fp.write(data.decode('utf8'))
break
server.close()
print('server closed')
file_server(9999)
## file_client.py ##
import socket
import data_file
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_address = ('localhost',9999)
print("Conecting to %s port %s" % server_address)
sock.connect(server_address)
with open(data_file.datafile,'r') as fp:
sock.sendall(fp.read().encode('utf8'))
print('sending file')
## data_file.py ##
import os
datafile = 'data/ft_test-client.txt'
if not os.path.exists('data'):
os.mkdir('data')
with open(datafile,'w') as fp:
fp.writelines([
'Over hil,over dale,',
'Thorough bush,thorough brier,',
'Over park,over pale,',
'Thorough flood, thorough fire!'
'Over hil,over dale,',
'Thorough bush,thorough brier,',
'Over park,over pale,',
'Thorough flood, thorough fire!'
'Over hil,over dale,',
'Thorough bush,thorough brier,',
'Over park,over pale,',
'Thorough flood, thorough fire!',])
3.3 TCP server
from socketserver import TCPServer,BaseRequestHandler
class MyBaseRequestHandlerr(BaseRequestHandler):
"""
从BaseRequestHandler继承,并重写handle方法
"""
def handle(self):
while True:
try:
data = self.request.recv.strip()#strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
print("receive from (%r):%r" %(self.client_address,data))
self.request.sendall(data.upper())
if data == "y":
print('server exit')
break
except:
break
host = '0.0.0.0'
port = 9997
addr = (host,port)
server = TCPServer(addr,MyBaseRequestHandlerr)
print('server is started')
server.serve_forever()
# 在套接字服务器程序中使用 ThreadingMixIn
import os
import socket
import threading
import socketserver
SERVER_HOST = 'localhost'
SERVER_PORT = 0
BUF_SIZE = 1024
def client(ip,port,message):
"""A client to test threading mixin server"""
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ip,port))
try:
sock.sendall(message)
response = sock.recv(BUF_SIZE)
print("Client received: %s" % response)
finally:
sock.close()
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
"""A example of threaded TCP request handler"""
def handle(self):
data = self.request.recv(BUF_SIZE)
current_thread = threading.current_thread()
response = '%s : %s' %(current_thread.name,data)
self.request.send(response.encode('utf8'))
class ThreadedTCPServer(socketserver.ThreadingMixIn,socketserver.TCPServer):# 利用多继承,继承ThreadingMixIn 和 TCPServer 类
pass
def main():
server = ThreadedTCPServer((SERVER_HOST,SERVER_PORT),ThreadedTCPRequestHandler)
ip,port = server.server_address
print(ip,port,'server')
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
print('server loop runing thread : %s '% server_thread.name)
input('start client next ?')
client(ip,port,b'hello from client 1')
client(ip,port,b'hello from client 2')
client(ip,port,b'hello from client 3')
server.shutdown()
main()
# 在套接字服务器程序中使用 ForkingMixIn
import os
import socket
import threading
import socketserver
SERVER_HOST = 'localhost'
SERVER_PORT = 0
BUF_SIZE = 1024
ECHO_MSG = 'hello echo server !'
class ForkingClient():
def __int__(self,ip,port):
self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect((ip,port))
def run(self):
current_process_id = os.getpid()
print('PID %s sending echo message to the server %s'%(current_process_id,ECHO_MSG))
send_data_length = self.sock.send(ECHO_MSG.encode('utf8'))
print('Send: %d characters,so far ... '% send_data_length)
response = self.sock.recv(BUF_SIZE)
print("PID %s received: %s " %(current_process_id,response[5:]))
def shutdown(self):
self.sock.close()
class ForkingServerRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(BUF_SIZE)
current_process_id = os.getpid()
response = '%s : %s'%(current_process_id,data)
print('server sending response [current_process_id: data] = %s'% response)
self.request.send(response.encode('uft8'))
return
class ForkingServer(socketserver.ForkingMixIn,socketserver.TCPServer):
pass
def main():
server = ForkingServer((SERVER_HOST,SERVER_PORT),ForkingServerRequestHandler)
ip, port = server.server_address
print(ip, port, 'server')
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
print('server loop runing thread : %s ' % os.getpid())
client1 = ForkingClient(ip,port)
client1.run()
client2 = ForkingClient(ip,port)
client2.run()
server.shutdown()
client1.shutdown()
server.socket.close()
main()
3.4 UDP server
## UDP_server.py ##
import socket
address = ('127.0.0.1',31500)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind(address)
while True:
data,addr = s.recvfrom(2048)
if not data:
print('client has exist')
break
if data:
if data == 'exit':
print(' exiting server')
break
s.close()
## UDP_client.py ##
import socket
address = ('127.0.0.1',31500)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg = input('message to send:')
if not msg:
break
s.sendto(msg.encode('utf8'),address)
if msg == 'exit':
print('client exit')
break
s.close()