Python聊天客户端-服务器修改出现严重错误
作为一个练习,我想找一个简单的Python聊天客户端-服务器系统来修改和玩玩。首先,我发现这个系统的一个大问题是,它只用一个tcp连接让服务器和客户端进行通信。第二个问题是,它只能让两个人(一个用客户端,另一个用服务器)进行交流。第三个问题是,连续发消息是不可能的。一个人发完消息后,必须等另一个人发完一条消息才能再说话。这限制太多了。
于是我开始尝试使用线程,并对socket进行实验。客户端只需连接到服务器一次,提供自己的IP地址,创建一个监听线程,然后再连接到服务器的消息接收器。所有的消息都会发送到这个接收器,接收器会遍历连接的客户端列表,逐个连接并发送消息(消息开头会有发送者的名字;这是个附加功能)。
(我知道这样频繁地打开新连接效率不高,但我想先把tcp连接搞定,然后再转到udp)
然而,奇怪的事情开始发生。可以说,我现在梦里都在想Error 91。
有没有人能帮我找出如何在这个结构和功能下让这段代码正常运行?
(Python版本是2.6,嘿;无穷循环只是个占位符,可以忽略)
服务器代码:
from socket import *
from time import time, ctime
import Queue, threading
IP = ''
PORT = 5000
PORTPlus = 2
PORTRec = 1000
ADS = (IP, PORT)
namelist = []
clientlist = []
class clientRec(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
print "I'm this far:", (IP, (PORT + PORTRec))
self.receiver = socket(AF_INET, SOCK_STREAM)
self.receiver.bind((IP, PORT + PORTRec))
self.sender = socket(AF_INET, SOCK_STREAM)
def run(self):
global clientlist, namelist
self.receiver.listen(10)
connected = True
while connected:
tcpcli, addr = receiver.accept()
message = tcpcli.recv(1024) # Accept clien't IP for home-dialing
for i in range(clientlist.__len__()): # For each connected client
try:
sender.connect(clientlist(i)) # connect
sender.send(namelist[i] + message) # and deliver message with sender's name
sender.close()
except:
del clientlist[i], namelist[i]
print "ADS:", (IP, 5000)
handle = clientRec()
tcpsoc = socket(AF_INET, SOCK_STREAM) # Paperwork
tcpsoc.bind(ADS) # Bind self to port
tcpsoc.listen(5) # Listen on that port0
handle.start() # Start thread
# Main
while 1:
print "Waiting for connection"
tcpcli, addr = tcpsoc.accept() # Accept unknown client
print "Connection received; handling..."
namelist.append(tcpcli.recv(1024)) # Accept client's name
client_IP = tcpcli.recv(1024) # Accept clien't IP for home-dialing
client_port = int(tcpcli.recv(1024))# Accept clien't listening port
port_assign = PORT + PORTRec
tcpcli.send(str(port_assign)) # Tell the client that port
tcpcli.close() # Close client connection
clientlist.append((client_IP, client_port))# Add client to send-list
print "Handled."
tcpsoc.close()
客户端代码:
#!/usr/bin/env python
from socket import *
import threading, cgi, os
IP = ''
PORT = 5000
PORTmy = 100
ADS = (IP, PORT)
class iListen(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.receiver = socket(AF_INET, SOCK_STREAM)# Paperwork
self.receiver.bind(('', PORT + PORTmy)) # Listen on that port
self.receiver.listen(5) # Listen for posts
def run(self):
while listening:
tcpcli, addr = receiver.accept() # Accept unknown client
message = tcpcli.recv(1024)
if message == "/q":
listening = False
tcpcli.close()
# Initial CONNECT
myname = raw_input("Tell me yer name partnah: ")
tcpsoc = socket(AF_INET, SOCK_STREAM)
tcpsoc.connect(ADS) # First Connect
tcpsoc.send(myname) # Declare name
tcpsoc.send(gethostbyname(gethostname()))# Give IP address
tcpsoc.send(str(PORT + PORTmy)) # Give listening port
ADS = (IP, int(tcpsoc.recv(1024))) # Get new connect details
tcpsoc.close() # Close old connection
listen = iListen() # Create listener thread
listen.start() # Start listening
# RECONNECT
print ADS
tcpsoc = socket(AF_INET, SOCK_STREAM)
tcpsoc.connect(ADS) # reconnect to new port
connected = True
# Main Chat-loop
while connected:
mes = raw_input(">>>")
tcpsoc.send(mes)
if mes == "/q":
tcpsoc.close()
connected = False
time.sleep(4)
sys.exit()
1 个回答
我正在做一个类似的项目,不过我打算实现文本加密。我注意到你在用列表来处理客户端列表,但我觉得有更好的方法。我使用的是字典。
如果你对字典已经很熟悉,可以跳过下一段。
字典基本上可以处理两个变量,用大括号{}来定义。
>>> stuff = {'a':'hello','b':'world'}
>>> print stuff['a']
hello
>>> print stuff['a'],stuff['b']
hello world
通过这个,你可以创建一个字典,比如{'用户名':'ip地址'},这样就可以把用户名和IP地址都放在一个变量里。如果你想要的最终效果和我一样,你会让服务器只重复消息,并把它发送给所有连接的用户。然后服务器可以循环遍历这些用户名。
另外,我觉得tcpsoc.listen(5)是指一次可以连接的用户数量……我记得我在某个地方看到过这个。
我不知道你为什么会出现那个错误,但如果你想看看我半成品的代码,欢迎你查看。(忽略import random,这个还没用到,但将来会是加密系统的一部分)