0

select() 関数 - I/O 多重化を使用して、Python で Web サーバーを構築しています。私の場合は Web ブラウザー (サファリ、クロム、Firefox) である複数のクライアントに接続し、各クライアントの HTTP 1.1 GET 要求を受け入れることができます。リクエストを受け取ったら、html ページが表示されているブラウザに html ページのコンテンツを返します。

私が得ている問題は、接続をしばらく開いたままにしようとしたときです。fd.close() を使用して接続を閉じるまで、ブラウザーに何も表示できないことに気付きました。

これは、ブラウザのリクエストを受け入れて応答するために使用している関数です。問題は、fd.sendall() を使用した後です。接続を閉じたくないのですが、閉じるまでページが表示されません。助けてください!どんな助けや提案も大歓迎です..

def handleConnectedSocket():
    try:
        recvIsComplete = False
        rcvdStr = ''

        line1 = "HTTP/1.1 200 OK\r\n"
        line2 = "Server: Apache/1.3.12 (Unix)\r\n"
        line3 = "Content-Type: text/html\r\n" # Alternately, "Content-Type: image/jpg\r\n"
        line4 = "\r\n"

        line1PageNotFound = "HTTP/1.1 404 Not Found\r\n"
        ConnectionClose = "Connection: close\r\n"

        while not recvIsComplete:
            rcvdStr = fd.recv( 1024 )

            if rcvdStr!= "" :

# look for the string that contains the html page
                recvIsComplete = True
                RequestedFile = ""
                start = rcvdStr.find('/') + 1 
                end = rcvdStr.find(' ', start)
                RequestedFile = rcvdStr[start:end] #requested page in the form of xyz.html

                try:
                    FiletoRead = file(RequestedFile , 'r')
                except:
                    FiletoRead = file('PageNotFound.html' , 'r')
                    response = FiletoRead.read()
                    request_dict[fd].append(line1PageNotFound + line2 + ConnectionClose + line4) 
                    fd.sendall( line1PageNotFound + line2 + line3 + ConnectionClose + line4 + response )
#                    fd.close()   <--- DONT WANT TO USE THIS
                else:    
                    response = FiletoRead.read()
                    request_dict[fd].append(line1 + line2 + line3 + ConnectionClose + line4 + response)
                    fd.sendall(line1 + line2 + line3 + line4 + response)
#                    fd.close()   <--- DONT WANT TO USE THIS
            else:
                recvIsComplete = True
#Remove messages from dictionary
                del request_dict[fd]    
                fd.close()

クライアント (ブラウザー) 要求は、次に示すように HTTP 1.1 形式です。

GET /Test.html HTTP/1.1
Host: 127.0.0.1:22222
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8) AppleWebKit/536.25 (KHTML, like    Gecko) Version/6.0 Safari/536.25
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
4

1 に答える 1

1

Connection: close接続を閉じることによってデータの送信が完了したら、ブラウザに通知することを示します。あなたはそれをしたくないので、おそらく のように に別の値を使用したいと思うでしょConnectionKeep-Alive。ただし、それを使用する場合は、Content-Lengthデータの送信が完了したことをブラウザーが認識できるように、送信するか、他の何かを行う必要もあります。

Keep-Aliveを使用していない場合でも、Content-Length送信することをお勧めします。これにより、ブラウザーはページのダウンロードの現在の進行状況を知ることができるからです。送信する大きなファイルがあり、送信しないContent-Length場合、ブラウザーは、たとえば進行状況バーを表示できません。Content-Lengthそれを可能にします。

Content-Lengthでは、どのようにヘッダーを送信しますか? 送信するデータのバイト数を数えます。それを文字列に変換し、それを値として使用します。それはとても簡単です。例えば:

# Assuming data is a byte string.
# (If you're dealing with a Unicode string, encode it first.)
content_length_header = "Content-Length: {0}\r\n".format(len(data))

ここに私のために働いているいくつかのコードがあります:

#!/usr/bin/env python3
import time
import socket

data = b'''\
HTTP/1.1 200 OK\r\n\
Connection: keep-alive\r\n\
Content-Type: text/html\r\n\
Content-Length: 6\r\n\
\r\n\
Hello!\
'''


def main(server_address=('0.0.0.0', 8000)):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    server.bind(server_address)
    server.listen(5)
    while True:
        try:
            client, client_address = server.accept()
            handle_request(client, client_address)
        except KeyboardInterrupt:
            break


def handle_request(client, address):
    with client:
        client.sendall(data)
        time.sleep(5)  # Keep the socket open for a bit longer.
        client.shutdown(socket.SHUT_RDWR)


if __name__ == '__main__':
    main()
于 2013-02-06T02:29:45.200 に答える