Python:通过套接字发送带有一些消息的文件

时间:2016-01-13 11:43:24

标签: python multithreading sockets

我有一个使用python socket的客户端服务器脚本,客户端读取文件并通过套接字发送它。它一直有效,直到我在传输文件后尝试从服务器向客户端发送内容。即,在服务器接收到文件之后,它发送一条消息" File Received" 服务器也使用Threading(以容纳并发客户端)

这是服务器脚本:

#!/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 +++

1 个答案:

答案 0 :(得分:2)

默认情况下,套接字被创建为阻止(请参阅官方文档中的this note)。

因此在服务器中行

data = self.sock.recv(1024)

在客户端完成文件块的发送后无限期地阻塞。

然后,客户端继续从服务器接收回复内容,两者最终陷入僵局。

在服务器代码中,一种解决方案是使用

将套接字设置为非阻塞

socket.setblocking(flag)

或使用

设置超时

socket.settimeout(value)

另请参阅此SO Q&A