Python通过socket实现在线聊天功能—初级版
服务器端
导入模块
import socket as sk
检索自身IP地址
通过socket实现聊天功能,需要知道相互的套接字地址(由IP地址与端口号组成)。
通过服务器检索自身套接字地址后打印(print)套接字地址或是通过SMTP模块将地址发送到指定邮箱,方便客户端连接。
通用版本
import socket as sk
# 获取服务端的主机名
hostname = sk.gethostname()
# 通过主机名获得IP地址
IP = sk.gethostbyname(hostname)
注:
若服务器端存在虚拟机,则获取到的IP将是虚拟机虚拟化的网卡(即虚拟网卡)使用的虚拟IP。
ipconfig
print(IP)
在上述的特殊情况下,print(IP)的结果将与VMnet8的IP地址相同,而不是主机的IP地址。
虚拟机版本
# 创建IP查找器,查找本机IP
finder = sk.socket(sk.AF_INET, sk.SOCK_DGRAM)
# 基于UDP协议连接公共DNS服务器 8.8.8.8 的80端口(默认为HTTP端口)
finder.connect(('8.8.8.8', 80))
# 获取本机IP地址
HOST = finder.getsockname()[0]
注:
- 使用该方法由于采用的是UDP协议,所以并不会连接到公共DNS服务器,但会向主机请求端口,会多出一些资源开销,在必要情况下,可以考虑保存本机IP。
- sk.socket的第一个参数指定使用IP协议,而第二个参数则指定采用UDP协议。
常用的公共的DNS服务器
国外DNS服务器地址
服务 | IP地址 |
---|---|
Google Public DNS | (8.8.8.8, 8.8.4.4) |
Google Public DNS | (8.8.8.8, 8.8.4.4) |
OpenDNS | (208.67.222.222, 208.67.220.220) |
OpenDNS Family | (208.67.222.123, 208.67.220.123) |
V2EX DNS | (199.91.73.222, 178.79.131.110) |
Dyn DNS | (216.146.35.35, 216.146.36.36) |
Comodo Secure | (8.26.56.26, 8.20.247.20) |
UltraDNS | (156.154.70.1, 156.154.71.1) |
Norton ConnectSafe | (199.85.126.10, 199.85.127.10) |
国内DNS服务器地址
服务 | IP地址 |
---|---|
OneDNS | (112.124.47.27) |
OpenerDNS | (42.120.21.30) |
aliDNS | (223.5.5.5, 223.6.6.6) |
114DNS | (114.114.114.114, 114.114.115.115) |
114DNS安全版 | (114.114.114.119, 114.114.115.119) |
114DNS家庭版 | (114.114.114.110, 114.114.115.110) |
创建基于TCP协议的服务器
# 设置服务器监听的端口号
PORT = 3600
# 创建基于TCP协议的服务器
server = sk.socket(sk.AF_INET, sk.SOCK_STREAM)
# 设置服务器绑定的主机地址及端口号
server.bind((HOST, PORT))
# 开始监听(设置参数,使得允许最大排队个数为五)
server.listen(5)
# 打印服务器运行的地址及端口
print(f'server is running at {HOST}:{PORT}')
注:
sk.socket的第一个参数指定使用IP协议,而第二个参数则指定采用TCP协议。
建立连接
# 与发出连接邀请的客户端建立连接
# 返回值类型为一元组,第一个元素为socket.socket对象,
# 第二个元素为客户端的地址,包含IP地址及端口号的元组
conn, address = server.accept()
# 向客户端发送连接成功的提示信息
tip = f'The server has received a connection from {address[0]}:{address[1]}'
print(tip)
conn.send(tip.encode())
在Socket对象中有两个用于发送信息(基于TCP连接)的方法,分别是send()与sendall()。
区别是:
- send()方法返回发送的字节大小,字节大小可能会小于实际要发送的数据大小,也就是说,该函数执行一次(由网络不良等引起的异常导致)可能不能将数据完整交付给目标。
- sendall()方法在成功将数据完整交付给对方时返回None,否则将抛出异常。
聊天功能
try:
while True:
# recv方法的参数为必填项,指定接受信息的最大字节数
# 由于发送过来的数据为二进制,所以需要对数据进行解码。
message = conn.recv(1024).decode()
if message:
print(message)
# 由于input函数是阻塞式的,所以信息只能轮流发送
# 若想不受input函数的限制,想发就发,可以考虑使用多线程(若有更好的方式,还请多多指教)
think = input()
if think:
# 发送信息需要对其进行编码
conn.send(f'【server】 {think}'.encode())
except ConnectionResetError:
# 在客户端连接到服务器,若客户端发送一条或多条信息并断开连接,那么当服务器发送信息时(断开连接后)将触发该错误。
print('The connection has been disconnected')
代码总汇
# 导入模块
import socket as sk
# 创建IP查找器,查找本机IP
finder = sk.socket(sk.AF_INET, sk.SOCK_DGRAM)
# 基于UDP协议连接公共DNS服务器 8.8.8.8 的80端口(默认为HTTP端口)
finder.connect(('8.8.8.8', 80))
# 获取本机IP地址
HOST = finder.getsockname()[0]
# 设置服务器监听的端口号
PORT = 3600
# 创建基于TCP协议的服务器
server = sk.socket(sk.AF_INET, sk.SOCK_STREAM)
# 设置服务器绑定的主机地址及端口号
server.bind((HOST, PORT))
# 开始监听(设置参数,使得允许最大排队个数为五)
server.listen(5)
# 打印服务器运行的地址及端口
print(f'server is running at {HOST}:{PORT}')
# 与发出连接邀请的客户端建立连接
# 返回值类型为一元组,第一个元素为socket.socket对象,
# 第二个元素为客户端的地址,包含IP地址及端口号的元组
conn, address = server.accept()
# 向客户端发送连接成功的提示信息
tip = f'The server has received a connection from {address[0]}:{address[1]}'
print(tip)
conn.send(tip.encode())
try:
while True:
# recv方法的参数为必填项,指定接受信息的最大字节数
# 由于发送过来的数据为二进制,所以需要对数据进行解码。
message = conn.recv(1024).decode()
if message:
print(message)
# 由于input函数是阻塞式的,所以信息只能轮流发送
# 若想不受input函数的限制,想发就发,可以考虑使用多线程(若有更好的方式,还请多多指教)
think = input()
if think:
# 发送信息需要对其进行编码
conn.send(f'【server】 {think}'.encode())
except ConnectionResetError:
# 在客户端连接到服务器,若客户端发送一条或多条信息并断开连接,那么当服务器发送信息时(断开连接后)将触发该错误。
print('The connection has been disconnected')
客户端
# 导入模块
import socket as sk
创建基于TCP协议的客户端
# 服务器信息
HOST = '172.26.36.25'
PORT = 3600
# 创建基于TCP协议的客户端
client = sk.socket(sk.AF_INET, sk.SOCK_STREAM)
# 开始连接服务器
client.connect((HOST, PORT))
聊天功能
while True:
# 对接受到的信息进行解码
message = client.recv(1024).decode()
# 如果有信息则将其打印
if message:
print(message)
think = input()
client.send(f'【client】{think}'.encode())
代码总汇
# 导入模块
import socket as sk
# 服务器信息
HOST = '172.26.36.25'
PORT = 3600
# 创建基于TCP协议的客户端
client = sk.socket(sk.AF_INET, sk.SOCK_STREAM)
# 开始连接服务器
client.connect((HOST, PORT))
while True:
# 对接受到的信息进行解码
message = client.recv(1024).decode()
# 如果有信息则将其打印
if message:
print(message)
think = input()
client.send(f'【client】{think}'.encode())
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84064.html