2015-11-02 4 views
0

Я делаю небольшую клиентскую/серверную игру. Хотя в основном это работает, связь между сервером и клиентом кажется слегка фанкой, и я не совсем уверен, что ее вызывает.Python - клиент иногда не получает данные

Итак, я запускаю server.py, а затем client.py, клиент соединяется и получает длину первого сообщения, он принимает фактическое сообщение и отображает его совершенно нормально. Но когда он снова пробегает, он никогда не получает второе сообщение, только то, как долго это происходит. Он просто ждет бесконечно (ну, по-моему, для тайм-аута TCPs я думаю).

Я понимаю, что некоторые байты могут потеряться, но TCP предназначен для гарантии доставки, если есть еще соединение, верно? UDP - это тот, который просто выбрасывает пакеты? Кажется, он тоже не отключается. Это также связано с локальным хостом, поэтому он даже не покидает мою машину.

В случае, если это связано с синхронизацией, я также сделал сервер time.sleep(.5) перед ожиданием ответа с пользовательского ввода клиента.

Почему клиент получает первое сообщение, но не второе, несмотря на то, что тот же метод отправил его?

Server.py

import socket, random, pickle, os.path, csv, time 

# Global variables 
c = 0 
a = "" 

def SendIt(d): 
    global c 
    d = pickle.dumps(d) 
    MSGLEN = len(d) 
    print ("MSGLEN =", MSGLEN) # REMOVE AFTER DEBUG 
    MSGLENstr = pickle.dumps(MSGLEN) 
    c.send(MSGLENstr) 
    totalsent = 0 
    while totalsent < MSGLEN: 
     sent = c.send(d[totalsent:]) 
     if sent == 0: 
      raise RuntimeError("socket connection broken") 
     totalsent = totalsent + sent 

def TheMainGame(): 
    def within(val, goal): 
     i = abs(val - goal) 
     if (i <= 3): 
      return True 
     else: 
      return False 

    def try_int(k): 
     try: 
      return int(k) 
     except ValueError: 
      return k 

    def GetScoreboard(): 
     with open('Scores.csv', 'r') as scores: 
      reader = csv.reader(scores) 
      tscores = [[str(e) for e in r] for r in reader if len(r) > 0] 
      return tscores 

    def WriteScore(gscore): 
     global c, a, tscore 
     exists = os.path.isfile("Scores.csv") 
     if (exists == False): # Checks if file exists, if not create it 
      nscore = [[gscore, a[0]]] # Add first line of data 
      with open("Scores.csv", "a") as scores: 
       writer = csv.writer(scores) 
       [writer.writerow(r) for r in nscore] 
     else: # File exists so we add to it 
      nscore = [[gscore, a[0]]] 
      with open('Scores.csv', 'r') as scores: 
       reader = csv.reader(scores) 
       tscores = [[str(e) for e in r] for r in reader if len(r) > 0] 
      tscores = [[try_int(l) for l in i] for i in tscores] 
      tscores.append(nscore[0]) 
      tscores = [x for x in tscores if x != []] 
      tscores.sort(key=lambda x: x[0]) 
      if (len(tscores) > 5): 
       tscores = tscores[:5] 
       with open("Scores.csv", "w+") as scores: 
        writer = csv.writer(scores) 
        [writer.writerow(r) for r in tscores] 
      elif (len(tscores) <= 5): 
       with open("Scores.csv", "w+") as scores: 
        writer = csv.writer(scores) 
        [writer.writerow(r) for r in tscores] 

    def Guess(): 
     global c 
     guesses = 0 
     while True: 
      data = ["open", "What is your guess?"] 
      SendIt(data) 
      time.sleep(.5) 
      print("sent question") # REMOVE AFTER DEBUG 
      t = int(c.recv(1000).decode()) 
      print("waiting for reply") # REMOVE AFTER DEBUG 
      if (t == x): 
       guesses += 1 
       data = ["msg","Correct!"] 
       SendIt(data) 
       if (guesses == 1): 
        msg = "You took ", guesses, " guess!" 
       else: 
        msg = "You took ", guesses, " guesses!" 
       msg = [str(x) for x in msg] 
       msg = ",".join(msg) 
       msg = msg.replace(",", "") 
       data = ["msg", msg] 
       SendIt(data) 
       WriteScore(guesses) 
       data = ["msg", "Heres the leaderboard:"] 
       SendIt(data) 
       data = ["scores", GetScoreboard()] 
       SendIt(data) 
       data = ["closing", "Thanks for playing!"] 
       SendIt(data) 
       c.close() 
       break 
      elif (within(t,x) == True): 
       guesses += 1 
       data = ["incorrect", "Close!"] 
       SendIt(data) 
      elif (within(t,x) == False): 
       guesses += 1 
       data = ["incorrect", "Far"] 
       SendIt(data) 
      else: 
       data = ["closing", "There was an error computing the value"] 
       SendIt(data) 
       c.close() 
       break 

    x = random.randrange(1, 20, 1) 
    print(x) # REMOVE AFTER DEBUG 
    Guess() 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind(("127.0.0.1", 4001)) 
s.listen(5) 
while True: 
    (c,a) = s.accept() 
    data = ["msg", "Hello user!"] 
    SendIt(data) 
    TheMainGame() 

Client.py

import socket, pickle 

# Global variables 
connected = False 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
data = ["closing", "Connection closed"] 

def GetData(): 
    global s, data 
    chunks = [] 
    bytes_recd = 0 
    MSGLEN = s.recv(512) # OLD RECV 
    MSGLEN = pickle.loads(MSGLEN) 
    print ("MSGLEN =", MSGLEN) # REMOVE AFTER DEBUG 
    while bytes_recd < MSGLEN: 
     chunk = s.recv(min(MSGLEN - bytes_recd, 2048)) 
     print("chunk =", chunk) # REMOVE AFTER DEBUG 
     if chunk == b'': 
      raise RuntimeError("socket connection broken") 
     chunks.append(chunk) 
     bytes_recd = bytes_recd + len(chunk) 
    data = b''.join(chunks) 
    data = pickle.loads(data) 
    print("data after depickled=", data) # REMOVE AFTER DEBUG 

def SendData(): 
    global s 
    sdata = input() 
    s.send(sdata.encode()) 


def Connect(): 
    global s, connected 
    s.connect(("127.0.0.1", 4001)) 
    connected = True 

# Connect to server 
Connect() 

# Send/recive data till session ends 
while (connected == True): 
    print("fetching data") # REMOVE AFTER DEBUG 
    GetData() 
    print ("got data") # REMOVE AFTER DEBUG 
    if (data[0] == "closing"): 
     print (data[1]) 
     s.close() 
     connected = False 
     break 
    elif (data[0] == "incorrect"): 
     print (data[1]) 
    elif (data[0] == "open"): 
     print("open task running") # REMOVE AFTER DEBUG 
     print (data[1]) 
     print("printed data[1]") # REMOVE AFTER DEBUG 
     SendData() 
    elif (data[0] == "msg"): 
     print (data[1]) 
    elif (data[0] == "scores"): 
     data = data[1] 
     data = [",".join(i) for i in data] 
     data = [i.replace(",", " - ") for i in data] 
     print("Guesses - User") 
     print(*data, sep='\n') 
    else: 
     print ("An error occured!") 


Выход сервера

MSGLEN = 36 
5 
MSGLEN = 45 
sent question 

выход Client

fetching data 
MSGLEN = 36 
chunk = b'\x80\x03]q\x00(X\x03\x00\x00\x00msgq\x01X\x0b\x00\x00\x00Hello user!q\x02e.' 
data after depickled= ['msg', 'Hello user!'] 
got data 
Hello user! 
fetching data 
MSGLEN = 45 


Сервер не будет иметь какой-либо вывод, когда закончил, я только поставил его, чтобы помочь мне отладки. И большая часть вывода в клиенте тоже не будет существовать, опять же, это просто для отладки. Я выделил все строки отладки # REMOVE AFTER DEBUG, чтобы облегчить их поиск. Как видите, chunk = s.recv(min(MSGLEN - bytes_recd, 2048)) никогда не заканчивается во второй раз.

+0

Хорошо, я исправил эту проблему. Я просто переместил 'time.sleep (.5)' line. Но теперь я получаю еще одну ошибку, получает случайное пустое сообщение, заставляя клиента думать, что соединение нарушено. – PairedPrototype

ответ

0

Это была логическая ошибка, которую я решил сам.

я удалил time.sleep(.5) линии на сервере и переехал его на SendIt() изменяя его time.sleep(.1) заставляя сервер спать в течение 0,1 секунд, прежде чем отправить данные клиента. Для того, чтобы поставить в перспективе:

def Guess(): 
    global c 
    guesses = 0 
    while True: 
     data = ["open", "What is your guess?"] 
     SendIt(data) 
     """time.sleep(.5)""" # This line gets removed 
     print("sent question") 
     t = int(c.recv(1000).decode()) 
     print("waiting for reply") 

и

def SendIt(d): 
    global c 
    d = pickle.dumps(d) 
    MSGLEN = len(d) 
    print ("MSGLEN =", MSGLEN) 
    MSGLENstr = pickle.dumps(MSGLEN) 
    time.sleep(.1) # This new line makes it pause 0.1 seconds before sending the data 
    c.send(MSGLENstr) 
    totalsent = 0 
    while totalsent < MSGLEN: 
     sent = c.send(d[totalsent:]) 
     if sent == 0: 
      raise RuntimeError("socket connection broken") 
     totalsent = totalsent + sent 

Надежда это помогает кому-то еще! Также запомните import time.