I have a code to start a simple socket sever on localhost. However, I want it to display a html page when it is accessed through browser. The html will contain two text fields and submit button. When user enters text in text fields and clicks on submit button, I want the program to read from text fields. How Can I Do That?
The instant answer (I hope so) to your question is in the last section The Answer - and, if I have interpreted your question wrong, let me know in the comment section.
The confusion - You are confusing the fundamentals - to display a html page, you simply need a server (localhost in your case), and the browser will use the HTTP/HTTPS protocol to fetch that content/response/html page. In Python (almost same for other languages) there are two levels of access to network services:
Low-level via sockets.
Higher-level via application level network protocols, like HTTP, FTP, etc.
Sockets - in plain english it is a functionality (interface) provided by the machine's operating system to implement client and server (for the higher-level network protocols) like communication between the processes. These processes can be running on a same machine or both processes on physically apart machines (e.g. requesting a website using browser).
A typical socket client is (asking for the desired html from browser):
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(("localhost", 80))
But to make it work you must already have server running (which will serve the html):
server_sock = socket.socket() # Create a socket object
server_sock.bind((localhost, 80)) # Bind to the port
server_sock.listen(5)
while True:
# lines for whatever we want server to do
The line server_sock.bind((localhost, 80)) has binded (assigned/allocated) the localhost:80 (a socket is basically 'host_name:port_number') to this server_sock i.e. any call/request to localhost:80 will be handled as per the lines in the above while True: block of the code above, can be a text response, HTML, etc.
Typical web scenario - We enter a website name www.google.com (which is resolved into an IP via DNS protocol - a whole another story) and hit enter, we'll get the Google's search homepage in response - Here you're the client, that is entering the website name and hitting enter is technically client_sock.connect('www.google.com', 80), and it only worked because on another (remote) machine/system/host they have server_socket binded and listening i.e.
server_sock.bind('machine's_IP', 80)
server_sock.listen(5)
while True:
#accept connections from outside
(client_socket, address) = server_socket.accept()
# here will be the lines which send us back the Google's
# homepage html as a response to our web request.
To sum-up, servers (webserver in your case) can be implemented using (almost) any programming languages e.g. python or C, etc, but the basis, the lowest layer, exactly where the data is passed between 2 processes whether on the same machine using locahost (loopback) or each process running on physically apart machine/host (typical web scenario ) via the HTTP (TCP) protocol rest upon sockets. Sockets are the fundamental building block from which HTTP, HTTPS, FTP, SMTP protocols (all of these are TCP-type protocols) are defined.
DNS, DHCP, VOIP protocols are UDP protocols but they too are built on top of sockets.
The Answer - To start, create a web_server.py and paste the following code (only to see how it works) and run the file as script i.e. from the file's location run "python
web_server.py" in command prompt/terminal:
#!/usr/bin/env python
import socket
host = 'localhost'
port = 80
server_sock = socket.socket(socket.AF_INET,\
socket.SOCK_STREAM) # Create a socket object
server_sock.bind((host , port)) # Bind to the port
print 'Starting server on', host, port
print 'The Web server URL for this would be http://%s:%d/' % (host, port)
server_sock.listen(5) # Now wait for client connection.
print 'Entering infinite loop; hit CTRL-C to exit'
while True:
# Establish connection with client.
client_sock, (client_host, client_port) = socket.socket.accept()
print 'Got connection from', client_host, client_port
client_sock.recv(1000) # should receive request from client. (GET ....)
client_sock.send('HTTP/1.0 200 OK\n')
client_sock.send('Content-Type: text/html\n')
client_sock.send('\n') # header and body should be separated by additional newline
# you can paste your 2 text field html here in the <body>
client_sock.send("""
<html>
<body>
<h1>Hello World</h1> this is my server!
</body>
</html>
""")
client_sock.close()
P.S. You have to implement a HTTP server (webserver) - which will definitely use the socket interface at the lowest level i.e.
server_sock.bind
server_sock.listen
server_sock.accept
Related
*Before you mark as duplicate please note that I am referencing this similar question found here:
Python Socket Programming - ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
unfortunately but have found anything in that post that provides a solution to my problem.
I am working on a very basic exercise designed to familiarize students with programming related to networks. This particular assignment is a common one as is described as follows:
In this assignment, you will learn the basics of socket programming for TCP connections in Python: how to create a socket, bind it to a specific address and port, as well as send and receive an HTTP packet. You will also learn some basics of HTTP header format. You can only use Python3.
You will develop a web server that handles one HTTP request at a time. Your web server should accept and parse the HTTP request, get the requested file from the server’s file system, create an HTTP response message consisting of the requested file preceded by header lines, and then send the response directly to the client. If the requested file is not present in the server, the server should send an HTTP “404 Not Found” message back to the client.
Part one specification:
Put the attached HTML file (named HelloWorld.html) in the same directory in which the server webserver.py runs. Run the server program. Determine the IP address of the host that is running the server (e.g., 128.238.251.26 or localhost). From another host, open a browser and provide the corresponding URL. For example: http://128.238.251.26:6789/HelloWorld.html. You can open a browser in the same host where the server runs and use the following http://localhost:6789/HelloWorld.html.
‘HelloWorld.html’ is the name of the file you placed in the server directory. Note also the use of the port number after the colon. You need to replace this port number with the port number that was assigned to you. In the above example, we have used port number 6789. The browser should then display the contents of HelloWorld.html. If you omit “:6789”, the browser will assume port 80 (why?), and you will get the web page from the server only if your server is listening at port 80.
Then try to get a file that is not present on the server (e.g., test.html). You should get a “404 File Not Found” message.
Part Two specification:
Write your own HTTP client to test your server. Your client will connect to the server using a TCP connection, send an HTTP request to the server, and display the server response as an output. You can assume that the HTTP request sent is a GET method. The client should take command line arguments specifying the server IP address or hostname, the port at which the server is listening, and the HTTP file name (e.g., test.html or HelloWorld.html). The following is an input command format to run the client. webclient.py <server_host> <server_port>
My code is for the Webserver is as follows:
#import socket module
from socket import *
import sys # In order to terminate the program
serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket
# Fill in start
serverHost = '192.168.1.4'
serverPort = 56014
serverSocket.bind((serverHost, serverPort))
serverSocket.listen(5)
# Fill in end
while True:
#establish connection
print('The server is ready to receive')
connectionSocket, addr = serverSocket.accept() # Fill in start #Fill in end
try:
message = connectionSocket.recv(4096) # Fill in start #Fill in end
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.readlines() # Fill in start #Fill in end
# send one http header line in to the socket
# Fill in start
connectionSocket.send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n")
connectionSocket.send("\r\n")
# Fill in end
# Send the content of the requested file to the connection socket
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
connectionSocket.close()
except IOError:
# Send HTTP response code and message for file not found
# Fill in start
connectionSocket.send("HTTP/1.1 404 Not Found\r\n")
connectionSocket.send("Content-Type: text/html\r\n")
connectionSocket.send("\r\n")
connectionSocket.send("<html><head></head><body><h1>404 Not Found</h1></body></html><\r\n>")
# Fill in end
# Close the client connection socket
# Fill in start
serverSocket.close()
# Fill in end
serverSocket.close()
sys.exit() # Terminate the program after sending the corresponding data
My code for the Webclient is as follows:
from socket import *
import sys
serverName = sys.argv[1]
serverPort = int(sys.argv[2])
fileName = sys.argv[3]
request = "GET "+str(fileName)+" HTTP/1.1"
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
clientSocket.send(request.encode())
returnFromSever = clientSocket.recv(4096)
while(len(returnFromSever)>0):
print(returnFromSever.decode())
returnFromSever = clientSocket.recv(4096)
clientSocket.close()
The error I am receiving is:
"No connection could be made because the target machine actively refused it"
Admittedly, I know almost nothing about network related programming and on top of that I am not familiar with the Python syntax (my entire degree program was exclusively in Java) so I am very lost here and somewhat desperate.
If anyone could please point me in the right direction as far as how to correct this error, I would be very deeply grateful.
Thanks
The error you are getting (No connection could be made because the target machine actively refused it) means that the port you are trying to connect to is not not being listened on the server.
For example, if you try to connect to 192.168.1.1:80 (IP = 192.168.1.1, port=80) and the server on 192.168.1.1 doesn't listen on port 80, you would receive this error.
A few things I would check in your case:
Is your server IP actually 192.168.1.4 ? If not, set it to the correct IP of the interface you want to listen on. If you want to listen on all the interfaces of the server, use this: serverHost = '0.0.0.0'
Does your client code attempt to connect to the server port? The server port is 56014. You need to pass it as the second parameter of your client program (because of this line serverPort = int(sys.argv[2])).
I am trying to learn how to use sockets to send files between pcs on my local network.
I am using ubuntu on my 'server' and my original plan was to create a ufw rule that allows all LAN connections but ask for a password when accepting the socket connection. That way only devices that are really supposed to communicate with the server would be accepted.
I do realise that creating ufw rules for static IPs would be an option but unfortunately I am dealing with dynamic IPs.
I have a text file of allowed keys on my 'server' and a text file containing one authentication key on the 'client'.
The server script looks like this:
#!/usr/bin/env python3
import socket
with open('/path/to/allowedKeys') as f:
allowedKeys = []
for line in f:
allowedKeys.append(line.rstrip('\n'))
HOST = '127.0.0.1' #standard loopback interface address (localhost)
PORT = 9999
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((HOST, PORT))
serversocket.listen()
(clientsocket, address) = serversocket.accept()
with clientsocket:
print('Connected by', address)
while True:
data = clientsocket.recv(1024)
data = data.decode(encoding="utf-8")
print('Received', repr(data))
if data in allowedKeys:
clientsocket.sendall(b'Thank you for logging in.')
clientsocket.shutdown(socket.SHUT_RDWR)
break
else:
clientsocket.sendall(b'Error: Failed authentication')
clientsocket.shutdown(socket.SHUT_RDWR)
break
and the client script looks like this:
#!/usr/bin/env python3
import socket
with open('/path/to/authenticationKey', 'r') as f: #read authenticationKey from textfile
authenticationKey = f.readline().rstrip('\n')
authenticationKey = bytes(authenticationKey, encoding="utf-8") #convert authenticationKey to bytes
#authenticationKey = bytes('wrongKey', encoding="utf-8") #wrong Key for testing
HOST = '127.0.0.1' #server hostname or IP address
PORT = 9999 #port used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(authenticationKey)
data = s.recv(1024)
s.shutdown(socket.SHUT_RDWR)
s.close()
print('Received', repr(data))
When I execute the scripts it looks like everything works as expected.
I get either
Received 'nhjp9NIin987BUHBlkuULK98zJKn98JH'
or
Received 'wrongKey'
and the server shuts down successfully.
I have looked at these two related questions:
socket accept only specific addresses?
Server socket - accept connections only from IP addresses in the whitelist
While I cannot filter by IP it seems as if one must first accept the connection in order to authenticate the client.
I only want devices that possess an allowed key to be able to communicate with the server. All other connections should be shut down.
Since I still have very limited knowledge I would like to know whether this is the way to go or whether this leaves me open to any vulnerabilities.
While I cannot filter by IP it seems as if one must first accept the connection in order to authenticate the client. I only want devices that possess an allowed key ..
Since you want to authenticate a client based on actual data (the key or proof of possession of the key) then you must first have a connection able to transfer the data from the client. With TCP this means that you have to accept the connection.
... whether this leaves me open to any vulnerabilities.
This is the usual way to go but it leaves you open to denial of service attacks. Creating a new connection takes resources, so by opening lots of connections an attacker can exhaust server resources. If all resources are exhausted this way even valid users can no longer access the server. See for example the SYN flood attack.
Depending on the setup of the client additional protections can be added. But these are outside of the python application and mostly out of scope of this question. But to get some ideas see the section about countermeasures in the Wikipedia article.
I have some code that hosts a local server and when a user connects it will send them some html code, which works fine.
But I want it so if they connect to http://localhost:90/abc it will show something different. How can I get the exact url they connected to?
Here is my code:
import socket
sock = socket.socket()
sock.bind(('', 90))
sock.listen(5)
print("Listening...")
while True:
client, address = sock.accept()
print("Connection recieved: ", address)
print(The exact url they connected to.)
print()
client.send(b'HTTP/1.0 200 OK\r\n')
client.send(b"Content-Type: text/html\r\n\r\n")
client.send(b'<html><body><h1>Hello, User!</body></html>')
client.close()
sock.close()
I tried print(client.getpeername()[1]), but that gets the client ip, and if there is a similar way to get the ip they connected to it probably wont get the 'abc' part of the url.
Thanks in advance.
Socket's don't have a notion of URL, that's specific to the HTTP protocol which runs on top of a socket. For this reason, only part of the HTTP URL is even used in the creation of a socket.
|--1---|----2----|-3-|--4-|
http:// localhost :90 /abc
Specifies which protocol inside of TCP the URL uses
Specifies the remote host, either by IP address or hostname
Specifies the remote port and is optional
Specifies the path of the URL
Only parts 2 and 3 are actually known to a TCP socket though! This is because TCP is a very basic form of communication, HTTP adds a bunch of functionality on top of it like requests and responses and paths and so on.
Basically if you're implementing an HTTP server, knowing the /abc part is your job. Take a look at this example. The client actually sends the /abc part to the server, otherwise it has no way of knowing which path the request is for.
When the client connects to your server, it will send:
GET /abc HTTP/1.1
Host: localhost
more headers...
<blank line>
Your server needs to parse the GET line and extract /abc from that.
I have some code trying to receive an email sent from a server on a client. The email is definitively sent from the server to the client, and a SMTP server on the client should be able to receive this email. Here is my test implementation:
# define the SMTP server (with the real IP adress of the client of course)
server = smtpd.PureProxy(('XXX.XXX.XXX.XXX', 25), None)
inputs = [server]
outputs = []
message_queues = {}
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Only one socket in the list returned (there is exactly one)
socket = readable[0]
# Accept the connection or get it or whatever
connection, client_address = socket.accept()
# get the data
data = connection.recv(1024)
print data
After a considerably long time some data is received, which in no way resembles the content of the email. It is always
EHLO YYY.YYY.YYY.YYY
with the YYY the address of the server. I am no expert in SMTP and sockets, but what am I doing wrong to correctly receive the emai and its contents?
Thanks
Alex
The EHLO is part of the SMTP protocol exchange and it represents the client sending its greeting to your server which doesn't respond properly (because it doesn't respond at all). When the client gets tired of waiting for "a considerably long time" the session times out and your server shows what it received.
You seem to be confused as to which process is the server. The smtpd module creates servers or Mail Transport Agents, not clients. As noted in the smtpd documentation for SMTPServer:
Create a new SMTPServer object, which binds to local address
localaddr. It will treat remoteaddr as an upstream SMTP relayer. It
inherits from asyncore.dispatcher, and so will insert itself into
asyncore‘s event loop on instantiation.
You also seem to have the sense of localaddr and remoteaddr confused. The localaddr is not (as your comment claims) the address of the client, but where that server should accept connections from. You might want to try in place of your code:
server = smtpd.DebuggingServer(('localhost', 2525), None)
asyncore.loop()
Which can be tested with client code (in a separate process) of:
client smtplib.SMTP('localhost', 2525)
client.sendmail('from', 'to', 'body')
Finally, having a PureProxy with a remoteaddr of None, it if works at all, would proxy mail into nowhere which is probably not what you want in a proxy.
That is the proper start of the ESMTP protocol dialog. Your program needs to understand and handle at least the basic SMTP verbs; see RFC5321.
I'm trying to build a DNS server in python. It must listen two ports (8007 - client, 8008 - admin). The client only send an URL and receives the respective IP. The admin has permissions to change the DNS table (add, remove,.. doesn't matter to this right now).
So my question is: how do I implement the server listening continuously on the two ports for any eventual request (we can have several clients at the same time but only one admin when he is operating)
my Server with one listening port:
from SocketServer import *
from threading import *
from string import *
import socket
class Server(ForkingMixIn, TCPServer): pass #fork for each client
class Handler(StreamRequestHandler):
def handle(self):
addr = self.request.getpeername()
print 'Got connection from', addr
data=(self.request.recv(1024)).strip()
if data not in dic: #dic -> dictionary with URL:IP
self.wfile.write('0.0.0.0')
else:
self.wfile.write(dic.get(data))
server = Server(('', 8007), Handler)
server.serve_forever()
No need to use threads.
Use twisted.
TwistedNames has support out of the box for a dns server. You can customize it as needed or read its source as base when you build yours.
You can use non-blocking sockets, and use the select call to read from the socket. This Sockets Programming HOWTO for Python article has a section on non-blocking sockets in Python that will help.
See also:
select (Python) | select (UNIX)
socket (Python) | socket (UNIX)