【发布时间】:2016-07-17 11:36:53
【问题描述】:
我有一个服务器和一个客户端,它们可以相互连接,我可以从客户端发送到服务器,但反之则不行。当我尝试将数据发送回客户端时程序失败。
client.py
from tkinter import *
import socket
import threading
tLock = threading.Lock()
shutdown = False
host = '::1';
port = 5000;
s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
class Application(Frame):
def __init__(self, master=None):
#Create master frame
Frame.__init__(self,master)
self.grid()
self.master.title("Test 1")
self.conn=False #State of connection to server
#Configure main frame
for r in range (4):
self.master.rowconfigure(r, weight=1)
for c in range (2):
self.master.columnconfigure(c)
#Create sub frames
TopFrame=Frame(master)
TopFrame.grid(row=0, column=0, rowspan=3)
BottomFrame=Frame(master, bg="green")
BottomFrame.grid(row=4, column=0, rowspan=3)
SideFrame=Frame(master, bg="red")
SideFrame.grid(column=1, row=0, rowspan=4)
#Create Chat log
self.chatlog=Text(TopFrame)
self.chatlog.pack(padx=5, pady=5)
#messenger and send button
self.e1=Entry(BottomFrame, width=92)
self.e1.pack(side=LEFT, pady=5, padx=5)
sendButton=Button(BottomFrame, text="Send", command=self.sendmessage, height = 1, width = 10)
sendButton.pack(side=LEFT)
#Create connect disconnect buttons
b1=Button(SideFrame, text="Connect", command=self.connect)
b1.grid(row=0, column=0, padx=5, pady=5)
b2=Button(SideFrame, text="Disconnect", command=self.disconnect)
b2.grid(row=1, column=0, padx=5, pady=5)
def connect(self): #Connect to server
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===ATTEMPTING TO CONNECT TO SERVER\n"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
s.connect((host,port))
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, (s))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("\n\n PLEASE ENTER A USER NAME AND SEND"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
self.conn=True
print("Connected") #Connection successful
# M- Adding threading for receiving messages
rT = threading.Thread(target=self.receving, args=("RecvThread",s))
rT.start()
# When attempting to connect a second time, produces OS error: an operation was attempted on something that is not a socket
def disconnect(self):
if self.conn: #Tests to see if client is connected
s.close()
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===DISCONNECTED FROM SERVER.\n"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
self.conn=False
else: #Prevents attempting to disconnect when already disconnected
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===YOU AREN'T CURRENTLY CONNECTED.\n"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
def sendmessage(self):
if self.conn: #Prevents sending if not connected
self.msg=self.e1.get()
if self.msg == "": #Empty message catcher
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===YOU CANNOT SEND AN EMPTY MESSAGE.\n" ))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
else:
self.send_data(self.msg) #Sends message to the server
self.e1.delete(0, END)
else:
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===YOU ARE NOT CONNECTED TO A SERVER. YOU CANNOT SEND A MESSAGE.\n" ))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
# M- Method to handle receiving from the server
# adds the data to the chat log.
def receving(self, name, sock):
while not shutdown:
try:
tLock.acquire()
while True:
data, addr = sock.recvfrom(1024)
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, (data + '\n'))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
except:
pass
finally:
tLock.release()
def send_data(self, message):
try:
s.send(message.encode('UTF-8'))
except:
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===THE PREVIOUS MESSAGE DIDN'T SEND. THIS IS POSSIBLY DUE TO A SERVER ERROR.\n"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
root = Tk()
app = Application(root)
app.mainloop()
服务器.py
import socket
import threading
import sys
hosts=["::1"]
port=5000
#dictionay to hold the socket as the key and the user name as the value
dic = {}
class Server:
def __init__ (self,hosts,port):
self.host=hosts
self.port=port
self.socketserver=socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.socketserver.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print("Socket has been created successfully")
for i in hosts:
try:
host=i
self.socketserver.bind((host,port))
print("Connection succeded to address",i)
print ("The server is now binded to the following IP address",host,"Port",port)
break
except socket.error:
print("Connection failed to address",i)
else:
sys.exit()
def Accept_connections(self):
while True:
self.socketserver.listen(10)
print("Socket is now awaiting connections")
server, clientaddress = self.socketserver.accept()
print("Connection enstablished with: " +str(clientaddress))
threading.Thread(target = self.message,args = (server,clientaddress),).start()
def message(self,server,clientaddress):
while True:
try:
data= server.recv(1024)
print("data ", data)
#check to see if it is a new socket that is not in the stored
#socket dictionary
if server not in dic.keys():
print("if statement")
#if it is a new socket
#add the socket and the user name
dic[server] = data
for key in dic:
#send the joined message to the users
print("failing")
key.send("\n\n" + data + " has joined the chat")
else:
#alias is a variable used to store the sockets username
alias = dic[server]
for key in dic:
#send the message to the sockets in the dictionary
key.send(alias + ": " +data)
except:
server.close()
#edit this bit !
print("Data transfer failed")
return False
Server(hosts,port).Accept_connections()
程序失败于:
key.send("\n\n" + data + " has joined the chat")
当客户端连接时,他们会输入要称为的用户名。这将它与一个套接字一起存储在字典中。当循环套接字以通知他们已加入的其他客户端时,会发生错误。任何帮助都会很棒。这在 python27 上工作,但是当我更新到 python34 时现在已经停止。
【问题讨论】:
-
出现错误时程序是否输出stacktrace?如果有,请提供。
-
嗨,唯一的输出是“数据传输失败”
-
将 server.py 中的
except:行更改为except Exception as ex:并紧跟在print(ex)之后添加一行。打印什么? (您的except隐藏了失败的详细信息)。 -
啊,原来如此。打印的错误是“无法将 'bytes' 对象隐式转换为 str”
-
你可能需要解码
key.send("\n\n" + data + " has joined the chat")中的data参数,所以key.send("\n\n" + data.decode('utf-8') + " has joined the chat")。这里的教训是不要使用“裸”excepts:明确说明你正在捕获的异常,如果你必须有一个像except Exception这样的包罗万象,那么记录它吞下的错误。
标签: python sockets server client chat