Python通过socket实现在线聊天功能—初级版

导读:本篇文章讲解 Python通过socket实现在线聊天功能—初级版,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

服务器端

导入模块

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]

注:

  1. 使用该方法由于采用的是UDP协议,所以并不会连接到公共DNS服务器,但会向主机请求端口,会多出一些资源开销,在必要情况下,可以考虑保存本机IP。
  2. 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()。
区别是:

  1. send()方法返回发送的字节大小,字节大小可能会小于实际要发送的数据大小,也就是说,该函数执行一次(由网络不良等引起的异常导致)可能不能将数据完整交付给目标。
  2. 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

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!