2016-01-13 151 views
2

我有一個客戶端服務器腳本使用python socket,其中客戶端讀取一個文件並通過套接字發送它。它一直運行到我嘗試在文件傳輸完成後從服務器發送到客戶端。即服務器收到文件後,它發出了一個信息,即「收到文件」 服務器也使用Threading(以適應併發客戶端)Python:通過套接字發送文件與一些消息

這裏的服務器腳本:

#!/usr/bin/python 
import socket 
from threading import Thread 
from SocketServer import ThreadingMixIn 

HOST = '192.168.56.106' 
TCP_PORT = 60001 
BUFFER_SIZE = 1024 


class ClientThread(Thread): 

    def __init__(self, ip, port, sock): 
     Thread.__init__(self) 
     self.ip = ip 
     self.port = port 
     self.sock = sock 

    def run(self): 
     filename = 'mytext.txt' 
     f = open(filename, 'wb') 
     while True: 
      data = self.sock.recv(1024) 
      if not data: 
       f.close() 
       # self.sock.close() 
       break 
      f.write(data) 
     self.sock.sendall("File received") 
     self.sock.close() 


tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
tcpsock.bind((HOST, TCP_PORT)) 
threads = [] 

while True: 
    tcpsock.listen(5) 
    (conn, (ip, port)) = tcpsock.accept() 
    newthread = ClientThread(ip, port, conn) 
    newthread.start() 
    threads.append(newthread) 

for t in threads: 
    t.join() 

和客戶端腳本:

#!/usr/bin/python 
import socket 

# TCP_IP = 'localhost' 
HOST = '192.168.56.106' 
TCP_PORT = 60001 

BUFFER_SIZE = 1024 

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
socket.connect((HOST, TCP_PORT)) 

filename='/tmp/f' 
f = open(filename, 'rb') 

while True: 
    chunk = f.read(BUFFER_SIZE) 
    if not chunk: 
     print "File transfer completed" 
     f.close() 
     break 
    socket.send(chunk) 

c = socket.recv(BUFFER_SIZE) 
print c 
socket.close() 
print('connection closed') 

它們都顯然卡在recevfrom()等待另一端發送數據。

# strace -f -e network ./server.py 
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 
bind(3, {sa_family=AF_INET, sin_port=htons(60001), sin_addr=inet_addr("192.168.56.106")}, 16) = 0 
listen(3, 5)       = 0 
accept(3, {sa_family=AF_INET, sin_port=htons(49045), sin_addr=inet_addr("192.168.56.106")}, [16]) = 4 
Process 4537 attached 
[pid 4532] listen(3, 5)    = 0 
[pid 4532] accept(3, <unfinished ...> 
[pid 4537] recvfrom(4, "This is test file\n", 1024, 0, NULL, NULL) = 18 
[pid 4537] recvfrom(4, 


# strace -e network ./client.py 
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 
connect(3, {sa_family=AF_INET, sin_port=htons(60001), sin_addr=inet_addr("192.168.56.106")}, 16) = 0 
sendto(3, "This is test file\n", 18, 0, NULL, 0) = 18 
File transfer completed 
recvfrom(3, 

編輯: 作爲建議的Pynchia,設置超時固定它,這裏的工作片段。

while True: 
    tcpsock.listen(5) 
    (conn, (ip, port)) = tcpsock.accept() 
    conn.settimeout(2) 
    newthread = ClientThread(ip, port, conn) 
    newthread.start() 
    threads.append(newthread) 

....

def run(self): 
     filename = 'mytext.txt' 
     f = open(filename, 'wb') 
     while True: 
      try: 
       data = self.sock.recv(1024) 
      except timeout: 
       pass 
      if not data: 
       f.close() 
       # self.sock.close() 
       break 
      f.write(data) 
      self.sock.sendall("File received") 
     self.sock.close() 

工作就像一個魅力。當然,上面的超時異常處理需要更多的調整(至少我現在知道在哪裏尋找)。

# strace -f -e network ./server.py 
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 
bind(3, {sa_family=AF_INET, sin_port=htons(60001), sin_addr=inet_addr("192.168.56.106")}, 16) = 0 
listen(3, 5)       = 0 
accept(3, {sa_family=AF_INET, sin_port=htons(49566), sin_addr=inet_addr("192.168.56.106")}, [16]) = 4 
Process 13161 attached 
[pid 13156] listen(3, 5)    = 0 
[pid 13156] accept(3, <unfinished ...> 
[pid 13161] recvfrom(4, "Hello 124\nThis is test file\n</em"..., 1024, 0, NULL, NULL) = 37 
[pid 13161] sendto(4, "File received", 13, 0, NULL, 0) = 13 
[pid 13161] recvfrom(4, "", 1024, 0, NULL, NULL) = 0 
[pid 13161] +++ exited with 0 +++ 

回答

2

默認情況下套接字作爲阻塞(參見官方文檔this note)創建的。

因此在服務器

data = self.sock.recv(1024) 

塊無限期當客戶端完成發送文件塊就行了。

而且由於客戶端繼續從服務器接收回來的東西,兩者最終陷入死鎖。

在服務器代碼,一種解決方案是使用

socket.setblocking(flag)

設置套接字到非阻隔或設置使用

socket.settimeout(value)

請參見本SO Q&A

超時
+0

謝謝,確實設置了超時工作。 – Mardanian