2017-05-08 165 views
1

我正在嘗試使用Python實現多線程TCP服務器。當我運行下面的代碼我得到了以下錯誤:TCP多線程服務器

錯誤

Incoming message: how are you 
Unhandled exception in thread started by <function client_thread at 0x00000000024499 E8> 
Traceback (most recent call last): 
File "tcp_test2.py", line 32, in client_thread 
message = recv_msg(conn) 
File "tcp_test2.py", line 24, in recv_msg 
raw_msglen = recvall(sock, 4) 
File "tcp_test2.py", line 13, in recvall 
raise EOFError('was expecting %d bytes but only received %d bytes before socket closed' % (length, len(data))) 
EOFError: was expecting 4 bytes but only received 0 bytes before socket closed 

不知道我在哪裏與執行線程功能走錯了。任何幫助將不勝感激。

代碼

import argparse 
import socket 
import struct 
from thread import start_new_thread 

def recvall(sock, length): 
    data = b'' 
    while len(data) < length: 
     packet = sock.recv(length - len(data)) 
     if not packet: 
      raise EOFError('was expecting %d bytes but only received %d bytes before socket closed' % (length, len(data))) 
     data += packet 
    return data 

def send_msg(sock, msg): 
    msg = struct.pack('>I', len(msg)) + msg 
    sock.sendall(msg) 


def recv_msg(sock): 
    raw_msglen = recvall(sock, 4) 
    if not raw_msglen: 
     return None 
    msglen = struct.unpack('>I', raw_msglen)[0] 
    return recvall(sock, msglen) 

def client_thread(conn): 
    while True: 
     message = recv_msg(conn) 
     print('Incoming message: {}'.format(message)) 
     conn.sendall(b'Message Received') #send data to the socket 
    conn.close() #mark the socket closed 
    print('\tReply sent, socket closed') 

服務器

def server(interface, port): 

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.bind((interface, port)) # the socket to address 
    sock.listen(1) #listen for connections made to the socket. 
    while True: 
     conn, sockname = sock.accept() 
     start_new_thread(client_thread,(conn,)) 

    sock.close() 

客戶

def client(host, port): 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((host, port)) 
    print('Client has been assigned socket name', sock.getsockname()) 
    message = raw_input("Type your message: ") 
    send_msg(sock, message) 
    reply = recvall(sock, 16) 
    print('Server Response: {}'.format(reply)) 
    print('\nSocket closed') 
    sock.close() 

if __name__ == '__main__': 
    choices = {'client': client, 'server': server} 
    parser = argparse.ArgumentParser(description='Send and receive over TCP') 
    parser.add_argument('role', choices=choices, help='which role to play') 
    parser.add_argument('host', help='interface the sever listens at:' 'host the client sends to') 
    parser.add_argument('-p', metavar='PORT', type=int, default=1060, help='TCP port(default 1060)') 
    args = parser.parse_args() 
    function = choices[args.role] 
    function(args.host, args.p) 

這是我以前的代碼沒有任何未處理的異常

import argparse 
import socket 
import struct 

def recvall(sock, length): 
    data = b'' 
    while len(data) < length: 
     packet = sock.recv(length - len(data)) 
     if not packet: 
      raise EOFError('was expecting %d bytes but only received %d bytes before socket closed' % (length, len(data))) 
     data += packet 
    return data 

def send_msg(sock, msg): 
    msg = struct.pack('>I', len(msg)) + msg 
    sock.sendall(msg) 


def recv_msg(sock): 
    raw_msglen = recvall(sock, 4) 
    if not raw_msglen: 
     return None 
    msglen = struct.unpack('>I', raw_msglen)[0] 
    return recvall(sock, msglen) 


def server(interface, port): 

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.bind((interface, port)) # the socket to address 
    sock.listen(1) #listen for connections made to the socket. 
    print('Listening at {}'.format(sock.getsockname())) #returns the socket's own address 
    while True: 
     conn, sockname = sock.accept() 
     print('Connection accepted from {}'.format(sockname)) 
     print('\tServer Socket: {}'.format(conn.getsockname())) 
     print('\tClient Socket: {}'.format(conn.getpeername())) # return remote address to which socket is connected 
     message = recv_msg(conn) 
     print('Incoming message: {}'.format(message)) 
     conn.sendall(b'Message Received') #send data to the socket 
     conn.close() #mark the socket closed 
     print('\tReply sent, socket closed') 

def client(host, port): 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((host, port)) 
    print('Client has been assigned socket name', sock.getsockname()) 
    message = raw_input("Type your message: ") 
    send_msg(sock, message) 
    reply = recvall(sock, 16) 
    print('Server Response: {}'.format(reply)) 
    print('\nSocket closed') 
    sock.close() 


if __name__ == '__main__': 
    choices = {'client': client, 'server': server} 
    parser = argparse.ArgumentParser(description='Send and receive over TCP') 
    parser.add_argument('role', choices=choices, help='which role to play') 
    parser.add_argument('host', help='interface the sever listens at:' 'host the client sends to') 
    parser.add_argument('-p', metavar='PORT', type=int, default=1060, help='TCP port(default 1060)') 
    args = parser.parse_args() 
    function = choices[args.role] 
    function(args.host, args.p) 
+0

如果你解釋你期望發生的事情,我可以提供更好的答案。你得到的行爲正是你應該預料到的。 –

回答

1

沒有錯。您的客戶端關閉套接字。服務器在嘗試讀取下一條消息時檢測到此情況。這應該是你所期望的。

+0

感謝您的評論大衛。我只是不明白爲什麼我得到這個代碼未處理的異常。沒有線程函數,我不會得到這個未處理的異常。我只得到客戶發送的理想訊息。我希望能夠清除在服務器上顯示的輸出。 –

+0

你知道你的代碼在正常關閉時會引發EOFError嗎? –

+0

是的我明白,沒有更多的字節發送時會引發EOFError。但是,請你向我解釋爲什麼然後它認爲它是一個未處理的異常? 我發佈了我以前的代碼,沒有任何未處理的異常進行比較。 –