i was tried to use asyncio and threading libraries in different scripts. but threading will cause this error in high connections:
filedescriptor out of range in select()
my source that cause this error:
try:
reader, _, _ = select.select([socket_src, socket_dst], [], [], 1)
except select.error as err:
error("Select failed", err)
i tried to increase fd limit but it not fix this error.
and in asyncio library:
after run script everything is ok.
after 20 minutes of running script, users will connect to proxy after about 1 min of send request
and any user can not connect to proxy after 1 hour...
my source:
import socket
import asyncio
import aiosocks
from struct import pack, unpack
class Client(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
self.server_transport = None
def data_received(self, data):
# print('recv:', repr(data))
self.server_transport.write(data)
def connection_lost(self, *args):
self.server_transport.close()
class Server(asyncio.Protocol):
INIT, HOST, DATA = 0, 1, 2
def connection_made(self, transport):
print('from:', transport.get_extra_info('peername'))
self.transport = transport
self.state = self.INIT
def connection_lost(self, exc):
self.transport.close()
def data_received(self, data):
# print('send:', repr(data))
if self.state == self.INIT:
assert data[0] == 0x05
self.transport.write(pack('!BB', 0x05, 0x00)) # no auth
self.state = self.HOST
elif self.state == self.HOST:
ver, cmd, rsv, atype = data[:4]
assert ver == 0x05 and cmd == 0x01
if atype == 3: # domain
length = data[4]
hostname, nxt = data[5:5+length], 5+length
elif atype == 1: # ipv4
hostname, nxt = socket.inet_ntop(socket.AF_INET, data[4:8]), 8
elif atype == 4: # ipv6
hostname, nxt = socket.inet_ntop(socket.AF_INET6, data[4:20]), 20
port = unpack('!H', data[nxt:nxt+2])[0]
print('to:', hostname, port)
asyncio.ensure_future(self.connect(hostname, port))
self.state = self.DATA
elif self.state == self.DATA:
self.client_transport.write(data)
async def connect(self, hostname, port):
loop = asyncio.get_event_loop()
socks5_addr = aiosocks.Socks5Addr('127.0.0.1', 1080)
dst = (hostname, port)
transport, client = await aiosocks.create_connection(Client, proxy=socks5_addr, proxy_auth=None, dst=dst)
client.server_transport = self.transport
self.client_transport = transport
hostip, port = transport.get_extra_info('sockname')
host = unpack("!I", socket.inet_aton(hostip))[0]
self.transport.write(
pack('!BBBBIH', 0x05, 0x00, 0x00, 0x01, host, port))
if __name__ == '__main__':
loop = asyncio.get_event_loop()
srv = loop.create_server(Server, 'localhost', 8000)
loop.run_until_complete(srv)
loop.run_forever()
what should i do to fix at least one of this problems?
if you know any other libraries, please say me.
thanks
Related
I tried to make async socket core for my private server for game. This works, but don't accept more than 1 client. 2 clients trying to connect, but second client cannot do this, only when first will disconnect.
import asyncio, socket, time
class Server:
def __init__(self, port: int):
self.server = socket.socket()
self.port = port
async def start(self):
self.server.bind(("0.0.0.0", self.port))
self.server.listen()
print(f"Server started on {self.port}!")
while True:
session, ip = self.server.accept()
print(f"{ip[0]} connected!")
await Connection(session, ip[0]).messaging()
class Connection:
def __init__(self, session, ip):
self.session = session
self.ip = ip
def receive(self, session, lens):
data = b""
while len(data) < lens:
s = session.recv(lens)
if not s:
s += 0
break
data += s
return data
async def messaging(self):
last = int(time.time())
while True:
try:
header = self.session.recv(7)
if len(header) > 0:
last = int(time.time())
mtype = int.from_bytes(header[:2], "big")
mlen = int.from_bytes(header[2:5], "big")
mdata = self.receive(self.session, mlen)
print(f"[C] {mtype} from {self.ip}")
if int(time.time()) - last > 7:
break
except(ConnectionAbortedError, ConnectionResetError, ConnectionRefusedError, TimeoutError, OSError):
break
self.session.close()
print(f"{self.ip} disconnected!")
asyncio.run(Server(9339).start())
I tried to use module select but this has laggy disconnect.
While studying about networks, i found a very common exercise that i thought was pretty insteresting, that is an application to manage simple chatrooms using sockets in Python
The thing is that i found a solution that uses thread, and was wondering how to adapt the solution i found from thread use to select.
The server.py :
from http import client
import os
import socket
import threading
import time
class Server:
def __init__(self, host, port):
self.HOST = host
self.PORT = port
self.rooms_list = []
def get_network(self):
return (self.HOST,self.PORT)
def run(self):
try:
self.create_connection_TCP()
self.accept_connection_rooms()
except:
print("Ocorreu um erro com o servidor principal")
os._exit(1)
def getList(self):
...
def create_connection_TCP(self):
server = (self.HOST, self.PORT)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
self.socket.bind(server)
except:
print("Bind failed")
os._exit(1)
self.socket.listen(100)
def accept_connection_rooms(self):
while True:
try:
client, client_address = self.socket.accept()
thread = threading.Thread(target = self.control_connection, args = (client, ))
thread.start()
except:
print("Failing while creating conection")
os._exit(1)
def check_comand(self, client_socket):
message = client_socket.recv(1024).decode('utf-8')
command = message.split(':')
if command[0] == '/shutdown':
self.socket.close()
if command[0] == '/add_room':
room = ':'.join(command[1:4])
print(room)
if not room in self.rooms_list:
qtd_clients = len(self.rooms_list)
print(f"servidor: {room} | max clients: {command[4]}")
room = ':'.join(command[1:5])
self.rooms_list.append(room)
if command[0] == '/get_room':
index = int(command[1])
try:
room = self.rooms_list[index].split(':')
room = ':'.join(room[1:3])
client_socket.send(f"{room}".encode('utf-8'))
except IndexError:
client_socket.send("error: invald option".encode('utf-8'))
if command[0] == '/get_room_id':
message = len(self.rooms_list)
client_socket.send(message.encode('utf-8'))
if command[0] == '/list_rooms':
rooms = []
for index in range(len(self.rooms_list)):
room_name = self.rooms_list[index].split(':')[0]
rooms.append(f"{index} - {room_name}")
rooms = '\n'.join(rooms)
client_socket.send(f"{rooms}".encode('utf-8'))
# print(f"{rooms}")
if command[0] == '/close_room':
room = ':'.join(command[1:4])
self.rooms_list.remove(room)
print(f"closed_room: {room}")
def control_connection(self, client):
self.check_comand(client)
def close_server(self):
self.socket.close()
server = Server('127.0.0.1', 5000)
server.run()
Probably a good solution is to use select to listen all sockets connections and implement on accept_connection_rooms to manage new sockets
I'm trying to find a way to forward stdin input from my main process to a child process, and what I've found that works is basically to open a socket on the main process and then send text via the socket to the children processes. But what I'm finding is that half of the time my socket gets refused, and I have no idea what's going on.
I've followed the instructions on this question 16130786 but to no avail, I can connect via telnet, but the software still fails.
Here is the minimally reproducable example I've made
from multiprocessing import Process, Queue
from queue import Full, Empty
from io import TextIOBase
import socket
import selectors
class SocketConsoleClient(TextIOBase):
def __init__(self, port: int):
self.port = port
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.conn.connect(('', self.port))
self.selector = selectors.DefaultSelector()
self.conn.setblocking(False)
self.selector.register(self.conn, selectors.EVENT_WRITE, data='hello')
def readline(self, size: int = ...) -> str:
while True:
for k, _ in self.selector.select(timeout=None):
if k.data == 'hello':
try:
return str(self.conn.recv(1024).decode('latin1'))
except Exception as e:
# print(e)
continue
class SocketConsoleWriter(Process):
def __init__(self):
super().__init__()
self.writes = Queue()
self.connections = []
self.listener = None
self.selector = None
self.port = 10000
def run(self) -> None:
while True:
try:
self.listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listener.bind(('', self.port))
self.listener.listen()
print('listening on', ('', self.port))
self.listener.setblocking(False)
break
except Exception as _:
self.port += 1 # if errno is 98, then port is not available.
self.selector = selectors.DefaultSelector()
self.selector.register(self.listener, selectors.EVENT_READ, data='test')
while True:
try:
w = self.writes.get_nowait()
if w == '$$$EXIT!!!':
break
else:
for c in self.connections:
c.send(w.encode('latin1'))
except Empty:
pass
try:
d = self.selector.select(1)
for k, _ in d:
if k.data == 'test':
conn, addr = self.listener.accept()
print('{} connected'.format(addr))
self.connections.append(conn)
except Exception as e:
# print(e)
pass
class SocketConsoleServer:
server = None
def __init__(self):
if SocketConsoleServer.server is None:
SocketConsoleServer.server = SocketConsoleWriter()
SocketConsoleServer.server.start()
#staticmethod
def port() -> int:
if SocketConsoleServer.server is None:
SocketConsoleServer.server = SocketConsoleWriter()
SocketConsoleServer.server.start()
return SocketConsoleServer.server.port
#staticmethod
def write(msg: str):
if SocketConsoleServer.server is None:
SocketConsoleServer.server = SocketConsoleWriter()
SocketConsoleServer.server.start()
SocketConsoleServer.server.writes.put(msg)
if __name__ == '__main__':
import sys, time
serv = SocketConsoleServer()
time.sleep(1)
class TestProcessSocket(Process):
def run(self):
sys.stdin = SocketConsoleClient(serv.port())
time.sleep(1)
print(input())
client = TestProcessSocket()
client.start()
serv.write(input('Type something: '))
client.join()
Why is my socket connection getting refused, I'm using ubuntu?
I'm trying to build a socket and I want to print an object of clients, but for some reason whenever I connect it just returns empty {}
I'm new to Python and would like some insight
import socket
from threading import Thread
from multiprocessing import Process
import time as t
previousTime = t.time()
clients = {}
hostAddr = "127.0.0.1"
hostPort = 80
class sClient(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.sock = socket
self.addr = address
self.start()
def run(self):
print("\nClient Connected from {}!".format(self.addr[0]))
self.sock.sendall("Welcome master".encode())
class sHost():
def __init__(self, host, port, clients):
self.sHost = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sHost.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sHost.bind((host, port))
self.sHost.listen()
self.start_listening()
def start_listening(self):
while 1:
clientSocket, clientAddr = self.sHost.accept()
clients[clientSocket.fileno()] = clientSocket
sClient(clientSocket, clientAddr)
def SendMsgToAllClients(msg):
print(clients) # this is empty
for client in clients.values():
try:
client.sendall(msg.encode())
except Exception as e:
print("Client probably disconnected, removing...")
finally:
del clients[client.fileno()]
if __name__ == '__main__':
Process(target=sHost, args=(hostAddr, hostPort, clients)).start()
print("Server is running")
while 1:
if previousTime + 3 <= t.time():
SendMsgToAllClients("Test")
previousTime = t.time()
I am learning python asyncio module and try to write a socks5 server with it. Python docs said:
Called when some data is received. data is a non-empty bytes object
containing the incoming data.
I wonder when client sends 2 bytes data, will data_received(self, data) just receive 1 byte not 2 bytes when it called and the rest 1 byte will call data_received(self, data) again?
#!/usr/bin/env python3
import asyncio
import logging
import socket
import struct
logging.basicConfig(level=logging.DEBUG,
format='{asctime} {levelname} {message}',
datefmt='%Y-%m-%d %H:%M:%S',
style='{')
class Remote(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
self.server_transport = None
def data_received(self, data):
self.server_transport.write(data)
class Server(asyncio.Protocol):
INIT, REQUEST, REPLY = 0, 1, 2
def connection_made(self, transport):
client_info = transport.get_extra_info('peername')
logging.info('connect from {}'.format(client_info))
self.transport = transport
self.state = self.INIT
def data_received(self, data):
if self.state == self.INIT:
if data[0] == 5:
amount = data[1] # Authentication amount
if 0 in data[2:]:
self.transport.write(b'\x05\x00')
self.state = self.REQUEST
else:
self.eof_received()
else:
self.eof_received()
elif self.state == self.REQUEST:
ver, cmd, rsv, addr_type = data[:4]
logging.info('addr type: {}'.format(addr_type))
if addr_type == 1: # ipv4
addr = socket.inet_ntoa(data[4:8])
elif addr_type == 3:
addr_len = data[4]
addr = data[5:5+addr_len]
else:
data = b'\x05\x08\x00\x01'
data += socket.inet_aton('0.0.0.0') + struct.pack('>H', 0)
self.transport.write(data)
logging.error('not support addr type')
self.eof_received()
port = struct.unpack('>H', data[-2:])[0]
logging.info('target: {}:{}'.format(addr, port))
asyncio.ensure_future(self.remote(addr, port))
self.state = self.REPLY
elif self.state == self.REPLY:
logging.info('start relay')
self.remote_transport.write(data)
async def remote(self, addr, port):
loop = asyncio.get_event_loop()
transport, _remote = await loop.create_connection(Remote, addr, port)
_remote.server_transport = self.transport
self.remote_transport = transport
bind_addr, bind_port = transport.get_extra_info('sockname')
data = b'\x05\x00\x00\x01'
data += socket.inet_aton(bind_addr) + struct.pack('>H', bind_port)
self.transport.write(data)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
server = loop.create_server(Server, '127.0.0.2', 1089)
loop.run_until_complete(server)
try:
loop.run_forever()
except KeyboardInterrupt:
server.close()
loop.run_until_complete(server.close())
loop.close()
no, data_received will receive as many bytes as are already received by the server. If you need to receive the first 3 bytes to handle the request, then you should implement some buffering in your Protocol to allow you to wait for the rest of the request to arrive before continuing.
It would typically look like this:
def __init__(self, …):
self._buffer = bytearray()
…
def data_received(self, data):
self._buffer += data
if self.state == self.INIT:
# here we need at least 3 bytes.
# if we don't have enough data yet, just wait for the next `data_received` call
if len(self._buffer) < 3:
return
header, self._buffer = self._buffer[:2], self._buffer[2:]
# parse authentication header, switch the state to REQUEST
elif self.state == self.REQUEST:
…