Python社区  »  Python

董付国PYTHON视频大讲堂

图灵人工智能 • 3 月前 • 90 次点击  

点击上方“图灵人工智能”,选择“星标”公众号

您想知道的人工智能干货,第一时间送达

                         

视频内容选自如上图书:


视频内容:编写程序,获取本机所在局域网内所有机器的IP地址与网卡的MAC地址。使用操作系统命令arp获取本地缓存的ARP表并生成文本文件,然后再从文件中读取和解析局域网内IPMAC地址的对应关系。

示例代码如下:

import os

from socket import gethostbyname_ex,gethostname

 

# 获取本机所有IP地址列表

hosts =gethostbyname_ex(gethostname())[-1]

# 获取ARP表,写入文本文件

os.system('arp -a > temp.txt')

# 读取和解析ARP表中的信息

with open('temp.txt') as fp:

   for line in fp:

       line = line.split()[:2]

       if not line:

            continue

       for host in hosts:

            ifline[0].startswith(host.rsplit('.',1)[0]) and\

               (not line[0].endswith('255')):

                print(':'.join(line))

代码生成的包含ARP表的临时文件temp.txt内容格式如图3-2所示,如果需要的话可以在程序最后增加一行代码调用os.remove()函数删除临时文件temp.txt,请自行修改和测试。


3-2  代码生成的本地ARP


视频内容:编写TCP通信程序模拟机器人自动聊天软件,服务端提前建立好字典,然后根据接收到的内容查询字典并自动回复。

示例代码如下:

1)服务端代码(单客户端版本)

import socket

from sys import exit

from struct import pack, unpack

from os.path import commonprefix

 

# 缓冲区大小,或者说一次能够接收的最大字节串长度

BUFFER_SIZE = 9012

 

words = {'how are you?':'Fine,thankyou.',

 'how old are you?':'38',

  'what is your name?':'Dong FuGuo',

"what's your name?":'DongFuGuo',

 'where do you work?':'University',

 'bye':'Bye'}

 

# 空字符串表示本地所有IP地址

# 如果需要绑定到本地特定的IP地址,可以明确指定,例如'192.168.9.1'

HOST = ''

PORT = 50007

# 创建TCP套接字,绑定socket地址

sock_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sock_server.bind((HOST, PORT))

# 声明自己为服务端套接字,开始监听,准备接收一个客户端连接

sock_server.listen(1)

print('Listening on port:',PORT)

 

# 阻塞,成功接收一个客户端连接请求之后返回新的套接字和对方地址

try:

   conn, addr = sock_server.accept()

except:

   # 接收客户端连接失败,服务器故障,直接退出

   exit()

 

print('Connected by', addr)

# 开始聊天,使用新套接字收发信息

while True:

   # 接收一个整数打包后的字节串,表示对方本次发送的实际字节串长度

   int_bytes = b''

   # struct序列化规则中,整数被打包为长度为4的字节串

   rest = 4

   # 在高并发网络服务器中,无法保证能够一次接收完4个字节,使用循环更可靠

   # 使用TCP协议通信时,必须保证接收方恰好收完发送方的数据,不能多,也不能少

   while rest > 0:

       # 接收数据时自动分配缓冲区

       temp = conn.recv(rest)

       # 收到空字节串,表示对方套接字已关闭

       if not temp:

            break

       int_bytes = int_bytes + temp

       rest = rest - len(temp)

   # 前面的while循环没有接收到数据或者没有收够4个字节

   # 表示对方已结束通信或者网络故障

   if rest > 0:

       break

 

   # rest表示接下来需要接收的字节串长度,unpack()的结果是一个元组

   rest = unpack('i', int_bytes)[0]

   data = b''

   while rest > 0:

       # 要接收的字节串长度可能非常大,限制一次最多接收BUFFER_SIZE个字节

       temp = conn.recv(min(rest,BUFFER_SIZE))

       data = data + temp

       rest = rest - len(temp)

   # 接收数据不完整,套接字可能损坏

   if rest > 0:

       break

 

   # 删除字符串中可能存在的连续多个空格

   data = ' '.join(data.decode().split())

   print('Received message:', data)

   # 尽量猜测对方要表达的真正意思

   m = 0

   key = ''

   for k in words.keys():

       # 与某个有超过70%的共同前缀,认为对方就是想问这个问题

       if len(commonprefix([k, data])) > len(k)*0.7:

            key = k

            break

       # 使用选择法,选择一个重合度较高(也就是共同单词最多)的

       length = len(set(data.split())&set(k.split()))

       if length > m:

            m = length

            key = k

   # 选择合适的信息进行回复

   reply = words.get(key, 'Sorry.').encode()

   # 发送数据时自动确定缓冲区长度

   conn.sendall(pack('i', len(reply))+reply)

 

conn.close()

sock_server.close()

 

2)客户端代码

import socket

from sys import exit

from struct import pack, unpack

 

# 服务端主机IP地址和端口号

# 如果服务端和客户端不在同一台计算机,需要自己修改变量HOST的值

HOST = '127.0.0.1'

PORT = 50007

 

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 设置超时时间,避免服务器不存在时客户端长时间等待或GUI界面无响应

sock.settimeout(0.3)

try:

   # 连接服务器,成功后设置当前套接字为阻塞模式

   sock.connect((HOST, PORT))

   sock.settimeout(None)

except Exception as e:

   print('Server not found or not open')

   exit()

 

while True:

   msg = input('Input the content you want to send:').encode()

   # 发送数据

   sock.sendall(pack('i', len(msg))+msg)

   # 从服务端接收数据

   # 客户端的实现可以比服务端简单一些,不需要循环接收来保证数据完整

   length = unpack('i', sock.recv(4))[0]

   data = sock.recv(length).decode()

   print('Received:', data)

   if msg.lower() == b'bye':

       break

# 关闭连接

sock.close()

打开一个命令提示符窗口运行服务端程序,再打开一个命令提示符窗口运行客户端程序,运行效果如图3-5所示。

3-5  机器人聊天程序运行效果

上面的程序中,服务端在同一时刻只能接收和回复一个客户端的聊天信息,如果想让服务端能够同时和多个客户端聊天,需要结合第2章的多线程编程技术,为每个客户端创建一个单独的线程为其服务。服务端代码改写如下,客户端代码不需要修改,请自行运行程序观察运行结果。

3)服务端代码(多客户端版本)

import socket

from threading import Thread

from struct import pack, unpack

from os.path import commonprefix

 

BUFFER_SIZE = 9012

 

def every_client(conn, addr):

   # 开始聊天

   while True:

       # 接收一个整数的字节串,表示对方本次发送的实际字节串长度

       int_bytes = b''

       rest = 4

       # 在高并发网络中,无法保证能够一次接收完4个字节,使用循环更可靠

       while rest > 0:

            temp = conn.recv(rest)

            # 收到空字节串,表示对方套接字已关闭

            if not temp:

                break

            int_bytes = int_bytes + temp

            rest = rest - len(temp)

       # 前面的while循环没有接收到数据或者没有收够4个字节

       # 表示对方已结束通信或者网络故障

       if rest > 0:

            break

 

       # rest表示接下来需要接收的字节串长度,unpack()的结果是一个元组

       rest = unpack('i', int_bytes)[0]

       data = b''

       while rest > 0:

            # 要接收的字节串可能非常长,限制一次最多接收BUFFER_SIZE个字节

            temp = conn.recv(min(rest,BUFFER_SIZE))

            data = data + temp

            rest = rest - len(temp)

       # 接收数据不完整,套接字可能损坏

       if rest > 0:

            break

 

       # 删除字符串中可能存在的连续多个空格

       data = ' '.join(data.decode().split())

       print('Received message:', data)

       # 尽量猜测对方要表达的真正意思

       m = 0

       key = ''

       for k in words.keys():

            # 与某个有超过70%的共同前缀,认为对方就是想问这个问题

            if len(commonprefix([k, data]))> len(k)*0.7:

                key = k

                break

            # 使用选择法,选择一个重合度较高的

            length = len(set(data.split())&set(k.split()))

            if length > m:

                m = length

                key = k

       # 选择合适的信息进行回复

       reply = words.get(key, 'Sorry.').encode()

       conn.sendall(pack('i', len(reply))+reply)

 

   conn.close()

   print(f'Client {addr} has left.')

 

words = {'how are you?':'Fine,thankyou.',

  'how old are you?':'38',

  'what is your name?':'Dong FuGuo',

"what's your name?":'DongFuGuo',

 'where do you work?':'University',

 'bye':'Bye'}

 

HOST = ''

PORT = 50007

sock_server =socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定socket

sock_server.bind((HOST, PORT))

# 开始监听套接字,准备接收客户端连接,最多可以同时和50个客户端通信

sock_server.listen(50)

print('Listening on port:', PORT)

while True:

   try:

       conn, addr = sock_server.accept()

   except:

       break

   print('Connected by', addr)

   # 为每个客户端连接创建单独的线程为其服务

   Thread(target=every_client, args=(conn,addr)).start()

 

sock_server.close()

董付国,山东省一流本科课程“Python应用开发”负责人,山东省高等教育优秀教材《Python程序设计基础(第2版)》作者,清华大学出版社3本畅销教材作者,华为技术有限公司独立顾问,阿里云天池等多个平台合作伙伴,全国高等院校计算机基础教育研究会“教育信息化”专业委员会委员,机械工业出版社计算机分社成立20周年本科教材“金牌作者”。出版的Python系列教材被国内超过800所高校选用,国家图书馆和各省市图书馆以及学校图书馆馆藏,累计印刷超过120次。


往期精彩必读文章(单击就可查看):

1.谷歌突然宣布:上帝的密码防线逐渐崩溃!人工智能有可能是人类文明史的终结!

2.人工智能的现状与未来

3. 国防科技大学教授:殷建平——计算机科学理论的过去、现在与未来

4.图灵奖得主Hamming的22年前经典演讲:如何做研究,才能不被历史遗忘

5.当这位70岁的Hinton老人还在努力推翻自己积累了30年的学术成果时,我才知道什么叫做生命力(附Capsule最全解析)

6.科学正在证明,科学并不科学

7. 沉痛!中国半导体 ”芯酸“史!

8.数学的深

9. 计算的极限(续)

10.计算的极限

11.高考大数据:哪个省才是高考地狱模式?结论和想象不太一样

12.老婆离家三周,我写了一个操作系统!


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/118170
 
90 次点击  
分享到微博