基于TCP完成一个在线聊天程序,主要功能是实现客户端和服务器的双向通信
创建TCP Socket
s=socket.socket(scoket.AF_INET,scoket.SOCK_STREAM)
创建UDP Socket
s=socket.socket(scoket.AF_INET,scoket.SOCK_DGRAM)
面向连接TCP的时序图
socket对象的函数
TCP Socket服务器示例
# -*- coding:utf-8 -*-
import socket
host='127.0.0.1'
port=8888
web=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
web.bind((host,port))
web.listen(10)
print('服务器等待客户端连接......')
conn,addr=web.accept()
data=conn.recv(1024).decode()
#开启循环
while True:
while data != 'bye':
if data:
print('接收到:',data)
send_data=input('发送:')
conn.send(send_data.encode())
if send_data == 'bye':
break
data=conn.recv(1024).decode()
conn.close()
web.close()
TCP Socket客户端示例
import socket
client =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host='127.0.0.1'
port=8888
client.connect((host,port))
print(socket.gethostname(),'已连接!')
info=''
while info !='bye':
send_data=input('发送内容:')
client.send(send_data.encode())
if send_data == 'bye':
break
#接收对方发过来的数据,最大接收1024字节
info=client.recv(1024).decode()
print('数据内容:',info)
client.close()
实现服务器和客户端双向通信
基于tkinter的在线聊天
服务端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: 人海中的海盗
# 在线聊天服务器
import tkinter
import tkinter.font as tkFont
from socket import *
import threading, time, sys
global serverSock
class ServerUI:
local = '0.0.0.0'
port = 9999
flag = False
connection = None
def __init__(self):
# 初始化相关属性
self.clientMsg = None
self.root = tkinter.Tk()
self.root.title('Python服务器-在线聊天')
# 窗口 4个frame面板布局
self.frame = [tkinter.Frame(), tkinter.Frame(), tkinter.Frame(), tkinter.Frame()]
# 显示消息的滚动条
self.chatTextScrollBar = tkinter.Scrollbar(self.frame[0])
self.chatTextScrollBar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
# 显示Text,绑定滚动条
ft = tkFont.Font(family='Fixdsys', size=11)
self.chatText = tkinter.Listbox(self.frame[0], width=70, height=18, font=ft)
self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
self.chatText.pack(expand=1, fill=tkinter.BOTH)
self.chatTextScrollBar['command'] = self.chatText.yview()
self.frame[0].pack(expand=1, fill=tkinter.BOTH)
# 分开消息显示和消息输入
label = tkinter.Label(self.frame[1], height=2)
label.pack(fill=tkinter.BOTH)
self.frame[1].pack(expand=1, fill=tkinter.BOTH)
# 输入消息的滚动条
self.inputTextScrollBar = tkinter.Scrollbar(self.frame[2])
self.inputTextScrollBar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
ft = tkFont.Font(family='Fixdsys', size=11)
self.inputText = tkinter.Text(self.frame[2], width=70, height=8, font=ft)
self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
self.inputText.pack(expand=1, fill=tkinter.BOTH)
self.inputTextScrollBar['command'] = self.chatText.yview()
self.frame[2].pack(expand=1, fill=tkinter.BOTH)
# 发送按钮
self.sendButton = tkinter.Button(self.frame[3], text='发送', width=10, command=self.sendMessage)
self.sendButton.pack(expand=1, side=tkinter.BOTTOM and tkinter.RIGHT, padx=25, pady=5)
# 关闭按钮
self.closeButton = tkinter.Button(self.frame[3], text='关闭', width=10, command=self.close)
self.closeButton.pack(expand=1, side=tkinter.RIGHT, padx=25, pady=5)
self.frame[3].pack(expand=1, fill=tkinter.BOTH)
def close(self):
self.root.destroy()
def receiveMessage(self):
try:
# 建立Socket连接
self.serverSock = socket(AF_INET, SOCK_STREAM)
self.serverSock.bind((self.local, self.port))
self.serverSock.listen(15)
self.buffer = 1024
self.chatText.insert(tkinter.END, '服务器已连接\n')
self.flag = False
self.accept_thread = threading.Thread(target=self.accept_connections)
self.accept_thread.start()
except Exception as e:
self.chatText.insert(tkinter.END, f'服务器发生异常:{str(e)}\n')
return # 异常发生时结束函数执行
def startNewThead(self):
thread = threading.Thread(target=self.receiveMessage(), args=(), daemon=True)
thread.start()
def accept_connections(self):
self.serverSock.listen(5)
while True:
try:
self.connection, self.address = self.serverSock.accept()
self.flag = True
client_thread = threading.Thread(target=self.handle_client, args=(self.connection, self.address))
client_thread.start()
except Exception as e:
print(f"Exception in accept_connections: {e}")
break
def handle_client(self, connection, address):
while True:
try:
clientMsg = connection.recv(self.buffer).decode()
print(clientMsg)
if not clientMsg:
continue
elif clientMsg == 'Y':
connection.send(b'Y')
self.update_chat("客户端连接成功")
elif clientMsg == 'N':
connection.send(b'N')
self.update_chat("客户端已断开连接")
else:
self.update_chat(f"客户端说: {clientMsg}")
except Exception as e:
self.update_chat(f"Exception: {e}")
break
def sendMessage(self):
message = self.inputText.get('1.0', tkinter.END)
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(tkinter.END, '服务器 ' + theTime + ' 说:'+ message + '\n')
if self.flag:
self.connection.send(message.encode()) # 发送到客户端
else:
self.chatText.insert(tkinter.END, '未与客户端建立连接\n')
self.inputText.delete(0.0, message.__len__() - 1.0)
def update_chat(self, message):
self.chatText.insert(tkinter.END, message + "\n")
self.chatText.see(tkinter.END)
def main():
server = ServerUI()
server.startNewThead()
server.root.mainloop()
if __name__ == '__main__':
main()
客户端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: 人海中的海盗
# 在线聊天客户端
import tkinter
import tkinter.font as tkFont
from socket import *
import threading, time, sys
global clientSock
class ClientUI:
local = '127.0.0.1'
port = 9999
flag = False
# 初始化类的相关属性的构造函数
def __init__(self):
self.buffer = None
self.clientSock = None
self.serverMsg = None
self.root = tkinter.Tk()
self.root.title('Python客户端-在线聊天')
# 窗口 4个frame面板布局
self.frame = [tkinter.Frame(), tkinter.Frame(), tkinter.Frame(), tkinter.Frame()]
# 滚动条
self.chatTextScrollBar = tkinter.Scrollbar(self.frame[0])
self.chatTextScrollBar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
# 显示Text,绑定滚动条
ft = tkFont.Font(family='Fixdsys', size=11)
self.chatText = tkinter.Listbox(self.frame[0], width=70, height=18, font=ft)
self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
self.chatText.pack(expand=1, fill=tkinter.BOTH)
self.chatTextScrollBar['command'] = self.chatText.yview()
self.frame[0].pack(expand=1, fill=tkinter.BOTH)
# 分开消息显示和消息输入
label = tkinter.Label(self.frame[1], height=2)
label.pack(fill=tkinter.BOTH)
self.frame[1].pack(expand=1, fill=tkinter.BOTH)
# 输入消息的滚动条
self.inputTextScrollBar = tkinter.Scrollbar(self.frame[2])
self.inputTextScrollBar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
ft = tkFont.Font(family='Fixdsys', size=11)
self.inputText = tkinter.Text(self.frame[2], width=70, height=8, font=ft)
self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
self.inputText.pack(expand=1, fill=tkinter.BOTH)
self.inputTextScrollBar['command'] = self.chatText.yview()
self.frame[2].pack(expand=1, fill=tkinter.BOTH)
# 发送按钮
self.sendButton = tkinter.Button(self.frame[3], text='发送', width=10, command=self.sendMessage)
self.sendButton.pack(expand=1, side=tkinter.BOTTOM and tkinter.RIGHT, padx=25, pady=5)
# 关闭按钮
self.closeButton = tkinter.Button(self.frame[3], text='关闭', width=10, command=self.close)
self.closeButton.pack(expand=1, side=tkinter.RIGHT, padx=25, pady=5)
self.frame[3].pack(expand=1, fill=tkinter.BOTH)
self.buffer = 1024
self.flag = False
self.receive_thread = threading.Thread(target=self.receive_message)
self.receive_thread.start()
# 接收消息
def receive_message(self):
try:
self.clientSock = socket(AF_INET, SOCK_STREAM)
self.clientSock.connect((self.local, self.port))
self.flag = True
self.clientSock.send('Y'.encode()) # 向服务器发送字符
except Exception as e:
self.flag = False
self.chatText.insert(tkinter.END, '未能与服务器建立连接\n')
return
while True:
try:
if self.flag:
self.server_msg = self.clientSock.recv(self.buffer).decode()
print(self.server_msg)
if not self.server_msg:
continue
elif self.server_msg == 'Y':
self.chatText.insert(tkinter.END, '服务器已经和客户端建立连接成功\n')
elif self.server_msg == 'N':
self.chatText.insert(tkinter.END, '服务器已经和客户端建立连接失败\n')
else:
the_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(tkinter.END, f'服务端 {the_time} 说:{self.server_msg}\n')
self.chatText.see(tkinter.END)
else:
break
except Exception as e:
self.clientSock.send('N'.encode())
# self.chatText.insert(tkinter.END, f'Exception: {e}\n')
break
def close(self):
self.root.destroy()
def close_connection(self):
self.flag = False
try:
self.clientSock.shutdown(socket.SHUT_RDWR)
self.clientSock.close()
except:
pass
# 发送消息
def sendMessage(self):
message = self.inputText.get('1.0', tkinter.END)
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(tkinter.END, '客户端' + theTime + '说:\n' + message + '\n')
if self.flag:
self.clientSock.send(message.encode()) # 发送到服务器
else:
self.chatText.insert(tkinter.END, '未与客户端建立连接\n')
self.inputText.delete(0.0, message.__len__() - 1.0)
def startNewThead(self):
thread = threading.Thread(target=self.receive_message())
thread.start()
def main():
client = ClientUI()
client.root.protocol("WM_DELETE_WINDOW", client.close_connection())
client.root.mainloop()
client.startNewThead()
if __name__ == '__main__':
main()