2011-12-25 39 views
12

Tôi có máy chủ và máy khách python đơn giản.Làm thế nào để giữ một ổ cắm mở cho đến khi khách hàng đóng cửa?

Server:

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() 

Chủ đầu tư:

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() 

Đây là kết quả tôi nhận được:

Server:

>python server.py 
127.0.0.1 wrote: 
hello 

Chủ đầu tư:

>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 

Tôi cũng đã thử trên máy linux. Máy chủ chỉ nhận được một tin nhắn và sau đó tôi nhận được một lỗi trên báo cáo recv của thông điệp thứ hai. Tôi vừa mới bắt đầu học mạng trên python nhưng tôi nghĩ rằng máy chủ đang đóng socket vì lý do nào đó. Làm cách nào để sửa lỗi này?

+0

điều này có thể giúp: http://stackoverflow.com/a/20421867/2290820 – user2290820

Trả lời

20

Một đối tượng MyTcpHandler được tạo ra cho mỗi kết nối, và handle được gọi là để đối phó với khách hàng. Các kết nối được đóng cửa khi handle lợi nhuận, vì vậy bạn phải xử lý các thông tin liên lạc đầy đủ từ các khách hàng trong handle phương pháp:

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()) 

LƯU Ý: recv lợi nhuận '' khi khách hàng đóng kết nối, vì vậy tôi chuyển .strip() sau recv do đó không có báo động giả do khách hàng chỉ gửi không gian trắng.

+0

Cảm ơn câu trả lời – Bruce

1

Tôi sẽ thừa nhận rằng đã nhiều năm kể từ lần cuối tôi sử dụng SocketServer, vì vậy có thể có nhiều cách tiếp cận thành ngữ hơn để giải quyết vấn đề của bạn.

Lưu ý rằng khách hàng của bạn sẽ mở một kết nối và gửi ba bộ dữ liệu và nhận ba bộ dữ liệu. (Hy vọng rằng TCP stack sẽ gửi dữ liệu đệm khi bạn gọi trên socket.)

Máy chủ của bạn đang chờ đợi để xử lý một kết nối khách hàng hoàn toàn, từ đầu đến cuối, khi nó được gọi là từ cơ chế SocketServer gọi lại. Lớp hiện tại của bạn thực hiện một chút IO và sau đó thoát. Bạn chỉ cần mở rộng callback máy chủ của bạn làm nhiều hơn nữa:

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

Cảm ơn câu trả lời – Bruce

1

ĐẾN một vấn đề tương tự ở đây error: [Errno 10053]

Tôi cũng đã cố gắng điều tương tự và có những lỗi tương tự.

Nếu có một mã đơn giản như thế này để chứng minh lỗi này:

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() 

Nếu bạn tạo một đối tượng ổ cắm và amt nó có thể gửi và echo lại từ máy chủ để xem có bao nhiêu nó thu, nếu bạn thay đổi điều đó, nói 1024 đến 102400 (trong mã này); Có nghĩa là các ổ cắm không nên đóng cửa nhưng một lần nữa trong hệ điều hành Windows của tôi, phía máy chủ tiếp tục nghe và in bất kỳ dữ liệu mà khách hàng gửi nhưng ở phía khách hàng bạn nhận được lỗi này;

Tuy nhiên, nếu khách hàng chỉ có thể kết nối một lần và gửi và nhận chỉ một lần thì đó là cách thiết kế được thiết kế. Thử công trình này mà không có bất kỳ lỗi nào:

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 

Tôi không chắc chắn nếu một đối tượng socket chỉ hoạt động một lần để gửi và nhận dữ liệu.

CẬP NHẬT Tôi nghĩ rằng vấn đề là dung lượng trên mỗi ổ cắm máy khách để nhận dữ liệu theo vùng đệm được cố định; Đó là lý do tại sao đoạn mã thứ hai ở trên hoạt động, do đó tạo các ổ cắm kết nối máy khách mới trên máy chủ. Nhưng cách đó rất nhiều ổ cắm sẽ được sử dụng hết.

Thay vào đó, mã sau đã khắc phục sự cố đó bằng cách kiểm tra kích thước đang được sử dụng hết. Nếu nó vượt quá số tiền nhất định, nó sẽ tạo một ổ cắm mới tại máy khách nhưng đảm bảo rằng thông báo được gửi; Trên thực tế vấn đề là với mã máy chủ nhưng cố định nó.

kích thước = 10

Đây là cách nhanh chóng để thử mã. Tôi chắc chắn bạn sẽ hiểu và tối ưu hóa nó cho tốt hơn!

mã khách hàng:

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) 

server Code:

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 

Hãy thử nó ra. Điều này sử dụng cùng một ổ cắm.

Các vấn đề liên quan