2

I have this following code which is in my server.py file. It is waiting to receive data from the client. Additionally I cannot use any of the http libraries. Only the socket Library:

def handle_client(conn, addr):
    print ('New client from', addr)
    x = []
    try:
        while True:
            data = conn.recv(1024)
            decoded_data = data.decode('utf-8')
            # if "GET / " in data.decode('utf-8'):
            #   handle_client_get(conn)
            # else:
            if data:
                print(data)
                x.append(decoded_data)
            else:
                print(x)
                break
    finally:
        print("in close now")
        conn.close()

The problem I am having is that I can only reach the print(x) statement once I manually CTRL + Cclose the client. Otherwise it doesn't print.

Why is that the case.

ANSWER

You need to send an acknowledgment to the client such that the data sent has been received correctly.

that will terminate the connection and not wait for a timeout.

This is because the client sends: Expect: 100-continue And you need to send an acknowledgment back to the client

11
  • The other side didn't close the socket. You'll only get an empty recv after the receive channel has been shutdown by the other side. Commented Mar 15, 2017 at 16:11
  • but if there is no data getting sent from the client how can I break? Are you saying that even though there is no data getting sent from the client as long as there is a connection, I cannot reach the else statement? Commented Mar 15, 2017 at 16:14
  • You need to define your protocol to get better answers. Is there an expected timeframe for receiving more data? Why does the server keep the connection open if it is finished? Some protocols, eg telnet or ssh, may have no data for minutes or hours but the connection is still valid and there may be more data after the extended period of no data. Commented Mar 15, 2017 at 16:21
  • I am using curl, it is a tcp connection with http protocols. Should I define a content-length? or something else? Commented Mar 15, 2017 at 16:22
  • 1
    An http server, for instance, will send a newline delimited header, a count of data and then the data itself. The client needs to implement this protocol to work properly. Commented Mar 15, 2017 at 16:23

2 Answers 2

1

You need to implement the protocol which will have a means to tell you how much data there is to read. In the case of HTTP, the request starts with a CRLF delimited header, and we can read that to get the information we want.

w3.org has a good description of the http request protocol. Its more complicated than I want to implement here but I've included an example that pulls in the request header by reading the socket one character at a time and looking for an empty \n terminated line. By reading one character at a time, I don't have to implement my own line buffer.

The first line is the request method and the remaining lines are other parameters included with the request. For a POST, for instance, there would be more data still to read from the socket.

import re

def handle_client(conn, addr):
    print ('New client from', addr)
    header = []
    line = []
    try:
        # read ascii http client header. 
        while True:
            c = conn.recv(1)
            # check for early termination
            if not c:
                return None
            # check for end of request line
            elif c == b"\n":
                # make line a string to add to header
                line = ''.join(line).decode('ascii').strip()
                # are we at the empty line signalling end-of-header?
                if not line:
                    break
                header.append(line)
                line = []
            # filter out \r
            elif c == b"\r":
                continue

        # request is first line of header
        request_line = header.pop(0)
        method, uri, http_version = re.split(r" +" request_line)

        if method.upper() == "GET":
            # this function needs more parameters... the uri to get and the protocol
            # version to use.
            handle_client_get(...)
    finally:
        print("in close now")
        conn.close()
Sign up to request clarification or add additional context in comments.

4 Comments

Ok so the client will make a post request sending a file that will contain some ascii characters. I do get all the information but as soon as I get all the information it does not close the connection. It's as if it's stll waiting for more data. That is my problem.
The header will likely contain Transfer-Encoding to tell you whether its ascii or something else, and Content-Length to tell you how many bytes to read. But like all things http, there can be complications. Read section 4.4 Message Length here.
It's something to do with Expect: 100-continue I found what was the problem
Yes, you must implement the protocol! : ) The client will wait after sending the request in order to receive the response from your server. The HTTP specifications tell you how to determine when the client has finished sending the request. As you discovered, the HTTP v1.1 protocol defines that "Expect" header and the client will wait for the expected response before continuing.
0

Edit:
Now that you mention this is a HTTP server and is to be done using only socket library, I suggest you remove certain complex elements from the program at this stage like removing the while block until this problem is solved.

server.py

def handle_client(conn, addr):
    print ('New client from', addr)
    x = []
    try:
        data = conn.recv(1024)
        decoded_data = data.decode('utf-8')
        if data:
            print(data)
            x.append(decoded_data)
        else:
            print(x)
            break
    finally:
        print("in close now")
        conn.close()

Original Answer:

Try sending an additional \n at the sender end and use the flush function later to send out any remaining data on the buffer something like:

sender.py

def send_data(data,sock_obj,addr):
    sock_obj.send(data+"\n")
    sock_obj.flush()

2 Comments

I am using the cURL so I cannot add such details to client that is sending
Don't I need the while loop though, such that I get all the data being sent from the client??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.