python - 在 Python 中通过套接字传输文本文件

标签 python sockets

我在 PYTHON 中有一个项目,有两台机器(A,B), 1)请求机器A向B发送请求以列出目录(在我的代码中我将其设置为当前目录) 2)在第二个请求中,机器A想要下载该目录的文本文件。 (在B机的目录下放入一个文本文件) 3)机器A修改文本文件后发送回机器B。 4)最后机器A发送两个数字,机器B发回结果。 它一直有效到第 2 步,但之后什么也没有发生,就像真实的一样,而我不明白为什么?! 这是我的代码 机器A(客户端):

# -*- coding: UTF-8 -*-
import os
import socket
PORT = 9000
HOST = 'localhost'
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect((HOST, PORT))
store=[]
direc = raw_input("Enter The Directory to List : ")
socket.sendall(direc)
len_data = socket.recv(2048)
print int(len_data)
for i in range(int(len_data)):
    data = socket.recv(2048)
    store.append(data)
print("List of Files:")
for i in store:
    print(i)
txt_file = raw_input("Please Choose a TEXT file :")
if store.count(txt_file) is 0:
    print("There no such a TXT file!!")
else:
    socket.sendall(txt_file)

def write_file(name):
    fname = open(name,'ab')
    while True:
        string = socket.recv(2048)
        if string:
            fname.write(string)
        else:
            fname.write("changed")
            fname.close()
            break
def read_file(name):
    fileToSend = open(name, 'rb')
    while True:
        data = fileToSend.readline()
        if data:
            socket.send(data)
        else:
            fileToSend.close()
            break

write_file(txt_file)
read_file(txt_file)
x = raw_input("Enter The First Num: ")
socket.send(x)
y = raw_input("Enter The Second Num: ")
socket.send(y)
result = socket.recv(1024)
print result
raw_input()
socket.sendall('')
socket.close()
exit()

和机器 B(服务器):

import os,sys,socket
PORT = 9000
HOST = 'localhost'
tcpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (HOST, PORT)
print >>sys.stderr, 'starting up on %s port %s' % server_address
socket.bind((HOST,PORT))
socket.listen(1)
conn, addr = socket.accept()
directory = conn.recv(2048)
if os.listdir(os.curdir):
    data = os.listdir(os.curdir)
len_data = data.__len__()
print(len_data)
if len_data:
        conn.send(str(len_data))
for i in data:
    if i:
        print >>sys.stderr, 'sending data back to the client'
        conn.send(i)
    else:
        break
txt_file_name = conn.recv(2048)
def write_file(name):
    with open(name,'wb') as fname:
        while True:
            string = conn.recv(2048)
            if string:
                fname.write(string)
            else:
                fname.close()
                break
def read_file(name):
    with open(name, 'rb') as fileToSend:
        while True:
            data = fileToSend.readline()
            if data:
                conn.send(data)
            else:
                fileToSend.close()
                break

def add (x,y):
    return str(x+y)

read_file(txt_file_name)
write_file(txt_file_name)

x = conn.recv(1024)
y = conn.recv(1024)
conn.send(add(x,y))
conn.sendall('')
conn.close()
exit()

最佳答案

我对你的问题很着迷并进行了调查。虽然我们可以使用socket来解决它。我倾向于 HTTP 协议(protocol)有几个原因:

  • 您不必自己编写“握手”。 HTTP 协议(protocol)提供了请求文件、上传文件和进行一些处理(您的步骤 #4)
  • 您可以使用网络浏览器测试您的服务器
  • 网络服务现在非常流行。这是了解网络服务的一小步。

这是服务器代码(server.py):

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import os

class MyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        global running
        if self.path == '/':
            self.list_files()
        elif self.path.startswith('/calculation'):
            self.send_calculation()
        elif self.path.startswith('/quit'):
            self.send_response(200)
            running = False
        else:
            self.send_file(self.path[1:])

    def do_POST(self):
        filename = self.path[1:] # Remove the / from the path
        filesize = int(self.headers['Content-Length'])
        contents = self.rfile.read(filesize)

        with open(filename, 'w') as f:
            f.write(contents.decode())

        self.send_response(200)

    def send_file(self, filename):
        # Check to see if file exists and is a file, not directory
        if os.path.isfile(filename):
            self.send_response(200)
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()

            # Read and send the contents of the file
            with open(filename) as f:
                contents = f.read()
            self.wfile.write(contents)
        else:
            self.send_response(404)
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()
            self.wfile.write('Dude! File not found')

    def send_calculation(self):
        empty, operation, number1, number2 = self.path.split('/')
        result = int(number1) + int(number2)
        self.send_response(200)
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()
        self.wfile.write(result)

    def list_files(self):
        file_list = os.listdir(os.curdir)
        if file_list:
            self.send_response(200)
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()
            for filename in file_list:
                self.wfile.write('{}\n'.format(filename))

#
# Main
#
running = True
server = HTTPServer(('', 9000), MyHandler)
print 'Server started on host:{}, port:{}'.format(*server.server_address)
while running:
    server.handle_request()

这是客户端代码(client.py):

import urllib2
import urlparse

def make_url(server, port, path, scheme='http'):
    netloc = '{}:{}'.format(server, port)
    url = urlparse.urlunsplit((scheme, netloc, path, '', ''))
    return url

#
# Main
#
server = '10.0.0.5'
port = 9000

# 1 - Request directory listing
url = make_url(server, port, '/')
file_list = urllib2.urlopen(url).read()
print 'Files from server:'
for filename in file_list.splitlines():
    print '- {}'.format(filename)

# 2 - Request contents of a file
filename = raw_input('Type a file name: ')
url = make_url(server, port, filename)
contents = urllib2.urlopen(url).read()
print 'Contents:'
print contents

# 3 - Upload a file to the server
contents = 'hello, world.\nThe End'
filename = 'foo.txt'
url = make_url(server, port, filename)
f = urllib2.urlopen(url, data=contents)

# 4 - Do some calculation
n1 = 19
n2 = 5
path = '/calculation/{}/{}'.format(n1, n2)
url = make_url(server, port, path)
result = int(urllib2.urlopen(url).read())
print '{} + {} = {}'.format(n1, n2, result)

# Send quit signal

url = make_url(server, port, '/quit')
urllib2.urlopen(url).read()

网络服务

服务器实际上是一个Web服务,它提供以下服务:

获取目录列表

GET http://server:port/

此服务将返回当前目录中的文件列表。

获取文件内容

GET http://server:port/filename

以纯文本格式返回文件的内容。

上传文件

POST http://server:port/filename

将文件从客户端复制到服务器。如果该文件已存在于服务器上,则覆盖它。

做一些计算

GET http://server:port/calculation/x/y

返回 x + y

关闭服务器

GET http://server:port/quit

告诉服务器退出。

错误处理

为了简洁明了,我没有在代码中添加错误处理。以下是我能想到的一些错误情况:

  • 检索不存在的文件或目录(服务器)
  • 由于缺少文件写入权限(服务器),上传失败
  • 在计算服务中,参数不是数字(服务器)
  • 服务器未启动、端口错误、服务器(客户端)错误

其他讨论

  • 一般来说,GET 表示数据从服务器流向客户端,POST 表示相反的方向。
  • 要测试来自服务器的 GET 操作,您可以使用浏览器。例如,要从 192.168.1.5、端口 9000 检索目录内容,请将 Web 浏览器指向:

    http://192.168.1.5:900/  
    
  • 测试 POST 比较棘手,请参阅上传部分中的客户端代码以了解使用 POST 的想法。

  • 在服务器代码中,do_GET() 函数处理所有 GET 请求,do_POST() 函数处理所有 POST 请求。

关于python - 在 Python 中通过套接字传输文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20560805/

相关文章:

c - TCP监听并在监听的同时做其他事情

Java服务器客户端绑定(bind)错误

node.js - 在 Node.js 中获取套接字描述符

Python 套接字无法正确关闭连接

python - 如何从输入行中提取两个数字并用制表符分隔它们?

python - numpy.memmap 无法处理非常大的数据

python - python3 和 pip 的问题

python - 使用 python 编码从 Excel 读取字符串的缺点 ('utf-8' )

python - 如何解决此错误 : AttributeError: 'NoneType' object has no attribute 'write_audiofile'

java - 我怎样才能摆脱 "white spaces"