Python 如何找出哪个套接字客户端发送消息?
我正在开发一个聊天程序。我有一个服务器和客户端,多个用户可以连接到服务器。目前,我只是让服务器发回客户端发送给服务器的任何消息。我想添加一个身份验证,以便在身份验证失败时可以接受/拒绝连接 客户:Python 如何找出哪个套接字客户端发送消息?,python,sockets,Python,Sockets,我正在开发一个聊天程序。我有一个服务器和客户端,多个用户可以连接到服务器。目前,我只是让服务器发回客户端发送给服务器的任何消息。我想添加一个身份验证,以便在身份验证失败时可以接受/拒绝连接 客户: class Network: # initialize the socket def __init__(self, client, host=host, port=port): self.client = client; self.socket = so
class Network:
# initialize the socket
def __init__(self, client, host=host, port=port):
self.client = client;
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
self.port = port;
self.host = host;
self.addr = (host, port);
# conenct to the server
def connect(self):
self.socket.connect(self.addr);
# receive data from server if there is any
def read(self):
while True:
time.sleep(0.1)
try:
data = self.socket.recv(1024);
except:
break;
# instead of breaking, create "connection lost" then open the login form again
print "in client: ", data;
data_split = data.split("\r\n");
for ds in data_split:
self.client.msgbox.addMsg(ds);
# send chat message to the server
def send(self, msg):
self.socket.send(msg);
# authenticate user
# if
def authenticate(self, info):
self.socket.send(info);
服务器:
class Server:
# init the socket
def __init__(self, host=host, port=port):
self.host = host;
self.port = port;
self.addr = (host, port);
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
# send data to client
def send(self, soc, data):
try:
soc.send(data);
except:
return "couldn't send message";
# receive data from client
def receive(self, soc):
while True:
try:
return soc.recv(size);
except:
return disconnect;
# connect client
def connect(self):
self.socket.bind(self.addr);
self.socket.listen(5);
self.socket_s = [self.socket];
self.read_socs = [self.socket];
self.write_socs = [];
self.user_addr = {};
# validate the user
def validate(self, username, password):
if username in users:
sha = s256.new();
sha.update(password);
password = sha.hexdigest();
if password == users[username]:
print "in server: true";
return True;
else:
print "in server: false";
return False;
# server
def serve(self):
while True:
r_socs, w_socs, exceptions = select.select(self.read_socs, [], []);
for s in r_socs:
if s in self.socket_s:
print "accepting socket connect";
soc, address = s.accept();
print "in server: ", soc, address;
self.read_socs.append(soc);
self.write_socs.append(soc);
for ws in self.write_socs:
self.send(ws, "len(users) == " + str(len(self.write_socs)) + "\n");
print connection;
else:
data = self.receive(s);
print "in server: " + data;
if auth in data:
ds = data.split(" ");
res = self.validate(ds[1], ds[2]);
elif data == disconnect:
s.close();
self.read_socs.remove(s);
self.write_socs.remove(s);
for ws in self.write_socs:
print "in server: " + ws
self.send(ws, "len(users) == " + str(len(self.write_socs)) + "\n");
else:
for ws in self.write_socs:
print "in server: " + ws;
self.send(ws, data);
您的设计实际上是行不通的,因为接收到的TCP消息中的数据不一定与来自另一端的单个发送相关,它可能是半条消息、3条消息或5-1/2条消息。如果您只是在本地主机上进行测试,并且只有一些小消息,那么它在您的测试中通常会正常工作,然后当您将它放到internet上时,它就会完全失败。这就是为什么您需要在TCP之上构建某种协议,使用定界符(如换行符)、长度前缀(如NetString)或自定界对象(如JSON) 不管怎么说,你都知道每一条消息所使用的套接字。您可以将套接字映射到用户,或者仅使用套接字本身或其FD来做出决策。因此,正如跟踪所有要传递到
select
的已知套接字一样,您也要跟踪所有已知要进行身份验证的套接字。如果消息进入的套接字在该列表中,则它经过身份验证;否则,该消息将被拒绝,除非它是身份验证消息
假设您有一个简单的线路协议:
def __init__(self):
self.sockets = [] # add clients here, along with listener
self.authsockets = [] # add authenticated clients here
self.buffers = defaultdict(str)
def loop(self):
r, w, x = select.select([sockets], [sockets], [sockets])
for sock in r:
buffers[sock] = buffers[sock] + sock.recv(4096)
lines = buffers[sock].split('\n')
if buffers[sock][-1] != '\n':
buffers[sock], lines = lines[-1], lines[:-1]
else:
buffers[sock] = ''
for line in lines:
processCommand(sock, line)
# etc.
def processCommand(self, sock, command):
if self.isAuthCommand(command):
if self.isValidAuthCommand(command):
self.authsockets.append(sock)
return
if not sock in self.authsockets:
return # ignore commands before auth
self.doNormalThing(command)
我已经去掉了处理接受、断开连接、错误、写入等所有不相关的内容,但是你的读取也有类似的问题。首先,假设套接字总是可写的,这是不正确的。您需要为每个套接字排队一个写入缓冲区,并在
select
告诉您可以时写入。同样,这似乎在localhost上也能起作用,但在internet上它会崩溃。其次,写入套接字可能不会发送整个缓冲区,因此您需要查看写入了多少字节,并将缓冲区[bytecount:]保留到下一次。您是否使用select
循环或其他方式处理了多个连接?@abarnert是的,我目前正在使用select,但我不太熟悉它。@LtWorf老实说,我不确定。我只是在看在线示例。你应该理解这些教程,而不仅仅是复制和粘贴它们。@ltwor如果我不是复制它们,我是从头开始写的。