无法通过Python中的套接字进行客户端 - 服务器通信
过去两周,我一直在反驳套接字问题,但无济于事。我有一台12台'客户'机器和一台服务器机器。服务器被赋予一个大任务,将其分成12个较小的任务,然后分配给12个客户端。客户流失了,一旦他们完成任务,他们应该让服务器知道他们已经通过套接字通信完成了。出于某种原因,这只是一直工作或根本没有(服务器和客户端,只是坐在while循环)。无法通过Python中的套接字进行客户端 - 服务器通信
这里是服务器上的代码:
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(('localhost', RandomPort))
socket.listen(0)
socket.settimeout(0.9)
[Give all the clients their tasks, then do the following:]
while 1:
data = 'None'
IP = [0,0]
try:
Client, IP = socket.accept()
data = Client.recv(1024)
if data == 'Done':
Client.send('Thanks')
for ClientIP in ClientIPList():
if ClientIP == IP[0] and data == 'Done':
FinishedCount += 1
if FinishedCount == 12:
break
except:
pass
这里是所有的客户端代码:
[Receive task from server and execute. Once finished, do the following:]
while 1:
try:
f = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
f.connect((IPofServer, RandomPort))
f.settimeout(0.5)
f.send('Done')
data = f.recv(1024)
if data == 'Thanks':
f.shutdown(socket.SHUT_RDWR)
f.close()
break
except:
f.close()
time.sleep(2+random.random()*5)
我已经使用Wireshark的,发现包被飞来飞去。然而,“FinishedCount”似乎从来没有增加过...我在设置时错过了什么明显的错误?这是我第一次接触到插座....
谢谢大家提前给予您的帮助!
编辑:我已经作出了如下代码修改:
在服务器上:socket.listen现在socket.listen(5)
好吧,这个我花了一段时间,但我想我想通了什么造成这样的:
- glglgl的答案是正确的 - 使用的“localhost”使机器 只听本身,而不是其他网络上的机器。这个 是主要的罪魁祸首。
- 将que允许的数量从0增加到5减少了 在客户端 端获得“连接被拒绝”错误的可能性。
-
我在假定无限 套接字连接的错误while循环可以关闭无限快的 - 但是,有一个 无限的,而两侧环有时会导致客户端 有时会因为同时重复计算循环不是 同步。当然,这导致'客户端不可知'finishedCount增加两次,这导致服务器相信所有 客户端时,他们没有。使用CHOWN的代码(!谢谢 CHOWN),这可以处理这样的:
def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((HOST, PORT)) sock.listen(0) FINISHEDCLIENTS = [] while 1: data = 'None' IP = [0, 0] try: client, ip = sock.accept() data = client.recv(1024) print "%s: Server recieved: '%s'" % (time.ctime(), data) if data == 'Done': print "%s: Server sending: 'Thanks'" % time.ctime() client.send('Thanks') if ip[0] in CLIENT_IPS and ip[0] not in FINISHEDCLIENTS: FINISHEDCLIENTS.append(ip[0]) if len(FINISHEDCLIENTS) == 12: #raise MyException break except Exception, e: print "%s: Server Exception - %s" % (time.ctime(), e)
在客户端,我改变了代码,这(这里当然, RandomPort是一样的一个在上面的服务器脚本)使用:
SentFlag = 0 data = 'no' while SentFlag == 0: try: f = socket.socket(socket.AF_INET, socket.SOCK_STREAM) f.connect((IPofServer, RandomPort)) f.settimeout(20) f.send('Done') data = f.recv(1024) if data == 'Thanks': f.shutdown(socket.SHUT_RDWR) f.close() SentFlag = 1 except: f.close() time.sleep(2*random.random())
PS:我.shutdown()VS .close(谅解)是关闭连接,但不一定是插座如果从事其他通信。 .shutdown()不管它在做什么,都会关闭套接字。虽然我没有任何证据。
我认为应该这样做 - 再次感谢您帮助解决此问题!
你的服务器有两个缺陷:
首先,这将打破内for
循环出来,而不是while
循环:
if FinishedCount == 12:
break
你while
LO op没有终止条件。
其次,这种模式:
try:
...
except:
pass
应该从未使用。你吞噬每一个异常,并忽略它。这是不好的做法,并会导致错误。它应该是:
try:
...
except OneExceptionIWantToIgnore:
pass
except:
raise
修复这两个问题,并返回给我们结果。
'except:raise'与没有uncoditional'相同,除了:'在那里。但是这个关于'break'没有结束while循环是正确的。 – chown
@chown这是真的,但我发现它有点更清楚/更容易理解,因为它明确指出唯一被忽略的例外是指定的例外。 –
突破的好处 - 我解决了这个问题。 一旦我加了加号,就得到了'socket.timeout:timed out'错误。我尝试将套接字设置为非阻塞,并导致出现[Error 11] Resource Temporarily unavailable'错误。除了避免暂停的方式之外,我原本做的是 - 当客户端还没有与服务器通信时,我期望这些发生。 – nodapic
呼叫监听(0)设置没有积压,所以你更有可能得到拒绝的连接。服务器端套接字也永远不会关闭。现在摆脱try/excepts,以便您可以看到真正的问题。否则,处理显式的socket.error异常。
我相信这里的问题是使用RandomPort
。每个客户端和服务器都需要在同一端口上发送/接收才能工作。而且,for ClientIP in ClientIPList(): if ClientIP == IP[0] and data == 'Done':
循环有点多余且不必要。它可以替换为if ip[0] in clientIpList:
,并放置在其上方的if data == 'Done':
内。
其他一些想法;不要将名称与您导入的名称命名为相同的名称(如socket = socket.socket(..)
),因为那样您将无法再使用导入的库。除非客户端/服务器都在同一个系统上运行或者在同一个子网内运行,否则settimeout(0.5)
是简短的方法。
我将您的代码与python socket
documentation中的一些example code合并,并提出了一些可以轻松适应您的需求的方法。这里是脚本;下面粘贴运行服务器和12个客户端的输出。
server.py:
#!/usr/bin/python
# server.py
import sys
import socket
import time
HOST = ''
PORT = 50008
CLIENT_IPS = ["10.10.1.11"]
## No longer necessary if the nested loop isn't needed
#class MyException(Exception):
# pass
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(0)
finishedCount = 0
while 1:
data = 'None'
IP = [0, 0]
try:
client, ip = sock.accept()
data = client.recv(1024)
print "%s: Server recieved: '%s'" % (time.ctime(), data)
if data == 'Done':
print "%s: Server sending: 'Thanks'" % time.ctime()
client.send('Thanks')
if ip[0] in CLIENT_IPS:
finishedCount += 1
print "%s: Finished Count: '%d'" % (time.ctime(), finishedCount)
if finishedCount == 12:
#raise MyException
break
except Exception, e:
print "%s: Server Exception - %s" % (time.ctime(), e)
#except MyException:
# print "%s: All clients accounted for. Server ending, goodbye!" % time.ctime()
# break
# close down the socket, ignore closing exceptions
try:
sock.close()
except:
pass
print "%s: All clients accounted for. Server ending, goodbye!" % time.ctime()
if __name__ == '__main__':
sys.exit(main())
client.py:从服务器在同一时间运行
[ 10:52 [email protected] ~/SO/python ]$ for x in {1..12}; do ./client.py $x && sleep 2; done
Fri Nov 18 10:52:44 2011: Client 1: Sending - 'Done'..
Fri Nov 18 10:52:44 2011: Client 1: Recieved - 'Thanks'
Fri Nov 18 10:52:44 2011: Client 1: Finished, goodbye!
Fri Nov 18 10:52:46 2011: Client 2: Sending - 'Done'..
Fri Nov 18 10:52:46 2011: Client 2: Recieved - 'Thanks'
Fri Nov 18 10:52:46 2011: Client 2: Finished, goodbye!
Fri Nov 18 10:52:48 2011: Client 3: Sending - 'Done'..
Fri Nov 18 10:52:48 2011: Client 3: Recieved - 'Thanks'
Fri Nov 18 10:52:48 2011: Client 3: Finished, goodbye!
Fri Nov 18 10:52:50 2011: Client 4: Sending - 'Done'..
Fri Nov 18 10:52:50 2011: Client 4: Recieved - 'Thanks'
Fri Nov 18 10:52:50 2011: Client 4: Finished, goodbye!
Fri Nov 18 10:52:52 2011: Client 5: Sending - 'Done'..
Fri Nov 18 10:52:52 2011: Client 5: Recieved - 'Thanks'
Fri Nov 18 10:52:52 2011: Client 5: Finished, goodbye!
Fri Nov 18 10:52:54 2011: Client 6: Sending - 'Done'..
Fri Nov 18 10:52:54 2011: Client 6: Recieved - 'Thanks'
Fri Nov 18 10:52:54 2011: Client 6: Finished, goodbye!
Fri Nov 18 10:52:56 2011: Client 7: Sending - 'Done'..
Fri Nov 18 10:52:56 2011: Client 7: Recieved - 'Thanks'
Fri Nov 18 10:52:56 2011: Client 7: Finished, goodbye!
Fri Nov 18 10:52:58 2011: Client 8: Sending - 'Done'..
Fri Nov 18 10:52:58 2011: Client 8: Recieved - 'Thanks'
Fri Nov 18 10:52:58 2011: Client 8: Finished, goodbye!
Fri Nov 18 10:53:01 2011: Client 9: Sending - 'Done'..
Fri Nov 18 10:53:01 2011: Client 9: Recieved - 'Thanks'
Fri Nov 18 10:53:01 2011: Client 9: Finished, goodbye!
Fri Nov 18 10:53:03 2011: Client 10: Sending - 'Done'..
Fri Nov 18 10:53:03 2011: Client 10: Recieved - 'Thanks'
Fri Nov 18 10:53:03 2011: Client 10: Finished, goodbye!
Fri Nov 18 10:53:05 2011: Client 11: Sending - 'Done'..
Fri Nov 18 10:53:05 2011: Client 11: Recieved - 'Thanks'
Fri Nov 18 10:53:05 2011: Client 11: Finished, goodbye!
Fri Nov 18 10:53:07 2011: Client 12: Sending - 'Done'..
Fri Nov 18 10:53:07 2011: Client 12: Recieved - 'Thanks'
Fri Nov 18 10:53:07 2011: Client 12: Finished, goodbye!
[ 10:53 [email protected] ~/SO/python ]$
输出::从运行12个客户
#!/usr/bin/python
# client.py
import sys
import time
import socket
import random
HOST = '10.10.1.11'
PORT = 50008
def main(n):
while 1:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('Done')
print "%s: Client %d: Sending - 'Done'.." % (time.ctime(), n)
data = s.recv(1024)
print "%s: Client %d: Recieved - '%s'" % (time.ctime(), n, data)
if data == 'Thanks':
break
except Exception, e:
print "%s: Client %d: Exception - '%s'" % (time.ctime(), n, e)
time.sleep(2 + random.random() * 5)
finally:
try:
s.shutdown(socket.SHUT_RDWR)
except:
pass
finally:
try:
s.close()
except:
pass
print "%s: Client %d: Finished, goodbye!" % (time.ctime(), n)
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1].isdigit():
sys.exit(main(int(sys.argv[1])))
输出
[ 10:52 [email protected] ~/SO/python ]$ ./server.py
Fri Nov 18 10:52:44 2011: Server recieved: 'Done'
Fri Nov 18 10:52:44 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:44 2011: Finished Count: '1'
Fri Nov 18 10:52:46 2011: Server recieved: 'Done'
Fri Nov 18 10:52:46 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:46 2011: Finished Count: '2'
Fri Nov 18 10:52:48 2011: Server recieved: 'Done'
Fri Nov 18 10:52:48 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:48 2011: Finished Count: '3'
Fri Nov 18 10:52:50 2011: Server recieved: 'Done'
Fri Nov 18 10:52:50 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:50 2011: Finished Count: '4'
Fri Nov 18 10:52:52 2011: Server recieved: 'Done'
Fri Nov 18 10:52:52 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:52 2011: Finished Count: '5'
Fri Nov 18 10:52:54 2011: Server recieved: 'Done'
Fri Nov 18 10:52:54 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:54 2011: Finished Count: '6'
Fri Nov 18 10:52:56 2011: Server recieved: 'Done'
Fri Nov 18 10:52:56 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:56 2011: Finished Count: '7'
Fri Nov 18 10:52:58 2011: Server recieved: 'Done'
Fri Nov 18 10:52:58 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:58 2011: Finished Count: '8'
Fri Nov 18 10:53:01 2011: Server recieved: 'Done'
Fri Nov 18 10:53:01 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:01 2011: Finished Count: '9'
Fri Nov 18 10:53:03 2011: Server recieved: 'Done'
Fri Nov 18 10:53:03 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:03 2011: Finished Count: '10'
Fri Nov 18 10:53:05 2011: Server recieved: 'Done'
Fri Nov 18 10:53:05 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:05 2011: Finished Count: '11'
Fri Nov 18 10:53:07 2011: Server recieved: 'Done'
Fri Nov 18 10:53:07 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:07 2011: Finished Count: '12'
Fri Nov 18 10:53:07 2011: All clients accounted for. Server ending, goodbye!
[ 10:53 [email protected] ~/SO/python ]$
如果你
socket.bind(('localhost', RandomPort))
服务器计算机将只接受来自本身的连接,我。即本地主机。
相反,做
socket.bind(('', RandomPort))
监听所有接口。
噢,在我忘记它之前 - 开始熟悉AF_INET6和/或getaddrinfo()对于新的应用程序。 – glglgl
提示:你不应该使用大写字母作为变量的第一个字母。该语法应该总是留给类名称。问题:为什么客户端在1循环中?为什么不只发一次说“我完成了”然后继续?数据是否第一次发送? – chown
啊 - 很高兴知道。谢谢。 – nodapic
我把它放在while循环中,因为我担心服务器拒绝连接,因为他已经处理了其他客户端。这是我的努力,以确保我们有一个积极的握手... – nodapic