So I am just getting into python and trying out some stuff. To start, I am making a server that does simple stuff like "GET"s stored text, "STORE"s new text over the old stored text, and "TRANSLATE"s lowercase text into uppercase. But I have a few questions. Here is my code so far:
import socket
HOST = '' # Symbolic name meaning the local host
PORT = 24069 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error code: ' + str(msg[0]) + 'Error message: ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(1)
print 'Socket now listening'
while 1:
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
data = conn.recv(1024)
reply = 'OK...' + data
if not data: break
conn.send(data)
conn.close()
s.close()
To start changing text from a client into uppercase, from my other programming knowledge, I assume I'd store the client's text in a variable and then run a function on it to change it to uppercase. Is there such a function in python? Could someone please give me a snippet of how this would look?
And lastly, how would I do something like a GET or STORE in python? My best guess would be:
data = conn.recv(1024)
if data == GET: print text
if data == STORE: text = data #Not sure how to reference the text that the client has entered
Thank you so much for any help! :)
Note to self:
import socket
HOST = '' # Symbolic name meaning the local host
PORT = 24069 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error code: ' + str(msg[0]) + 'Error message: ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(1)
print 'Socket now listening'
# Accept the connection
(conn, addr) = s.accept()
print 'Server: got connection from client ' + addr[0] + ':' + str(addr[1])
storedText = 'Hiya!'
while 1:
data = conn.recv(1024)
tokens = data.split(' ', 1)
command = tokens[0]
if command == 'GET':
print addr[0] + ':' + str(addr[1]) + ' sends GET'
reply = storedText
elif command == 'STORE':
print addr[0] + ':' + str(addr[1]) + ' sends STORE'
storedText = tokens[0]
reply = '200 OK\n' + storedText
elif command == 'TRANSLATE':
print addr[0] + ':' + str(addr[1]) + ' sends TRANSLATE'
storedText = storedText.upper()
reply = storedText
elif command == 'EXIT':
print addr[0] + ':' + str(addr[1]) + ' sends EXIT'
conn.send('200 OK')
break
else:
reply = '400 Command not valid.'
# Send reply
conn.send(reply)
conn.close()
s.close()
I see that you're quite new to Python. You can try to find some code example, and you should also learn how to interpret the error message. The error message will give you the line number where you should look at. You should consider that line or previous line, as the error may be caused by previous mistakes.
Anyway, after your edits, do you still have indentation error?
On your real question, first, the concept.
To run client/server, you'll need two scripts: one as the client and one as the server.
On the server, the script will just need to bind to a socket and listen to that connection, receive data, process the data and then return the result. This is what you've done correctly, except that you just need to process the data before sending response.
For starter, you don't need to include the accept in the while loop, just accept one connection, then stay with it until client closes.
So you might do something like this in the server:
# Accept the connection once (for starter)
(conn, addr) = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
stored_data = ''
while True:
# RECEIVE DATA
data = conn.recv(1024)
# PROCESS DATA
tokens = data.split(' ',1) # Split by space at most once
command = tokens[0] # The first token is the command
if command=='GET': # The client requests the data
reply = stored_data # Return the stored data
elif command=='STORE': # The client want to store data
stored_data = tokens[1] # Get the data as second token, save it
reply = 'OK' # Acknowledge that we have stored the data
elif command=='TRANSLATE': # Client wants to translate
stored_data = stored_data.upper() # Convert to upper case
reply = stored_data # Reply with the converted data
elif command=='QUIT': # Client is done
conn.send('Quit') # Acknowledge
break # Quit the loop
else:
reply = 'Unknown command'
# SEND REPLY
conn.send(reply)
conn.close() # When we are out of the loop, we're done, close
and in the client:
import socket
HOST = '' # Symbolic name meaning the local host
PORT = 24069 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
while True:
command = raw_input('Enter your command: ')
if command.split(' ',1)[0]=='STORE':
while True:
additional_text = raw_input()
command = command+'\n'+additional_text
if additional_text=='.':
break
s.send(command)
reply = s.recv(1024)
if reply=='Quit':
break
print reply
Sample run (first run the server, then run the client) on client console:
Enter your command: STORE this is a text
OK
Enter your command: GET
this is a text
Enter your command: TRANSLATE
THIS IS A TEXT
Enter your command: GET
THIS IS A TEXT
Enter your command: QUIT
I hope you can continue from there.
Another important point is that, you're using TCP (socket.SOCK_STREAM), so you can actually retain the connection after accepting it with s.accept(), and you should only close it when you have accomplished the task on that connection (accepting new connection has its overhead). Your current code will only be able to handle single client. But, I think for starter, this is good enough. After you've confident with this, you can try to handle more clients by using threading.
Related
I'm building a tcp/ip server in python that works with clients.
Each client gets its own thread and its socket is added to a list called client_list.
there also is a variable "clients_connected" which stores the amount of connected clients.
for some reason it just works with one client at the moment.
Also when a client disconnects, it should be removed from client_list but I'm not sure how to do that.
Could you take a look at the code please? thanks a lot!
this thread is looking for incoming connections:
def addclientsthread(sock):
global client_list
conn, addr = sock.accept()
client_list += [conn]
print_line('Client connected on ' + addr[0] + "\n")
start_new_thread(clientthread, (conn,))
So when a client connects it gets its own "clientthread"
def clientthread(conn):
# handling connections.
global clients_connected
while True:
# Receiving from client
in_data = conn.recv(1024)
data = decrypt(in_data)
if data.lower().find("id=-1") != -1:
clients_connected += 1
print_line("new client ID set to " + str(clients_connected) + "\n")
crypted_msg = encrypt("SID=" + str(clients_connected))
conn.sendall(crypted_msg)
pass
elif data.lower().find("uin") == 0:
uin_id = int(data[4:])
clients_connected -= 1
break
else:
print_line(data)
if not data:
break
# If client disconnects
conn.close()
Oh and please don't hate, I just started coding :)
EDIT: This is the main code (not in a thread)
HOST = ''
PORT = 8820
clients_connected = 0
client_list = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
# Bind socket to host and port
try:
s.bind((HOST, PORT))
except socket.error, msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket successfully binded'
# Start listening on socket
s.listen(100000)
print 'Socket is listening'
start_new_thread(addclientsthread, (s,))
I'm new to sockets. I've written a simple 'proxy' server in Python that will just catch the data from the remote server and send it to my client (browser). I was wondering: is there a way to send the response_text without a time.sleep? While i try to delete time.sleep(0.5) I only get one package of data from the remote server so the 'Content-lenght' isn't equal to the length of the package and I get an error (I'm using recv() to get a buffer with size equaled to buffer_size, so if the server data needs more then one package of 4096 bytes I need to catch it in the next package). With the time.sleep i get all the packages of data from the remote server and I can send the data to my browser. Am I doing something wrong? Or I just don't know enough? Can someone help?
The code:
# coding: utf-8
import socket
import sys
import time
from thread import *
max_conn = 5
buffer_size = 4096
def proxy_server(webserver, port, conn, addr, data):
try:
remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_sock.connect((webserver, port))
remote_sock.send(data)
response_text = ''
while True:
time.sleep(0.5)
response = remote_sock.recv(buffer_size)
response_text += response
if len(response) < buffer_size:
remote_sock.close()
break
conn.sendall(response_text)
conn.close()
except socket.error, msg:
print 'Proccessing error. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
remote_sock.close()
conn.close()
sys.exit()
def conn_string(conn, data, address):
header = data.split('\r\n')
method, address, protocol = header[0].split(' ')
host_key, host_value = header[1].split(': ')
proxy_server(host_value, 80, conn, address, data)
def start():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 8001))
sock.listen(max_conn)
print 'Proxy: on'
except socket.error, msg:
print 'Failed creating a socket. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
sys.exit()
while True:
try:
connection, address = sock.accept()
data = connection.recv(buffer_size)
# start_new_thread(conn_string, (connection, data, address))
conn_string(connection, data, address)
except KeyboardInterrupt:
sock.close()
print "Socket closed"
sys.exit()
if __name__ == "__main__":
start()
Don't use time.sleep() , it makes your proxy very slow , and its not efficient .
You need to set your socket in non-blocking mode , with a timeout .
You can do this with socket.settimeout()
I made a few modifications to your proxy_server , it should be much faster now .
def proxy_server(webserver, port, conn, addr, data):
try:
remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_sock.connect((webserver, port))
remote_sock.send(data)
remote_sock.settimeout(0.5)
response_text = ''
while True:
try :
response = remote_sock.recv(buffer_size)
if len(response) == 0:
break
except :
break
response_text += response
conn.sendall(response_text)
except socket.error, msg:
if str(msg) != 'timed out' :
print 'Proccessing error. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
remote_sock.close()
conn.close()
The rest of your code is quite ok , but you may want to use multithreading
if you want to handle multiple clients at the same time .
is their a function that i can check if there is incoming connection or not to the server ( inside While Loop )?
import socket
import sys
HOST = ''
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10)
print 'Socket now listening'
while 1:
##### IF there is request to server Do #####
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
data = conn.recv(1024)
reply = 'OK...' + data
conn.sendall(reply)
##### Else Do something else like print for example #####
print 'Nothing yet'
conn.close()
s.close()
what i want to do is to check if there is no request to my server i will do something else.
is it possible to do that?
Yes, there's a such function.
From man accept:
In order to be notified of incoming connections on a socket, you can
use select(2), poll(2), or epoll(7). A readable event will be
delivered when a new connection is attempted and you may then call
accept() to get a socket for that connection.
In python you can use select combined with the timeout parameter:
import select
# somewhere in a while loop
timeout = 0
incoming_connections, _, __ = select.select([s], [], [], timeout)
if incoming_connections:
conn, addr = s.accept()
...
else:
...
I can send messages in the form of strings but I cannot send integers to the server.
What I have done is this:
import socket #for sockets
import sys #for exit
try:
#create an AF_INET, STREAM socket (TCP)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sys.exit();
print 'Socket Created'
host = 'localhost'
port = 6000
try:
remote_ip = socket.gethostbyname( host )
except socket.gaierror:
#could not resolve
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Ip address of ' + host + ' is ' + remote_ip
#Connect to remote server
s.connect((remote_ip , port))
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
nb = input('Choose a number')
print ('Number%s \n' % (nb))
#Send some data to remote server
#message = nb
try :
#Set the whole string
s.send(mySocket, nb, sizeof(int),0);
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
print 'Message send successfully'
you can use int() and str() function for convert integer to string and send it
and in other side with int() function convert it to integer
look at these links
http://docs.python.org/2/library/functions.html#int
http://docs.python.org/2/library/functions.html#str
In the code shown below I am using the blocking call to receive 50 bytes of data from socket and echo it back.But what is happening is that the code stuck after receiving one byte.In the telnet running on another command prompt the connection still shows as connected. What might be missing from this ?
import socket
import sys
host = ''
port = 8888
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
print 'Socket Bind Complete'
s.listen(10)
print 'Now Listening'
while 1:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
The problem is that you're accepting a new connection each time through the loop, and only receiving from that connection once. The next time through the loop, your forget about that connection and accept a new one, which blocks until someone else connects.
If you just want to handle a single connection and quit, just move the accept outside the loop:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle one connection at a time, but then wait for a new connection after you finish with the first, add an outer loop.
while True:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle more than one connection at a time, as most servers do, you need some sort of asynchronous mechanism—select and nonblocking sockets, gevent, threads, whatever. For example:
def handle_client(conn, addr):
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
client_threads = []
try:
while True:
conn, adr = s.accept()
client_thread = threading.Thread(target=handle_client, args=[conn, addr])
client_thread.start()
client_threads.append(client_thread)
finally:
s.close()
for client_thread in client_threads:
client_thread.join()
In any of these designs, you're probably better off using a with statement instead of explicit close calls and/or try/finally.