Simple Python Echo Server - Wrong Argument - python

import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(5)
input = [server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input.remove(s)
server.close()
Whenever I run this code, I get this error message for my argument for the while loop:
inputready,outputready,exceptready = select.select(input,[],[])
TypeError: argument must be an int, or have a fileno() method.
How can I fix this to make the server run properly? Sorry if this is a bad question, I'm new to python and I can't figure this out. Thanks.

Yeah found the solution to your problem their seem to be sys.stdin , the python IDLE GUI for some reason doesn't allow you to use sys.stdin.fileno() in your code, while if you run it in the command prompt or the terminal it will work fine on linux. Link
An if your using windows, you cant pass the sys.stdin as an argument to the select() function, as in windows it accepts only sockets as arguments. As Explained in the documentation Documentation
Note: File objects on Windows are not acceptable, but sockets are. On Windows, the underlying select() function is provided by the WinSock library, and does not handle file descriptors that don’t originate from WinSock.
So to mitigate the problem , such that it works on both windows and linux:
import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input1 = [server]
running = 1
while running:
inputready,outputready,exceptready = select.select(input1,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input1.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input1.remove(s)
server.close()

Related

How to create Python API or network requests hidden (protected from hackers checking network traffic) on Local Network to manage Computers

I know that I can see inside of network traffic for example with WireShark. When i use GET on HTML I can see those stuff in URL, what should not be problem what I am doing. But I believe GET,POST and maybe REQUEST too, as I did not work with that one yet can bee seen on something like Wire Shark network analyzer.
I am making Python client, what i will put on computers in network to show their IP,Host Name and Users on PC. This client will be as gate to the computer for remote control. As our management does not want to spend money for windows server, or other management system we need to get something free to manage all computers.
I am also seeking advice how I could do it as you are more skilled then me here.
I found few ways.
With the client create SSH Gateway for receiving commands.
With Client enable the Powershell remote option, then just push scripts to all computers at once.
Use some way the API requests etc... I am not skilled in this one at all, but I believe this is the way how other similar programs works?
As this client would create big security risk, I am first seeking way what is best way to hide it from network. Probably I will need to come up with some Private and public Key system here as well.
What are yours suggestions please on this topic?
here is just very short code I am playing with to receive basic info as IP, Host name and all Users
the Flask website showing those values is just for test, It will not be there once it is deployed
Update
I took advice from MarulForFlask but I got a couple issues. First this i think can have only one connection at a time. And second if possible Can i get the output of console from the client PC on screen of Server PC?
I want this output only for testing, as I know if i do something like netstat or any other command with multiple clients it would filled up screen with too many text... Currently I am getting back text format as plaintext with \r \n ... and other text deviders.
I am now trying Multicast, but i am getting error for binding the multicast IP.
OSError: [WinError 10049] The requested address is not valid in its context
Master.py
import time
import socket
import sys
import os
valueExit = True
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = socket.gethostname()
BUFFER_SIZE = 1024
# Initialize the port
port = 8080
# Bind the socket with port and host
s.bind(('', port))
print("waiting for connections...")
# listening for conections
s.listen()
# accepting the incoming connections
conn, addr = s.accept()
print(addr, "is connected to server")
def send_query():
keepAllive, repeatIt = True, False
print("""To exit session write: EndSession
For help write: help
""")
while (keepAllive == True):
# commands for server use only
innerCommands = ["endsession", "help"]
# take command as input
command = input(str("Enter Command : "))
if command not in innerCommands:
conn.send(command.encode())
print("Command has been sent successfully.")
keepAllive = False
repeatIt = True
elif (command == "endsession"):
conn.send(command.encode())
valueExit = False
elif (command == "help"):
print("""To exit session write: EndSession""")
while (repeatIt == True):
# recieve the confrmation
data = conn.recv(BUFFER_SIZE)
if data:
print(f"command recieved and executed sucessfully.\n {data}")
keepAllive = True
repeatIt = False
else:
print("No reply from computer")
keepAllive = True
repeatIt = False
while valueExit == True:
send_query()
Slave.py
import time
import socket
import sys
import subprocess
import os
stayOn = True
def establishConnection():
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = "127.0.0.1"
# Initiaze the port
port = 8080
keepAlive = True
try:
# bind the socket with port and host
s.connect((host, port))
print("Connected to Server.")
while keepAlive == True:
# recieve the command from master program
command = s.recv(1024)
command = command.decode()
# match the command and execute it on slave system
if command == "endsession":
print("Program Ended")
keepAlive = False
elif command != "":
# print("Command is :", command)
#s.send("Command recieved".encode())
proc = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
s.send(f"{out}".encode())
print("program output:", out)
except Exception as err:
print(f"Error: {err}")
s.send(f"Error: {err}".encode())
while stayOn == True:
establishConnection()
see:
https://www.pythonforthelab.com/blog/how-to-control-a-device-through-the-network/
There uses a flask webserver.
otherwise, create a master.py file and paste this code:
import time
import socket
import sys
import os
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = socket.gethostname()
# Initialize the port
port = 8080
# Bind the socket with port and host
s.bind(('', port))
print("waiting for connections...")
# listening for conections
s.listen()
# accepting the incoming connections
conn, addr = s.accept()
print(addr, "is connected to server")
# take command as input
command = input(str("Enter Command :"))
conn.send(command.encode())
print("Command has been sent successfully.")
# recieve the confrmation
data = conn.recv(1024)
if data:
print("command recieved and executed sucessfully.")
open a slave.py and paste this code:
import time
import socket
import sys
import os
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = "127.0.0.1"
# Initiaze the port
port = 8080
# bind the socket with port and host
s.connect((host, port))
print("Connected to Server.")
# recieve the command from master program
command = s.recv(1024)
command = command.decode()
# match the command and execute it on slave system
if command == "open":
print("Command is :", command)
s.send("Command recieved".encode())
# you can give batch file as input here
os.system('ls')
open slave.py in client, master.py in server
https://www.geeksforgeeks.org/how-to-control-pc-from-anywhere-using-python/

How to incorporate the IP address of a device into a Python script if the address changes

I have a Python script which retrieves the measured data from a smart plug so that I can visualize it on my Rasbperry Pi.
This command gets the data
send_hs_command("192.168.1.26", 9999, b'{"emeter":{"get_realtime":{}}}')
and this is the define
def send_hs_command(address, port, cmd):
data = b""
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
tcp_sock.connect((address, port))
tcp_sock.send(encrypt(cmd))
data = tcp_sock.recv(2048)
except socket.error:
print(time.asctime( time.localtime(time.time()) ), "Socket closed.", file=sys.stderr)
finally:
tcp_sock.close()
return data
My problem is that if I take the Smart Plug somewhere else, it will have
a new IP-Address, which means I have to keep rewriting it on my Python script. This is not an option for me. What would be the simplest solution? Thanks
I don't have a Pi to run this on.
If the IP address of the target(Smart Plug) is variable, can you not use a pre-determined host-name(located in '/etc/hostname') instead?
the socket library provides a few handy functions;
You can first use
gethostbyaddr to get the host-name if you don't have the host-name information already.
Then from that point onward you can use the known host-name and use
create_connection to establish connections.
However, if you want to use something more dynamic; I'd suggest using the MAC address as the key.
Please be advised that running scapy which perhaps depends on tcpdump on Raspberry Pi might be CPU exhaustive.
Please take a look at the following snippet:
import socket
import time
import sys
from scapy.all import *
def send_hs_command(address, port, cmd):
data = b""
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
tcp_sock.connect((address, port))
tcp_sock.send(encrypt(cmd))
data = tcp_sock.recv(2048)
except socket.error:
print(time.asctime( time.localtime(time.time()) ), "Socket closed.", file=sys.stderr)
finally:
tcp_sock.close()
print(data)
return data
def get_ip_from_mac():
# Match ARP requests
packet_list = sniff(filter="arp", count=10) # increase number of arp counts
for i in packet_list:
# Show all ARP requests
# print(i[Ether].src, "is broadcasting IP", i[ARP].psrc)
if (i[ARP].hwsrc == '00:0c:29:b6:f4:be'): # target MAC address
return (True, i[ARP].psrc)
return (False, '')
def main():
result = get_ip_from_mac()
if result[0] == True:
print("Succeeded to reach server")
send_hs_command(result[1], 22, b'{"emeter":{"get_realtime":{}}}')
else:
# logic to retry or graciously fail
print("Failed to reach server")
if __name__== "__main__":
main()

Telnet reads double characters when running python server script

So I am new to python and I'm trying to learn some socket programming and the following script, when ran and connected to the server via telnet, returns me something like "hheelllloo wwoorrlldd" instead of letting me write "hello world" and then send the data. I've looked online and I've already tried to change the localecho setting in telnet and that didn't work either.
The servers script is:
import socket
import sys
import threading
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 10000))
sock.listen(1)
connections = []
def handler(c, a):
global connections
while True:
data = c.recv(1024)
for connection in connections:
connection.send(bytes(data))
if not data:
connections.remove(c)
c.close()
break
while True:
c, a = sock.accept()
conn_thread = threading.Thread(target = handler, args = (c, a))
conn_thread.daemon = True
conn_thread.start()
connections.append(c)
The code when ran should return the sender the text he sent. I think mine does it character by character, without pressing enter to send and I don't know why. I might be wrong though.
Also, I'm running Windows 10, if this matters.

Python select with sockets and sys.stdin

I'm new to Python programming and I'm trying to create a server and a client. I still want to be able to type something from the keyboard so i can close the server from the server by typing 'exit'. I've taken samples codes from various sites to get to where I'm at in socket programming and this code.
However, whenever I run the code I get the following error message:
The host name of this machine is 127.0.0.1
The IP address of the host is 127.0.0.1
Server now awaiting client connection on port 2836
im right before the select
Traceback (most recent call last):
File "/root/Server_2.py", line 42, in <module>
inputready, outputready, exceptready = select.select(input, [], [])
TypeError: argument must be an int, or have a fileno() method.
>>>
I was reading around that to get passed this (in Windows) is to remove the sys.stdin because Windows only accepts sockets. I'm trying to write this code in Linux. I've tried all sorts of things to try to get it to work and I'm all out of resources and ideas to try. Below is the server code:
import socket #import socket module
import select
import sys
host = "127.0.0.1"
print ("The host name of this machine is " + host)
hostIP = socket.gethostbyname(host) # get host IP address
print ("The IP address of the host is %s" % (hostIP))
port = 2836 # Reserve the port for the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((hostIP, port)) # This server to a port
s.listen(4) # Now wait for client connection
print("Server now awaiting client connection on port %s" % (port))
#WINDOWS ONLY ACCEPTS SOCKETS FOR SELECT(), no standard in
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
print("i'm here na")
# check who made a response
for x in inputready:
if x == s:
print(s)
#handle the server socket
client, address = s.accept()
print("connection comming in")
input.append(client)
elif x == sys.stdin:
# handle standard input
stuff = sys.stdin.readline()
if stuff == "exit":
running = 0
else:
print("you typed %s" % (stuff))
else:
#handle all other sockets
data = x.recv(1024)
print("i received " + data)
if data:
if data == "exit":
x.close()
input.remove(x)
running = 0
else:
x.send(data)
print("I am sending %s" % (data))
else:
x.close()
input.remove(x)
s.close()
Any help or ideas would be greatly appreciated. Thanks!!
Well I know you asked this 7 years ago, but I had similar questions so I would figure I answer you. I'm still working and bugfixing a program that has the same functionality, but one thing I do know is that the lists that are the arguments in select.select() need to be file descriptors (ints).
So if you have this block
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
The first thing I'd say is change your read list to not be input. You'll likely get some clashing with the input() function, which may cause confusing bugs. After that, you want the values to be file descriptors. So that first line should be
inputSockets = [s.fileno(), sys.stdin.fileno()]
Then when checking which socket is ready to ready, you would want to do it like this
for x in inputready:
if x == s.fileno():
# Read from your s socket
elif x == sys.stdin().fileno():
# Read from stdin
else:
'''
Here you would want to read from any other sockets you have.
The only problem is your inputSockets array has ints, not socket
objects. What I did was store an array of actual socket objects
alongside the array of file descriptors. Then I looped through the
list of sockets and found which socket's .fileno() matched x. You could
probably be clever and use a dict() with the filenos as key and socket as
value
'''
I just came across this while writing a unix domain socket (UDS) interface. The server socket id is used to accept incoming client connections. That is pretty much all it does. Once the client is accepted, reading uses its own file descriptor. Something like this works:
conn = None
inputReady, Null, Null = select.select(inputSockets, [], [])
for x in inputReady:
if x == s.fileno():
# accept incoming connect and add to poll list
conn, addr = s.accept()
inputReady.append(conn.fileno())
elif x = sys.stdin.fileno():
# read whole line and remove newline
cmd = sys.stdin.readline()[:-1]
...
elif conn and x == conn.fileno():
data = conn.recv(msglen)
if data:
....
else:
# connection has ended, remove from poll list and close
if conn.fileno() in inputReady:
inputReady.remove(conn.fileno())
conn.close()

python xinetd client not receiving data

I'm trying to use xinetd to remotely run a command (traccejob). When I connect through telnet, everything works fine. Unfortuantely, the client that I've written doesn't seem to receive the data from the server. The code looks like:
server:
import sys
import commands
def main():
tjinput = sys.stdin.readline().strip()
(ret, out) = commands.getstatusoutput('/usr/bin/tracejob '+tjinput)
print out
sys.stdout.flush()
if __name__ == "__main__":
main()
client:
host = 'xxx.xxx.xxx.xxx'
port = 12345
import socket
import sys
def main(argv):
message = 'hello'
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host, port))
sock.send(message)
data = sock.recv(1024)
sock.close()
print repr(data)
if __name__ == '__main__':
main(sys.argv)
The client process stops on the sock.recv(1024) line. I can't for the life of me tell why sock.recv isn't reading the output from the socket. Probably a coding issue? If it helps, the xinetd.d file looks like this:
service tracejob
{
flags = IPv4
disable = no
socket_type = stream
wait = no
user = root
group = root
server = /usr/local/bin/tracejob_xinetd.py
port = 12345
type = UNLISTED
}
where tracejob_xinetd.py is the server described above.
Any tips? Thanks in advance.
You have a deadlock situation: The client sends an incomplete line and waits for the server to send something, the server waits for line completion or EOF before it sends a reply.
So you have now 2 ways to proceed now:
Append a \n to the string being sent.
"Half-close" the socket on client side with sock.shutdown(socket.SHUT_WR) after writing, but before reading.

Categories