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 .
Related
I make some program to send data from raspberry to pc using socket communication. so I want to make raspberry to keep sending data in every second via socket if my pc send command "RUN". and stop if my pc send command "STOP".
client.py
.
.
.
def setupSocket():
try :
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s,'CONNECT'
except socket.error as msg:
print(msg)
def sendReceive(s, message):
try:
s.send(str.encode(message))
reply = s.recv(1024)
reply = reply.decode('utf-8')
print(reply)
return reply
except:
return 'ERR'
if __name__=='__main__':
s = setupSocket()
while True:
data = sendReceive(s,'GET')
sleep(1)
s.close()
server.py
import socket
from random import randint,random
host = ''
port = 5560
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((socket.gethostname(), 5560))
## s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind comlete.")
return s
def setupConnection():
s.listen(1)
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def getDustData():
data = 'some data'
return str(data)
def GET():
data = getDustData()
reply = 'MSG'+' '+data
return reply
def dataTransfer(conn):
while True:
data = conn.recv(1024)
data = data.decode('utf-8')
dataMessage = data.split(' ', 1)
command = dataMessage[0]
print(command)
if command == 'GET':
reply = GET()
else:
reply = 'Unknown Command'
conn.sendall(str.encode(reply))
conn.close()
if __name__=='__main__':
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
pass
so how to make server keep sending data if command=='RUN' and my client keep listen to server
I want to make raspberry to keep sending data in every second via socket if my pc send command "RUN". and stop if my pc send command "STOP".
You can set a timeout on the socket.recv() operation and upon the timeout act as if a GET command were received. For this purpose change
data = conn.recv(1024)
to
try:
data = conn.recv(1024)
except socket.timeout:
data = b'GET' # simulate GET command on timeout
and add the handling of the RUN and STOP commands:
reply = ''
if command == 'GET':
reply = GET()
elif command == 'RUN':
conn.settimeout(1) # activate timeout for recv()
elif command == 'STOP':
conn.settimeout(None) # deactivate timeout for recv()
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,))
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:
...
Hi i'm trying to send multiple messages to the tcp server but in my client i got an error that data is referenced before assignment. If i send one message there will be no error but if i try to send more than one it returns the error.
tcp server:
class Connect(object):
def __init__(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print('socket cannot be created')
server_address = ('169.254.34.240', 10000)
#print('starting up: ' + server_address)
self.sock.bind(server_address)
self.sock.listen(1)
def listen(self):
while True:
connection, client_address = self.sock.accept()
print('client connected')
try:
data = connection.recv(16)
print(data)
if data == "STATUS":
connection.sendall("vision=ready")
elif data == "MEASURE":
connection.sendall("vision=computing")
elif data == "GET_RESULT":
connection.sendall("x=1.5,y=0.25,z=0.14,a=0.15")
else:
connection.sendall("wrong command")
finally:
connection.close()
def main():
connect = Connect()
connect.listen()
if __name__=='__main__':
main()
my tcp client which is sending messages:
class Connect(object):
def __init__(self):
# Create a TCP/IP socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port on the server given by the caller
print('connecting to host')
self.sock.connect(('169.254.34.240',10000))
def send(self, command):
try:
message = command
print('sending: ' + message)
self.sock.sendall(message)
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = self.sock.recv(16)
amount_received += len(data)
print('received: ' + data)
finally:
self.sock.close()
return data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
if __name__=='__main__':
main()
so anyone an idea, i suppose i don't end correctly or something, i thought it had something to do about my while in the client?
The problem is that you are calling self.sock.close() after each request without creating a new socket. You will need to create a new socket after each time you close it.
You can solve this by creating a connection per request as follows:
class Connect(object):
def connect(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('connecting to host')
sock.connect(('127.0.0.1',10000))
return sock
def send(self, command):
sock = self.connect()
recv_data = ""
data = True
print('sending: ' + command)
sock.sendall(command)
while data:
data = sock.recv(1024)
recv_data += data
print('received: ' + data)
sock.close()
return recv_data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
Providing full stack trace would help, pointing to exact line, where is the problem present. Learn reading these stack traces, they look boring, but provide valuable information like source file and line where it comes from.
Reading your code I suspect, that it fails at finally block, where you return data.
data will not have assigned value in case, the while amount_received < amount_expected would not allow even the first round in the loop or if withing that loop would happen an exception on the line self.sock.recv(16).
Btw.: you are assuming, that length of response will be the same as length of request, but your server does not provide responses with such length.
Server
import socket
import sys
HOST = ''
PORT = 9000
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'
conn, addr = s.accept()
print 'Connecting from: ' + addr[0] + ':' + str(addr[1])
while 1:
message=raw_input(">")
s.sendto(message, (addr[0], addr[1]))
print(s.recv(1024))
How do I make this send a message to the client?
I can make it reply to a string the client sends to the server, but in this case I want the server to send the first message...
Can anyone help me, The solutions on google don't seem to work properly and I'm not sure what I'm doing wrong.
Since this is the 1st Google Stack Overflow result for this, I'll post a complete, working example for both a client and a server. You can start either 1st. Verified working on Ubuntu 18.04 w/ Python 3.6.9
text_send_server.py:
# text_send_server.py
import socket
import select
import time
HOST = 'localhost'
PORT = 65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen()
print('socket now listening')
# accept the socket response from the client, and get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
myCounter = 0
while True:
message = 'message ' + str(myCounter)
print('sending: ' + message)
sendTextViaSocket(message, conn)
myCounter += 1
time.sleep(1)
# end while
# end function
def sendTextViaSocket(message, sock):
# encode the text message
encodedMessage = bytes(message, 'utf-8')
# send the data via the socket to the server
sock.sendall(encodedMessage)
# receive acknowledgment from the server
encodedAckText = sock.recv(1024)
ackText = encodedAckText.decode('utf-8')
# log if acknowledgment was successful
if ackText == ACK_TEXT:
print('server acknowledged reception of text')
else:
print('error: server has sent back ' + ackText)
# end if
# end function
if __name__ == '__main__':
main()
text_receive_client.py
# text_receive_client.py
import socket
import select
import time
HOST = 'localhost'
PORT = 65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
connectionSuccessful = False
while not connectionSuccessful:
try:
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause an error, hence the try-except
print('socket connected')
connectionSuccessful = True
except:
pass
# end try
# end while
socks = [sock]
while True:
readySocks, _, _ = select.select(socks, [], [], 5)
for sock in readySocks:
message = receiveTextViaSocket(sock)
print('received: ' + str(message))
# end for
# end while
# end function
def receiveTextViaSocket(sock):
# get the text via the scoket
encodedMessage = sock.recv(1024)
# if we didn't get anything, log an error and bail
if not encodedMessage:
print('error: encodedMessage was received as None')
return None
# end if
# decode the received text message
message = encodedMessage.decode('utf-8')
# now time to send the acknowledgement
# encode the acknowledgement text
encodedAckText = bytes(ACK_TEXT, 'utf-8')
# send the encoded acknowledgement text
sock.sendall(encodedAckText)
return message
# end function
if __name__ == '__main__':
main()
Use the returned socket object from 'accept' for sending and receiving data from a connected client:
while 1:
message=raw_input(">")
conn.send(message)
print conn.recv(1024)
You just have to use send
Server.py
import socket
s = socket.socket()
port = 65432
s.bind(('0.0.0.0', port))
s.listen(5)
while True:
c, addr = s.accept()
msg = b"Hello World!"
c.send(msg)
Client.py
import socket
s = socket.socket()
port = 65432
s.connect(('127.0.0.1', port))