2011-11-18 138 views
3

過去兩週,我一直在反駁套接字問題,但無濟於事。我有一臺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)

+2

提示:你不應該使用大寫字母作爲變量的第一個字母。該語法應該總是留給類名稱。問題:爲什麼客戶端在1循環中?爲什麼不只發一次說「我完成了」然後繼續?數據是否第一次發送? – chown

+0

啊 - 很高興知道。謝謝。 – nodapic

+0

我把它放在while循環中,因爲我擔心服務器拒絕連接,因爲他已經處理了其他客戶端。這是我的努力,以確保我們有一個積極的握手... – nodapic

回答

3

好吧,這個我花了一段時間,但我想我想通了什麼造成這樣的:

  1. glglgl的答案是正確的 - 使用的「localhost」使機器 只聽本身,而不是其他網絡上的機器。這個 是主要的罪魁禍首。
  2. 將que允許的數量從0增加到5減少了 在客戶端 端獲得「連接被拒絕」錯誤的可能性。
  3. 我在假定無限 套接字連接的錯誤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()不管它在做什麼,都會關閉套接字。雖然我沒有任何證據。

我認爲應該這樣做 - 再次感謝您幫助解決此問題!

2

你的服務器有兩個缺陷:

首先,這將打破內for循環出來,而不是while循環:

if FinishedCount == 12: 
    break 

while LO op沒有終止條件。

其次,這種模式:

try: 
    ... 
except: 
    pass 

應該從未使用。你吞噬每一個異常,並忽略它。這是不好的做法,並會導致錯誤。它應該是:

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

修復這兩個問題,並返回給我們結果。

+1

'except:raise'與沒有uncoditional'相同,除了:'在那裏。但是這個關於'break'沒有結束while循環是正確的。 – chown

+0

@chown這是真的,但我發現它有點更清楚/更容易理解,因爲它明確指出唯一被忽略的例外是指定的例外。 –

+0

突破的好處 - 我解決了這個問題。 一旦我加了加號,就得到了'socket.timeout:timed out'錯誤。我嘗試將套接字設置爲非阻塞,並導致出現[Error 11] Resource Temporarily unavailable'錯誤。除了避免暫停的方式之外,我原本做的是 - 當客戶端還沒有與服務器通信時,我期望這些發生。 – nodapic

0

呼叫監聽(0)設置沒有積壓,所以你更有可能得到拒絕的連接。服務器端套接字也永遠不會關閉。現在擺脫try/excepts,以便您可以看到真正的問題。否則,處理顯式的socket.error異常。

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)是簡短的方法。

我將您的代碼與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 ]$ 
+0

我正在看[socket.close()'](http://docs.python.org/library/socket.html#socket.socket.close)的文檔,它明確指出調用'.shutdown ()'有附加效果。只是'.close()'絕對不會「爲你做」。 –

+0

@AndréCaron嗯,我的錯誤..也許我當時正在考慮停止線程......修復答案。 – chown

+0

這很好,謝謝你。套接字命名只是概念上的 - 這不是我實際實現的方式。看到我發佈的答案 - 我必須做一些額外的編輯。 – nodapic

0

如果你

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

服務器計算機將只接受來自本身的連接,我。即本地主機。

相反,做

socket.bind(('', RandomPort)) 

監聽所有接口。

+0

噢,在我忘記它之前 - 開始熟悉AF_INET6和/或getaddrinfo()對於新的應用程序。 – glglgl

相關問題