pycom urequests timeouts not working as expected - sockets

The standard Pycom urequests library (part of below) does not support user configurable timeouts.
def request(method, url, data=None, json=None, headers={}, stream=None):
try:
proto, dummy, host, path = url.split("/", 3)
except ValueError:
proto, dummy, host = url.split("/", 2)
path = ""
if proto == "http:":
port = 80
elif proto == "https:":
import ussl
port = 443
else:
raise ValueError("Unsupported protocol: " + proto)
if ":" in host:
host, port = host.split(":", 1)
port = int(port)
ai = usocket.getaddrinfo(host, port)
ai = ai[0]
s = usocket.socket(ai[0], ai[1], ai[2])
try:
s.connect(ai[-1])
If the server I'm trying to contact does not respond the code waits at
ai = usocket.getaddrinfo(host, port)
for 30s before exiting with an OSError.
So I changed it using https://github.com/micropython/micropython-lib/pull/263/files as a guide
def request(method, url, data=None, json=None, headers={}, stream=None, timeout=5):
try:
proto, dummy, host, path = url.split("/", 3)
except ValueError:
proto, dummy, host = url.split("/", 2)
path = ""
if proto == "http:":
port = 80
elif proto == "https:":
import ussl
port = 443
else:
raise ValueError("Unsupported protocol: " + proto)
if ":" in host:
host, port = host.split(":", 1)
port = int(port)
ai = usocket.getaddrinfo(host, port)
ai = ai[0]
s = usocket.socket(ai[0], ai[1], ai[2])
if timeout is not None:
assert hasattr(usocket.socket, 'settimeout'), 'Socket does not support timeout'
s.settimeout(timeout)
try:
s.connect(ai[-1])
It did me no good, the damn thing still waits for 30s if there is no server response. If anything I'm worse off because now it also waits for 5s after every server response before returning the data, whereas previously I'd get the data the instant the server responded.
I figure the 30s timeout must be accessible somewhere I just can't figure out where. I'm in a bit over my head here. Can anyone offer some suggestions?

Related

Why does Rasp Pi Pico can not connect to TCP Server after some point?

I use Raspberry Pi Pico with ESP8266 WiFi module, and I am trying to write a TCP client. Rasp Pi Pico is able to send AT commands and receive responses and send data through UART. Also the TCP client is able to send data to the TCP server, which runs in my laptop. However the problem is that the client is not able to connect to the server after some point.
Let me first show the server-side code. In server, I am trying to receive data basically. ConnectionResetError was a problem for me so I wrote the following except block. I am not sure it is buggy or not, since I'm kind of a noob in this area.
import socket
HOST = ""
PORT = 8080
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
mysocket.bind((HOST, PORT))
mysocket.listen(1)
while True:
print("Waiting...")
conn, addr = mysocket.accept()
print('[SERVER] - Connected from: %s' % str(addr))
while True:
try:
request = conn.recv(1024)
if not request:
break
conn.sendall(request.upper())
print('[SERVER] - Received Data: %s' % str(request))
except ConnectionResetError as cr_err:
break
conn.close()
print("[SERVER] - Disconnected")
Here is my client-side code. In client, I wrote two helper classes called ESP8266 and Sensor, in which I control the WiFi module and read analog value from a sensor. Pico first tries to start WiFi module, afterwards it tries to connect to TCP server and send data. After some point it does not connect to the TCP server, so it restart the WiFi module and reconnects.
class EndDevice:
def __init__(self, sensor_id):
self.__wifi_module = ESP8266(UART_PIN, BAUDRATE)
self.__sensor = Sensor(sensor_id, SENSOR_PIN)
def start(self):
self.__wifi_module.start()
self.__wifi_module.set_mode(STATION_MODE)
self.__wifi_module.join_access_point(AP_NAME, AP_PWD)
def reconnect(self):
self.__wifi_module.restart()
self.__wifi_module.set_mode(STATION_MODE)
self.__wifi_module.join_access_point(AP_NAME, AP_PWD)
def run(self):
retry_count = 0
while True:
if self.__wifi_module.start_connection("TCP", SERVER_HOST, SERVER_PORT):
self.__wifi_module.send_data(
str(self.__sensor.generate_package()))
self.__wifi_module.close_connection()
else:
retry_count += 1
if retry_count == MAX_RETRY:
break
if __name__ == "__main__":
pico = EndDevice("SM-0")
pico.start()
while True:
pico.run()
pico.reconnect()
Finally I will share some of the methods in classes ESP8266 and UARTHandler (which is used in ESP8266), so you can see if I do anything non-sense.
start_connection method in ESP8266 is as follows. In this method, I tried to send the corresponding AT command to connect to a TCP server. In the method self.__uart_handler.send_receive_cmd timeout duration is 2000ms, and other parameters are AT command, connection_type (TCP), server IP address and server port, in order.
def start_connection(self, conn_type, remote_ip, remote_port):
conn_type, remote_ip = "\"{}\"".format(conn_type), "\"{}\"".format(remote_ip)
response = self.__uart_handler.send_receive_cmd(2000, CONN_START, conn_type, remote_ip, str(remote_port))
if "OK" in response:
self.__log("Connected to {} at port {}.".format(remote_ip, remote_port))
return True
else:
self.__log("Failed to create a connection with {} at port {}.".format(remote_ip, remote_port))
return False
send_receive_cmd method in UARTHandler is as follows. In this method I use lots of helper methods as you can see, however they are just formatting and writing to UART or reading from UART. I also insert a timeout between UART-read and UART-write
def __generate_cmd(self, cmd, *args):
if len(args) != 0:
cmd += "="
for idx, each in enumerate(args):
cmd += str(each)
if idx != len(args)-1:
cmd += ","
cmd += "\r\n"
return cmd
def __send_cmd(self, cmd, *args):
sent_cmd = self.__generate_cmd(cmd, *args)
self.__uart.write(sent_cmd)
def __receive_response(self, cmd):
response = self.__uart.read()
try: return response.decode('utf-8')
except: return response
def send_receive_cmd(self, timeout, cmd, *args):
self.__send_cmd(cmd, *args)
utime.sleep_ms(timeout)
return self.__receive_response(self.__generate_cmd(cmd, *args))
Let me ask my question again. This codes are working properly in starting-restarting and sending data for (let me say) 3 connections. However, after some connect-disconnect later, TCP client is not able to make a connection with TCP server. Again after some failed connection attempt, WiFi module is restarted and TCP connection is made and working properly again.

Socket Programming: Setup server, it runs if port is 80, but cannot run if port is other

I'm trying to setup a server using Python socket programming, using the code below:
from socket import *
serverPort = 80
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(("", serverPort))
serverSocket.listen(1)
print ("The server is ready to receive")
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()
When I use this code and try to enter localhost in a web browser, I get the response without any problem as shown.
But, when I change line 3 in the code to serverPort = 12000 and try to enter localhost:12000, I don't get a response.
Note: I use Windows not Linux, and I run the Python code on PyCharm 2020.3.3.
Neither example should be working, regardless of the port used, because the server is not sending back a valid HTTP response, like the error message says. The fact that the 1st example "works" is a fluke.
Try this instead:
from socket import *
serverPort = 80
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(("", serverPort))
serverSocket.listen(1)
print ("The server is ready to receive")
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
reply = "HTTP/1.0 200 OK\r\nConnection: close\r\n\r\n"
connectionSocket.send(reply.encode()) # <-- add this!
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()

Connecting two computers in different networks using socket and Port forwarding

I have set up a simple client-server communication code and it works well in my computer when my computer itself acts as a server and the client.
Now I am trying to run this same code on two different computers in different networks( different locations) where my computer will act as a server and my friend's computer as a client.
I have done port forwarding in my router as well as in my friend's router for the port which we are trying to communicate. We both have set up a static IP in our internal network behind the router. We both had shutdown the firewall while running the code.
I am running my code on Jupiter notebook and the same is my friend too.
here is my server code:
import socket
import threading
HEADER = 64
PORT = 5064
SERVER = '0.0.0.0'
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "quit"
Receive_from_client = "get info"
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ADDR)
def handle_client(conn, addr):
print("\n" + f"[NEW Connection] detected from IP: {addr[0]} & Port:{addr[1]} ")
conn.send(f"connected to server {ADDR}".encode(FORMAT))
connected =True
while connected:
msg_length = conn.recv(HEADER).decode(FORMAT) # decode the msg from byte to utf-8 format
if msg_length:
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
if msg == DISCONNECT_MESSAGE:
connected = False
print(f" [Client][{addr}] {msg}")
print("Your session is disconnected")
break
if msg == Receive_from_client:
print("\n" + f"Send your msg to client with IP: {addr[0]}")
thread = threading.Thread(target = send2client, args = (conn, addr))
thread.start()
print(f" [Client][{addr}] {msg}")
conn.send(f"Msg received by server with IP:{addr[0]}".encode(FORMAT))
conn.close()
server.close()
def start():
server.listen()
print("\n"+ f"[LISTENING] Server is listening from IP: {SERVER} ")
while True:
conn, addr = server.accept()
thread = threading.Thread(target = handle_client, args = (conn, addr))
thread.start()
Here is the client code
import socket
import threading
HEADER = 64
PORT = 5064
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "quit"
SERVER = '103.192.207.250' # SERVERS public IP
ADDR = (SERVER, PORT)
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(ADDR)
def send2server():
while True:
msg = input()
message = msg.encode(FORMAT)
msg_lenght = len(message)
send_length = str(msg_lenght).encode(FORMAT)
send_length += b' '*(HEADER - len(send_length))
client.send(send_length)
client.send(message)
print(client.recv(2048).decode(FORMAT))
if msg == DISCONNECT_MESSAGE:
print("session closed")
client.close()
def start():
print("\n"+ f"[LISTENING] client is listening from IP: {ADDR} ")
send2server()
I have opened the port by going on windows firewall defender and selecting new inbound and outbound rules to open 5064 TCP port.
but still, the code doesn't works..
my server keeps waiting for connection and the client-side after few seconds of running gives this error:
TCP error code 10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Even while my server is listening from port 5064 when I scan this port to check if the port is open or not it says closed.
How do I check if the port I have forwarded is for sure open and also how do I get this thing work?
I have tried all of this and if there is any other thing I am missing please tell. I am struggling to get this work for the past 3 days.

Establish a connection through socks with socket library

I have this script that simply uses a list of socks and tries to connect to a host. But it always shows this error:
File "*.py", line 38, in requestsocks
s.connect((host, port))
File "/home/*/.local/lib/python3.5/site-packages/socks.py", line 729, in connect
_BaseSocket.connect(self, proxy_addr)
TypeError: an integer is required (got type str)
Here is the code:
import socket,socks,random
def checkurl():
global url
global url2
global urlport
url = input("Insert URL: ")
if url[0]+url[1]+url[2]+url[3] == "www.":
url = "http://" + url
elif url[0]+url[1]+url[2]+url[3] == "http":
pass
else:
url = "http://" + url
try:
url2 = url.replace("http://", "").replace("https://", "").split('/')[0].split(":")[0]
except:
url2 = url.replace("http://", "").replace("https://", "").split('/')[0]
try:
urlport = url.replace("http://", "").replace("https://", "").split('/')[0].split(':')[1]
except:
urlport = "80"
def proxylist():
global entries
out_file = str(input("Enter the proxy list: "))
entries = open(out_file).readlines()
requestsocks()
def requestsocks():
while True:
proxy = random.choice(entries).strip().split(':')
host = str(url2)
port = int(urlport)
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, proxy[0], proxy[1], True)
s = socks.socksocket()
s.connect((host, port))
s.sendall('Hello world')
checkurl()
proxylist()
I don't know how can I solve this. Ideas?
P.S. I've taken the socks list from here: https://www.socks-proxy.net/
I haven't done much with the sockets library, but it's asking for an integer for both host and port. Try getting the IP like this.
Add this ------> host = socket.gethostbyname(host)
def requestsocks():
while True:
proxy = random.choice(entries).strip().split(':')
host = str(url2)
# convert url to IP address
host = socket.gethostbyname(host)
port = int(urlport)
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, proxy[0], proxy[1], True)
s = socks.socksocket()
s.connect((host, port))
s.sendall('Hello world')

Python Socket Multiple Clients

So I am working on an iPhone app that requires a socket to handle multiple clients for online gaming. I have tried Twisted, and with much effort, I have failed to get a bunch of info to be sent at once, which is why I am now going to attempt socket.
My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?
Thank you!
#!/usr/bin/python # This is server.py file
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 50000 # Reserve a port for your service.
print 'Server started!'
print 'Waiting for clients...'
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
while True:
msg = c.recv(1024)
print addr, ' >> ', msg
msg = raw_input('SERVER >> ')
c.send(msg);
#c.close() # Close the connection
Based on your question:
My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?
Using the code you gave, you can do this:
#!/usr/bin/python # This is server.py file
import socket # Import socket module
import thread
def on_new_client(clientsocket,addr):
while True:
msg = clientsocket.recv(1024)
#do some checks and if msg == someWeirdSignal: break:
print addr, ' >> ', msg
msg = raw_input('SERVER >> ')
#Maybe some code to compute the last digit of PI, play game or anything else can go here and when you are done.
clientsocket.send(msg)
clientsocket.close()
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 50000 # Reserve a port for your service.
print 'Server started!'
print 'Waiting for clients...'
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
print 'Got connection from', addr
while True:
c, addr = s.accept() # Establish connection with client.
thread.start_new_thread(on_new_client,(c,addr))
#Note it's (addr,) not (addr) because second parameter is a tuple
#Edit: (c,addr)
#that's how you pass arguments to functions when creating new threads using thread module.
s.close()
As Eli Bendersky mentioned, you can use processes instead of threads, you can also check python threading module or other async sockets framework. Note: checks are left for you to implement how you want and this is just a basic framework.
accept can continuously provide new client connections. However, note that it, and other socket calls are usually blocking. Therefore you have a few options at this point:
Open new threads to handle clients, while the main thread goes back to accepting new clients
As above but with processes, instead of threads
Use asynchronous socket frameworks like Twisted, or a plethora of others
Here is the example from the SocketServer documentation which would make an excellent starting point
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
Try it from a terminal like this
$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello
HELLOConnection closed by foreign host.
$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Sausage
SAUSAGEConnection closed by foreign host.
You'll probably need to use A Forking or Threading Mixin too
This program will open 26 sockets where you would be able to connect a lot of TCP clients to it.
#!usr/bin/python
from thread import *
import socket
import sys
def clientthread(conn):
buffer=""
while True:
data = conn.recv(8192)
buffer+=data
print buffer
#conn.sendall(reply)
conn.close()
def main():
try:
host = '192.168.1.3'
port = 6666
tot_socket = 26
list_sock = []
for i in range(tot_socket):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host, port+i))
s.listen(10)
list_sock.append(s)
print "[*] Server listening on %s %d" %(host, (port+i))
while 1:
for j in range(len(list_sock)):
conn, addr = list_sock[j].accept()
print '[*] Connected with ' + addr[0] + ':' + str(addr[1])
start_new_thread(clientthread ,(conn,))
s.close()
except KeyboardInterrupt as msg:
sys.exit(0)
if __name__ == "__main__":
main()
def get_clients():
first_run = True
startMainMenu = False
while True:
if first_run:
global done
done = False
Thread(target=animate, args=("Waiting For Connection",)).start()
Client, address = objSocket.accept()
global menuIsOn
if menuIsOn:
menuIsOn = False # will stop main menu
startMainMenu = True
done = True
# Get Current Directory in Client Machine
current_client_directory = Client.recv(1024).decode("utf-8", errors="ignore")
# beep on connection
beep()
print(f"{bcolors.OKBLUE}\n***** Incoming Connection *****{bcolors.OKGREEN}")
print('* Connected to: ' + address[0] + ':' + str(address[1]))
try:
get_client_info(Client, first_run)
except Exception as e:
print("Error data received is not a json!")
print(e)
now = datetime.now()
current_time = now.strftime("%D %H:%M:%S")
print("* Current Time =", current_time)
print("* Current Folder in Client: " + current_client_directory + bcolors.WARNING)
connections.append(Client)
addresses.append(address)
if first_run:
Thread(target=threaded_main_menu, daemon=True).start()
first_run = False
else:
print(f"{bcolors.OKBLUE}* Hit Enter To Continue.{bcolors.WARNING}\n#>", end="")
if startMainMenu == True:
Thread(target=threaded_main_menu, daemon=True).start()
startMainMenu = False
#!/usr/bin/python
import sys
import os
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = 50000
try:
s.bind((socket.gethostname() , port))
except socket.error as msg:
print(str(msg))
s.listen(10)
conn, addr = s.accept()
print 'Got connection from'+addr[0]+':'+str(addr[1]))
while 1:
msg = s.recv(1024)
print +addr[0]+, ' >> ', msg
msg = raw_input('SERVER >>'),host
s.send(msg)
s.close()