I am writing a very simple Python socket program to read an HTML body from the server. If I create a HelloWorld.html file and open it with the designated host and port, I can open the file in my browser with the following server and read the message in the HTML file. However, I am having trouble reading in the same information from my client.
Server
from socket import *
serverSocket = socket(AF_INET,SOCK_STREAM)
host = '127.0.0.1'
port = 6789
serverSocket.bind((host,port))
serverSocket.listen(5)
print("server started...")
(connectionSocket, addr) = serverSocket.accept()
try:
message = connectionSocket.recv(1024).decode()
filename = message.split()[1]
f = open(filename[1:]) # Throws IOError if file not found
print(filename, "found")
connectionSocket.send("HTTP/1.0 200 OK\r\n".encode())
connectionSocket.send("Content-Type: text/html\r\n".encode())
connectionSocket.send(message.encode())
outputdata = f.read()
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
connectionSocket.close()
print(filename, "delivered")
except IOError:
print(filename, "NOT found")
connectionSocket.send('HTTP/1.0 404 NOT FOUND\r\n')
connectionSocket.close()
print("file not found message delivered")
serverSocket.close()
print("server closed...")
My server seems to be working. However, when my client tries to send the HTML object path to the socket and have the server read it, it does not seem to be picking up the message. I have just started socket programming in Python and I am trying to understand how the server receives the message from the socket. My initial thought was if I send the path of the HTML object (located in same directory as client and server) to the socket, the server should be able to read that information, open it, and return the information to the client.
Client
from socket import *
import sys
client = socket(AF_INET, SOCK_STREAM)
host = sys.argv[1]
port = sys.argv[2]
obj = sys.argv[3]
port = int(port)
client.connect((host, port))
print(client.getsockname())
request = obj
client.send("hello".encode())
client.send(request.encode())
s = client.recv(1024).decode()
print(s)
For my client, I accept the host,port, and the path to the HTML from a commandline argument and establish a connection.
When I run the browser for my HTML file with the url http://127.0.0.1:6789/HelloWorld.html, the server responds well. However, when I run the server and run the client with the command py capClient.py 127.0.0.1 6789 HelloWorld.html on the shell, it returns the filename = message.split()[1] IndexError: list index out of range error. I am assuming that this problem is coming from the server not being able to split the message coming in from the connectionSocket as an acceptable HTML object path.
What are some tips on modifying the client code to receive HTML file from servers?
This trouble is because you await message string is 'hello HelloWorld.html', but it is 'helloHelloWorld.html' and split() get you list ['helloHelloWorld.html'] where index 1 not exists.
f = open(filename[1:])
# must be replaced with [1:] give you a list, not string
f = open(filename)
# there needs encode()
connectionSocket.send('HTTP/1.0 404 NOT FOUND\r\n'.encode())
Related
Im having trouble getting my very basic and simple TCP Server to properly work with http requests. This is what I have so far
from socket import *
import sys
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', 4567))
serverSocket.listen(1)
while True:
print('Ready to serve...')
connectionSocket, addr = serverSocket.accept()
print("connected from: ", addr)
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
connectionSocket.send("HTTP/1.1 200 OK\r\n")
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
connectionSocket.close()
except IOError:
connectionSocket.send("file not found")
serverSocket.close()
sys.exit()
The error comes from the open statement. I dont fully understand how this line of code's return value is organized.
message = connectionSocket.recv(1024)
I know that the return value is in bytes but when I try to use a fuction to turn it into a string like decode() i get errors as well
I have the .py file and the html file sitting in the same directory on my local machine and the way I test this is I just run this and open up a browser and type in
http://127.0.0.1:4567/helloworld.html
My code then promptly crashes after receiving the HTTP request.
Any and all help will be greatly appreciated!
There are numerous problems with your code and since you don't state what specific issues you are concerned about, here is what I see:
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
That appears to send a newline after every character you send back to the client.
Also, it doesn't deal with the client disconnecting because you're sending back invalid data.
Even if what you were trying to do didn't have these errors in it, you don't appear to be attempting to send back a valid http response.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
I have a homework assignment which involves implementing a proxy cache server in Python. The idea is to write the web pages I access to temporary files on my local machine and then access them as requests come in if they are stored. Right now the code looks like this:
from socket import *
import sys
def main():
#Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM) #Initializing socket
tcpSerSock.bind(("", 8030)) #Binding socket to port
tcpSerSock.listen(5) #Listening for page requests
while True:
#Start receiving data from the client
print 'Ready to serve...'
tcpCliSock, addr = tcpSerSock.accept()
print 'Received a connection from:', addr
message = tcpCliSock.recv(1024)
print message
#Extract the filename from the given message
print message.split()[1]
filename = message.split()[1].partition("/")[2]
print filename
fileExist = "false"
filetouse = "/" + filename
print filetouse
try: #Check whether the file exists in the cache
f = open(filetouse[1:], "r")
outputdata = f.readlines()
fileExist = "true"
#ProxyServer finds a cache hit and generates a response message
tcpCliSock.send("HTTP/1.0 200 OK\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
for data in outputdata:
tcpCliSock.send(data)
print 'Read from cache'
except IOError: #Error handling for file not found in cache
if fileExist == "false":
c = socket(AF_INET, SOCK_STREAM) #Create a socket on the proxyserver
hostn = filename.replace("www.","",1)
print hostn
try:
c.connect((hostn, 80)) #https://docs.python.org/2/library/socket.html
# Create a temporary file on this socket and ask port 80 for
# the file requested by the client
fileobj = c.makefile('r', 0)
fileobj.write("GET " + "http://" + filename + "HTTP/1.0\r\n")
# Read the response into buffer
buffr = fileobj.readlines()
# Create a new file in the cache for the requested file.
# Also send the response in the buffer to client socket and the
# corresponding file in the cache
tmpFile = open(filename,"wb")
for data in buffr:
tmpFile.write(data)
tcpCliSock.send(data)
except:
print "Illegal request"
else: #File not found
print "404: File Not Found"
tcpCliSock.close() #Close the client and the server sockets
main()
To test my code, I run the proxy cache on my localhost and set my browser proxy settings accordingly like so
However, when I run this code and try to access google with Chrome, I'm greeting with an error page saying err_empty_response.
Stepping through the code with the debugger made me realizing it's failing on this line
c.connect((hostn, 80))
and I have no idea why. Any help would be greatly appreciated.
P.S. I'm testing this with Google Chrome, Python 2.7, and Windows 10
You cannot use a name on connect. Connect expects an IP address to connect to.
You can get the socket information you need to build the connection using getaddrinfo(). In my pure-python-whois package I used the following code to create a connection:
def _openconn(self, server, timeout, port=None):
port = port if port else 'nicname'
try:
for srv in socket.getaddrinfo(server, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG):
af, socktype, proto, _, sa = srv
try:
c = socket.socket(af, socktype, proto)
except socket.error:
c = None
continue
try:
if self.source_addr:
c.bind(self.source_addr)
c.settimeout(timeout)
c.connect(sa)
except socket.error:
c.close()
c = None
continue
break
except socket.gaierror:
return False
return c
Note that this isn't great code because the loop is actually there for nothing instead of using the different alternatives. You should only break the loop once you have established a connection. However, this should work as an illustration for using getaddrinfo()
EDIT:
You are also not cleaning your hostname correctly. I get /www.example.com/ when I try accessing http://www.example.com/ which obviously won't resolve. I'd suggest that you use a regular expression to get the file name for your cache.
We're learning about sockets in Networking and we've been tasked to fill out a template in Python (teacher's using Python2.x while I'm using Python3.x).
# Import socket module
from socket import *
# Create a TCP server socket
#(AF_INET is used for IPv4 protocols)
#(SOCK_STREAM is used for TCP)
serverSocket = socket(AF_INET, SOCK_STREAM)
# Assign a port number
serverPort = 6789
# Bind the socket to server address and server port
serverSocket.bind(('',serverPort))
# Listen to at most 1 connection at a time
serverSocket.listen(1)
# Server should be up and running and listening to the incoming connections
while True:
print ("Ready to serve...")
# Set up a new connection from the client
connectionSocket, addr = serverSocket.accept()
# If an exception occurs during the execution of try clause
# the rest of the clause is skipped
# If the exception type matches the word after except
# the except clause is executed
try:
# Receive the request message from the client
message = connectionSocket.recv(4096).decode()
# Extract the path of the requested object from the message
# The path is the second part of HTTP header, identified by [1]
filename = message.split()[1]
# Because the extracted path of the HTTP request includes
# a character '\', we read the path from the second character
f = open(filename[1:])
# Store the entire contenet of the requested file in a temporary buffer
outputdata = f.read()
# Send the HTTP response header line to the connection socket
connectionSocket.send(("HTTP/1.1 200 OK \r\n").encode())
# Send the content of the requested file to the connection socket
for i in range(0, len(outputdata.encode())):
connectionSocket.send(outputdata.encode())
connectionSocket.send(("\r\n").encode())
# Close the client connection socket
connectionSocket.close()
break
except IOError:
# Send HTTP response message for file not found
connectionSocket.send(("HTTP/1.1 404 NOT FOUND\r\n").encode())
connectionSocket.send(("<html><head></head><body><h1>ERROR. TRY AGAIN</h1></body></html>\r\n").encode())
# Close the client connection socket
connectionSocket.close()
break
#Close the Socket
serverSocket.close()
The file I'm reading into it is a .htm file:
<html><head><title>HTML Test File</title></head><body><h1>Trying to Get This Frickin' Program to Work</h1></body></html>
When I run the program and enter: localhost:6789/TestFile.htm, it prints the file contents over and over and gives me the error message: line 34, indexerror: list index out of range. edit: break takes care of the error message, but file is still being printed over and over
What am I doing wrong?
edit #2: now I'm trying to do the error handling, but it merely states that no data was sent when I type in a file that doesn't exist (i.e. localhost:6789/Test.htm). How do I get the error message to print?
for i in range(0, len(outputdata.encode())):
connectionSocket.send(outputdata.encode())
This code:
encodes the text twice
loops 121 times (which is the length of the file you posted, encoded as ASCII or UTF-8)
sends the entire file each of the 121 times
I have created a proxy server that receives requests, searches for the requested file in its cache. If available it returns the cached file. If file is not available then it will ask the actual server, gets it, stores it in the cache and returns the file to the client.
Following is the code:
from socket import *
import sys
if len(sys.argv) <= 1:
print 'Usage : "python ProxyServer.py server_ip"\n[server_ip : It is the IP Address Of Proxy Server'
sys.exit(2)
# Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind((sys.argv[1], 8888))
tcpSerSock.listen(100)
while 1:
# Strat receiving data from the client
print 'Ready to serve...'
tcpCliSock, addr = tcpSerSock.accept()
print 'Received a connection from:', addr
message = tcpCliSock.recv(1024)
print message
# Extract the filename from the given message
print message.split()[1]
filename = message.split()[1].partition("/")[2]
print filename
fileExist = "false"
filetouse = "/" + filename
print filetouse
try:
# Check wether the file exist in the cache
f = open(filetouse[1:], "r")
outputdata = f.readlines()
fileExist = "true"
# ProxyServer finds a cache hit and generates a response message
tcpCliSock.send("HTTP/1.0 200 OK\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
for i in range(0, len(outputdata)):
tcpCliSock.send(outputdata[i])
print 'Read from cache'
# Error handling for file not found in cache
except IOError:
if fileExist == "false":
# Create a socket on the proxyserver
c = socket(AF_INET, SOCK_STREAM)
hostn = filename.replace("www.","",1)
print hostn
try:
# Connect to the socket to port 80
c.connect((hostn, 80))
# Create a temporary file on this socket and ask port 80 for the file requested by the client
fileobj = c.makefile('r', 0)
fileobj.write("GET "+"http://" + filename + " HTTP/1.0\n\n")
# Read the response into buffer
buff = fileobj.readlines()
# Create a new file in the cache for the requested file. Also send the response in the buffer to client socket and the corresponding file in the cache
tmpFile = open("./" + filename,"wb")
for line in buff:
tmpFile.write(line);
tcpCliSock.send(line);
except:
print "Illegal request"
else:
# HTTP response message for file not found
tcpCliSock.send("HTTP/1.0 404 sendErrorErrorError\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
tcpCliSock.send("\r\n")
# Close the client and the server sockets
tcpCliSock.close()
tcpSerSock.close()
But for every file I request I only get an "illegal request" message printed. There seems to be an issue that the proxy server actually is not able to retrieve the requested file by the client. Can someone tell me where I can improve the code.
This is the first time I am coding in Python so please mention any minor errors.
Your request is illegal. For normal http servers, GET must not contain a URL, but only the path. The rest of your proxy contains also many errors. You probably want to use sendall everywhere you use send. recv can receive less that one message, so you have to handle this case also.
Why do you use the strings "true" and "false" instead of True and False?
There is a security hole, as you can read any file on your computer through your proxy. Reading binary files won't work. You don't close opened files.
I can't seem to figure out why my code can't handle the exception of reporting an error if my web server does not contain a file. In the directory of my server I have the code for it and HelloWorld.html. For other files it should report an error. I'm looking through my code and it would seem that it is reading any file and just saying that its contents are blank without actually throwing an error that the file is not on the server. What is going on here?
#Tasks: Create a socket, bind to a specific address and port, send and receive an HTTP packet.
#Description: Web server should handle one HTTP request at a time. So the serve closes its TCP connection after response.
#Accept and parse the HTTP request, get the requested file from the server (i.e. HelloWorld.html), create a response
#message with the requested file and header lines, then send the response to the client.
#Error handling: If file not found then send HTTP "404 Not Found" Message back to client.
#import socket module: here we are using a low-level networking class from Python
from socket import *
#create the socket that belongs to the server.
#AF_INTET represents the address families and protocols.
#SOCK_STREAM represents the socket type
serverSocket = socket(AF_INET, SOCK_STREAM)
#Prepare a server socket
#Define variable for serverPort; we'll use the one in the helper page of the book
serverPort = 51350
#Define host address
serverHost = ''
#Bind the socket to the local host machine address and port
serverSocket.bind((serverHost, serverPort))
#Listen for TCP connections from the client
serverSocket.listen(1)
#Verify setup for receiving
print 'Server is ready to receive'
while True:
#Establish the connection
print 'Ready to serve...'
#When the server receive a request from the client it must establish a new connectionSocket and begin taking in the data.
connectionSocket, addr = serverSocket.accept()
try:
#Take data from connectionSocket and place in message.
#.recvfrom doesn't work because it expects data and return address variables.
message = connectionSocket.recv(1024)
#uncomment for header information
#print message
#parse the message
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read();
#Send one HTTP header line into socket
connectionSocket.send('HTTP/1.1 200 OK\r\n\r\n')
#Send the content of the requested file to the client
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i])
connectionSocket.close()
except IOError:
#Send response message for file not found
connectionSocket.send('404 Not Found')
connectionSocket.close()
#Close client socket
serverSocket.close()
Perhaps you need "HTTP/1.1 404 Not Found\r\n\r\n" instead of "404 Not Found".
Also, you seem to close serverSocket within the loop, thus next accept() fails.