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]

注:

  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())
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinaryMoon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值