无法通过Python中的套接字进行客户端 - 服务器通信

时间:2011-11-18 14:45:28

标签: python sockets client-server

过去两周我一直在反对插座问题,但无济于事。我有一个12'客户端'机器和一台服务器机器的设置。服务器被赋予了大量任务,将其分成12个较小的任务,然后将它们分发给12个客户端。客户流失,一旦完成任务,他们应该让服务器知道他们已经通过套接字通信完成了。出于某种原因,这只是一点点工作或根本不工作(服务器和客户端,只是坐在while循环中)。

以下是服务器上的代码:

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)

5 个答案:

答案 0 :(得分:3)

好吧,这花了我一段时间,但我想我弄清楚是什么造成了这个:

  1. glglgl的答案是正确的 - 使用'localhost'导致机器 只听自己而不是网络上的其他机器。这个 是罪魁祸首。
  2. 将que中允许的数量从0增加到5减少了 在客户端上出现“连接被拒绝”错误的可能性 侧。
  3. 我错误地认为套接字连接是无限的 while循环可以无限快速关闭 - 但是,有一个 无限时,两边的循环有时会导致客户端 有时会被计算两次,因为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())
    
  4. PS:我对.shutdown()vs .close()的理解是关闭连接,但如果它正在进行另一次通信,则不一定是套接字。无论它正在做什么,.shutdown()都会关闭套接字。我虽然没有任何证据。

    我认为应该这样做 - 再次感谢大家帮忙修复此代码!

答案 1 :(得分:2)

您的服务器有两个错误:

首先,这将突破内部for循环,而不是while循环:

if FinishedCount == 12:
    break

您的while循环没有终止条件。

其次,这种模式:

try:
    ...
except:
    pass

永远不会使用。你正在吞噬每一个例外并忽略它。这是不好的做法,并会导致错误。它应该是:

try:
    ...
except OneExceptionIWantToIgnore:
    pass
except:
    raise

修复这两个问题,然后回复我们的结果。

答案 2 :(得分:2)

我认为这里的问题是使用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)是缩短的方式。

我将您的代码与example code中的一些python socket documentation合并,并提出了一些可以轻松适应您需求的内容。这是脚本;运行服务器和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:

#!/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])))

运行12个客户端的输出:

[ 10:52 jon@hozbox.com ~/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 jon@hozbox.com ~/SO/python ]$

服务器同时运行的输出:

[ 10:52 jon@hozbox.com ~/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 jon@hozbox.com ~/SO/python ]$

答案 3 :(得分:0)

调用listen(0)不会设置积压,因此您更有可能拒绝连接。服务器端套接字也永远不会关闭。暂时摆脱尝试/排除,这样你就可以看出真正的问题是什么。否则处理显式的socket.error异常。

答案 4 :(得分:0)

如果你这样做

socket.bind(('localhost', RandomPort))

您的服务器机器只接受来自它自己的连接,i。即本地主机。

相反,做

socket.bind(('', RandomPort))

监听所有接口。