Search K
Appearance
Appearance
首先,我们要了解TCP是什么? TCP(传输控制协议,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它在互联网协议族(Internet Protocol Suite)中属于传输层,与IP协议(Internet Protocol)共同构成了网络通信的基础,通常被合称为TCP/IP协议。 以下是TCP协议的主要特点:
TCP协议广泛应用于各种需要高可靠性的应用场景,如网页浏览(HTTP)、文件传输(FTP)、电子邮件(SMTP)等。由于它的可靠性,TCP比UDP(用户数据报协议,User Datagram Protocol)等其他传输层协议在数据传输上更为可靠,但通常也会有更高的传输延迟。
我们可以通过TCP网络传输协议来搭建一个简单的网络聊天工具。
要知道我们需要使用什么库:
需要用到的库非常简单和少量:
仅此而已。
首先,我们要搞清楚编写代码的步骤
选择是客户端还是服务端
选择相应的端可以使用相应的功能服务
import socket
import threading
# 初始化全局变量
clients = []
nicknames = []
server = None
# 发送消息给所有连接的客户端
def broadcast(message):
for client in clients:
try:
client.send(message)
except Exception as e:
print(f"无法发送消息至客户端: {e}")
clients.remove(client)
client.close()
# 处理每个客户端的线程
def handle_client(client):
while True:
try:
# 接收消息
message = client.recv(1024)
if message:
message_decoded = message.decode('utf-8')
print(f"{message_decoded}") # Debug print
broadcast(message)
else:
# No data means disconnected
break
except Exception as e:
print(f"An error occurred: {e}")
break
# 客户端断开连接
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast(f'{nickname} 离开了聊天室'.encode('utf-8'))
nicknames.remove(nickname)
# 接受客户端连接的函数
def receive_connections(HOST, PORT):
global server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
print(f"服务器正运行在: {HOST}:{PORT}")
while True:
client, address = server.accept()
print(f"来自 {str(address)} 的连接")
# 请求并存储昵称
client.send('NICK'.encode('utf-8'))
nickname = client.recv(1024).decode('utf-8')
nicknames.append(nickname)
clients.append(client)
# 广播新客户端的加入
print(f"{nickname} 进入了聊天室")
broadcast(f"{nickname} 进入了聊天室".encode('utf-8'))
client.send('连接成功!'.encode('utf-8'))
# 开启新线程处理客户端
thread = threading.Thread(target=handle_client, args=(client,))
thread.start()
# 服务器管理员发送消息的函数
def admin_message_sender():
while True:
message = input()
if message.lower() == 'quit':
# 关闭所有客户端连接
for client in clients:
client.close()
# 关闭服务器
global server
server.close()
print("关闭服务器中...")
break
broadcast(f"Server: {message}".encode('utf-8'))
def start_server(HOST, PORT):
# 启动服务器监听线程
server_thread = threading.Thread(target=receive_connections, args=(HOST, PORT))
server_thread.start()
# 启动服务器管理员消息发送线程
admin_thread = threading.Thread(target=admin_message_sender)
admin_thread.start()
# 等待线程结束
server_thread.join()
admin_thread.join()
import socket
import threading
def login_chat_server(HOST,PORT):
# 服务器的IP地址和端口
# HOST = '127.0.0.1'
# PORT = 65432
# 创建socket对象
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client.connect((HOST, PORT))
# 输入昵称并发送给服务器
nickname = input("请输入你的名字: ")
client.send(nickname.encode('utf-8'))
# 接收欢迎消息
message = client.recv(1024)
print(message.decode('utf-8'))
# 开启新线程用于持续接收消息
def receive():
while True:
try:
# 接收消息
message = client.recv(1024)
print(message.decode('utf-8'))
except:
# 出现连接问题
print("连接失败!检查网络问题或请联系房主解决")
client.close()
break
# 开启线程
thread = threading.Thread(target=receive)
thread.start()
# 发送消息
while True:
message = f'{nickname}: {input("")}'
client.send(message.encode('utf-8'))
import server
import client
while True:
mode = input('开启服务器/加入服务器?>>')
if mode == '开启服务器' or mode == '开启':
server.start_server(input('输入ip>>'),int(input('输入端口号>>')))
break
if mode == '加入服务器' or mode == '加入':
client.login_chat_server(input('输入ip>>'),int(input('输入端口号>>')))
break
else:
print("输入错误!请重新输入")
continue
在分段代码中将server.py与client.py当作了模块在主程序main.py中运行,所以我们可以看到主程序main.py代码十分的简洁短小
代码过长的时候为避免在修补BUG检查的时候眼花缭乱会把一段代码拆分成几段程序以import导入的方式连接在一起
不信的可以看下面的连接代码
import socket
import threading
# 初始化全局变量
clients = []
nicknames = []
server = None
# 发送消息给所有连接的客户端
def broadcast(message):
for client in clients:
try:
client.send(message)
except Exception as e:
print(f"无法发送消息至客户端: {e}")
clients.remove(client)
client.close()
# 处理每个客户端的线程
def handle_client(client):
while True:
try:
# 接收消息
message = client.recv(1024)
if message:
message_decoded = message.decode('utf-8')
print(f"{message_decoded}") # Debug print
broadcast(message)
else:
# No data means disconnected
break
except Exception as e:
print(f"An error occurred: {e}")
break
# 客户端断开连接
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast(f'{nickname} 离开了聊天室'.encode('utf-8'))
nicknames.remove(nickname)
# 接受客户端连接的函数
def receive_connections(HOST, PORT):
global server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
print(f"服务器正运行在: {HOST}:{PORT}")
while True:
client, address = server.accept()
print(f"来自 {str(address)} 的连接")
# 请求并存储昵称
client.send('NICK'.encode('utf-8'))
nickname = client.recv(1024).decode('utf-8')
nicknames.append(nickname)
clients.append(client)
# 广播新客户端的加入
print(f"{nickname} 进入了聊天室")
broadcast(f"{nickname} 进入了聊天室".encode('utf-8'))
client.send('连接成功!'.encode('utf-8'))
# 开启新线程处理客户端
thread = threading.Thread(target=handle_client, args=(client,))
thread.start()
# 服务器管理员发送消息的函数
def admin_message_sender():
while True:
message = input()
if message.lower() == 'quit':
# 关闭所有客户端连接
for client in clients:
client.close()
# 关闭服务器
global server
server.close()
print("关闭服务器中...")
break
broadcast(f"Server: {message}".encode('utf-8'))
def start_server(HOST, PORT):
# 启动服务器监听线程
server_thread = threading.Thread(target=receive_connections, args=(HOST, PORT))
server_thread.start()
# 启动服务器管理员消息发送线程
admin_thread = threading.Thread(target=admin_message_sender)
admin_thread.start()
# 等待线程结束
server_thread.join()
admin_thread.join()
import socket
import threading
def login_chat_server(HOST,PORT):
# 服务器的IP地址和端口
# HOST = '127.0.0.1'
# PORT = 65432
# 创建socket对象
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client.connect((HOST, PORT))
# 输入昵称并发送给服务器
nickname = input("请输入你的名字: ")
client.send(nickname.encode('utf-8'))
# 接收欢迎消息
message = client.recv(1024)
print(message.decode('utf-8'))
# 开启新线程用于持续接收消息
def receive():
while True:
try:
# 接收消息
message = client.recv(1024)
print(message.decode('utf-8'))
except:
# 出现连接问题
print("连接失败!检查网络问题或请联系房主解决")
client.close()
break
# 开启线程
thread = threading.Thread(target=receive)
thread.start()
# 发送消息
while True:
message = f'{nickname}: {input("")}'
client.send(message.encode('utf-8'))
while True:
mode = input('开启服务器/加入服务器?>>')
if mode == '开启服务器' or mode == '开启':
start_server(input('输入ip>>'),int(input('输入端口号>>')))
break
if mode == '加入服务器' or mode == '加入':
login_chat_server(input('输入ip>>'),int(input('输入端口号>>')))
break
else:
print("输入错误!请重新输入")
continue
见识到了连接代码的恐怖后相信大家都会选择分段代码
但是要注意的是分段代码是由不同的文件组成
并且文件要在同目录下,否则程序会检测不到模块
另外,服务器ip并不是瞎填的
在CMD中写ipconfig
查看电脑的ip地址,如果程序无法在该ip上创建服务器的话就会报错
在开启服务器后还需要公网才能与远在他乡的好友聊天,没有公网只能与家里共用一个网络的人使用
在这段代码中可以不限人数的聊天