2011-12-25 112 views
12

我有簡單的python服務器和客戶端。如何在客戶端關閉前保持套接字打開?

服務器:

import SocketServer 
import threading 


class MyTCPHandler(SocketServer.BaseRequestHandler): 
    def handle(self): 
     self.data = self.request.recv(1024).strip() 
     print str(self.client_address[0]) + " wrote: " 
     print self.data 
     self.request.send(self.data.upper()) 


if __name__ == "__main__": 
    HOST, PORT = "localhost", 3288 
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) 
    server.serve_forever() 

客戶:

import socket 
import sys 
from time import sleep 

HOST, PORT = "localhost", 3288 
data = "hello" 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

try: 
    sock.connect((HOST, PORT)) 
    sock.send(data + "\n") 
    received = sock.recv(1024) 

    sleep(10) 

    sock.send(data + "\n") 
    received = sock.recv(1024) 

    sleep(10) 

    sock.send(data + "\n") 
    received = sock.recv(1024) 

finally: 
    sock.close() 

這裏是輸出我得到:

服務器:

>python server.py 
127.0.0.1 wrote: 
hello 

客戶:

>python client.py 
Traceback (most recent call last): 
    File "client.py", line 18, in <module> 
    received = sock.recv(1024) 
socket.error: [Errno 10053] An established connection was aborted by the software in your host machine 

我想它在Linux機器上爲好。服務器只收到一條消息,然後在第二條消息的recv語句中出現錯誤。我剛剛開始學習python的網絡,但我認爲服務器出於某種原因正在關閉套接字。我該如何糾正?

+0

這可能有所幫助:http://stackoverflow.com/a/20421867/2290820 – user2290820 2013-12-06 16:07:20

回答

20

一個MyTcpHandler對象,handle被調用來處理客戶端。連接被關閉時handle的回報,所以你必須處理handle方法中來自客戶端的完整的通信:

class MyTCPHandler(SocketServer.BaseRequestHandler): 
    def handle(self): 
     while 1: 
      self.data = self.request.recv(1024) 
      if not self.data: 
       break 
      self.data = self.data.strip() 
      print str(self.client_address[0]) + " wrote: " 
      print self.data 
      self.request.send(self.data.upper()) 

注:recv回報''當客戶端關閉連接,所以我的recv後移動.strip()所以不會因客戶端只發送空白而造成誤報。

+0

感謝您的答案 – Bruce 2011-12-25 03:56:24

1

我會首先承認自從我上次使用SocketServer以來已經有多年了,所以可能會有更多的慣用方法來解決您的問題。您的客戶端打開一個連接併發送三組數據,並接收三組數據

注意。 (希望一旦你在插座上調用的TCP堆棧將發送緩衝的數據。)

你的服務器要求徹底處理客戶端連接,從開始到結束,當它從SocketServer回調機制調用。你當前的班級做了一點IO,然後退出。你只需要擴展服務器回調做多:爲每個連接創建

class MyTCPHandler(SocketServer.BaseRequestHandler): 
    def handle(self): 
     self.data = self.request.recv(1024).strip() 
     print str(self.client_address[0]) + " wrote: " 
     print self.data 
     self.request.send(self.data.upper()) 
     foo = self.request.recv(1024).strip() 
     self.request.send(foo.lower()) 
     bar = self.request.recv(1024).strip() 
     self.request.send("goodbye " + bar) 
+0

感謝您的回答 – Bruce 2011-12-25 03:56:36

1

到類似的問題在這裏error: [Errno 10053]

我也嘗試過同樣的事情,得到了同樣的錯誤。

如果有一個簡單的這樣的代碼演示此錯誤:如果您創建一個Socket對象,它可以發送AMT和從服務器回顯,看看有多少的接收方,如果

import socket 

host = 'localhost' 
port = 5001 
size = 102400 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((host,port)) 
for msg in ['Hello, world','Test','anything goes here']: 
    s.send(msg) 
    data = s.recv(size) 
    print 'Received:', data 
s.close() 

你例如1024到102400(在此代碼中); 這意味着套接字不應該關閉,但是在我的Windows操作系統中,服務器端會一直監聽並打印客戶端發送的任何數據,但在客戶端您會收到此錯誤;

但是,如果客戶端只能連接一次,只能發送和接收一次,那麼它就是這樣設計的。嘗試此工作沒有任何錯誤:

for msg in ['Hello, world','Test','anything goes here']: 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect((host,port)) 
    s.send(msg) 
    data = s.recv(size) 
    s.close() 
    print 'Received:', data 

我不確定是否一個套接字對象只能發送和接收數據一次。

UPDATE 我認爲問題是每個客戶端套接字接收數據的容量按緩衝區大小固定; 這就是爲什麼上面的第二個代碼片段工作,從而在服務器上創建新的客戶端連接套接字。但這樣,很多套接字將會耗盡。

取而代之,下面的代碼通過檢查所用的大小來解決這個問題。如果超過了給定的數量,它會在客戶端創建一個新的套接字'但確保發送消息;其實問題出在服務器代碼上,但是修復了它。

size = 10

這是一個快速寶寶嘗試的代碼。我相信你會理解並優化它!

客戶端代碼:

messag = ['Hello, world', 'Test', 'anything goes here'] 

def client_to_server(messag,host,port,size): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect((host, port)) 
    countmsg = 0 
    restmsg = '' 
    for msg in messag: 
     strl = tmsg = msg 
     if len(restmsg): 
      tmsg = restmsg + ' ' + msg 
     countmsg = len(tmsg) 
     if countmsg <= size: 
      pass 
     else: 
      restmsg = tmsg[size:] 
      tmsg = tmsg[:size] 
      #s.close() 
      countmsg = len(tmsg) 
      #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      #s.connect((host, port)) 
     print 'Sending to server msg {}'.format(tmsg) 
     s.send(tmsg) 
     # s.settimeout(1) 
     try: 
      data = s.recv(size) 
      print 'Received:', data 
      if strl == data: 
       print strl,data 
       countmsg = 0 
       restmsg = '' 
     except (socket.error), e: 
      print e.args,e.message 
      s.close() 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      s.connect((host, port)) 
    s.close() 
    if restmsg: 
     client_to_server([restmsg],host,port,size) 
    return 


client_to_server(messag,host,port,size) 

服務器代碼:

size = 1024 #This has to be bigger than client buf size! 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind((host, port)) 
s.listen(backlog) 
while True: 
     #this is what accepts and creates a P2P dedicated client socket per socket 
     client, address = s.accept() 
     try: 
      data = client.recv(size) 
      while data or 0: 
       print "Client sent {} | Server sending data to client address {}".format(data, address) 
       client.send(data) 
       data = client.recv(size) 
      else: client.close() 
     except (socket.error), e: 
      client.close() 
      print e.args, e.message 

試試吧。這使用相同的套接字。

相關問題