Question regarding the python socket package
My goal is to create a simple network port scanner. This is the basic idea:
#List of ports to scan
ports = [20,21,22,23,25,80]
#dictionary of port statuses
port_status = {}
#Create socket:
MY_SOCK = s.socket(s.AF_INET, s.SOCK_STREAM)
#For loop to scan each port
for port in ports:
TARGET = ("192.168.12.123", port)
#If connection is successful, result should be int 0
result = MY_SOCK.connect_ex(TARGET)
#save port and status as key/pair value
port_status[port] = result
#Terminate socket
MY_SOCK.shutdown(s.SHUT_RDWR)
MY_SOCK.close()
I am having an issue that after the first successful socket connection, it doesn't restart properly for the following sockets.
With the syntax shown above, I get thrown an OSerror
if I don't do a shutdown, it makes one successful connection then doesn't connect to the following ports.
There must be something wrong with my closing of the socket.
Any advice? Many thanks
By running it line by line outside the loop, I managed to pinpoint the problem.
The issue is that if a connection fails, it throws an error because it could not terminate a failed connection
I solved it (incorporating h4z3's advice to move the socket creation into the for loop) in the following way:
for port in ports:
MY_SOCK = s.socket(s.AF_INET, s.SOCK_STREAM)
TARGET = ("192.168.12.123", port)
result = MY_SOCK.connect_ex(TARGET)
port_status[port] = result
#Only attempt to close connection if connection was successful (== 0)
if result == 0:
MY_SOCK.shutdown(s.SHUT_RDWR)
MY_SOCK.close()
Thanks for the assistance
Related
This question already has answers here:
Make a connection between two computers behind NAT
(1 answer)
How can i connect two computers with python socket?
(2 answers)
Closed 1 year ago.
I am using Mobile Hotspot with configurations Security:WPA2-Personal and AP Band:2.4GHz-band.
Server code:
import socket
s = socket.socket()
print ("Socket successfully created")
s.bind(("0.0.0.0", 9999)) # xxxx also does not work
# xxx=external ip address returned by https://checkip.amazonaws.com/
s.listen(3)
print("waiting for connections...")
while True:
print ("Entered while loop!!!")
flag = input("Stop: ")
if flag == "y":
break
# Establish connection with client.
c, addr = s.accept()
print ('Got connection from', addr )
# send a thank you message to the client. encoding to send byte type.
c.send('Thank you for connecting 9433'.encode())
# Close the connection with the client
c.close()
flag = input("Stop: ")
if flag == "y":
break
Client Code:
# Import socket module
import socket
# Create a socket object
s = socket.socket()
# Define the port on which you want to connect
port = 9999
# connect to the server on local computer
s.connect(('xxxx', port)) # xxxx=external ip address returned by https://checkip.amazonaws.com/
# receive data from the server and decoding to get the string.
print (s.recv(1024).decode())
# close the connection
s.close()
What I want to achieve
Let's say I have started the server in one of my computer(note:moblie hotspot connected). My other computer is in another apartment connected to another mobile hotspot. I want them to communicate in all ways possible- such as checking battery level, asking to create a folder or file, sending or receving file, etc. In all of this, my laptop acts like a server and the other PC always keep checking if the server is running. If runing, it connects to my laptop
Current Problem
I can do this communication using localhost. But cannot do it in two completely seperate Pcs💻.
I am getting the error Win 10060 in my current code.
Please note: The above code is in its simplest form and I am just trying to establish the connection so that I can send and receive data. After that I will modify it.
If My approach is wrong or there is conceptual problem, please write in the comments.
I'm reading about socket module in a web learning site about python, they gave us a simple steps to use socket module like follows:
import socket
with socket.socket() as client_socket:
hostname = '127.0.0.1'
port = 9090
address = (hostname, port)
client_socket.connect(address)
data = 'Wake up, Neo'
data = data.encode()
client_socket.send(data)
response = client_socket.recv(1024)
response = response.decode()
print(response)
when executing I got the error message:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it.
when I searched about this some sites was talking about server listening and I see in most of tutorials about server socket and they use it along with client one.
so Is the error message related to the fact that I'm not using a server socket and is it a must to use them both
Update:
after reading the answers I got, I went to the test.py file that the course instructors use to evaluate our codes and I see that they make the server socket in it , so the server is already made by them. that take me back to the Error I got why does it happen then.
def server(self):
'''function - creating a server and answering clients'''
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(('localhost', 9090))
self.ready = True
try:
self.sock.listen(1)
conn, addr = self.sock.accept()
self.connected = True
conn.settimeout(15)
while True:
data = conn.recv(1024)
self.message.append(data.decode('utf8'))
if len(self.message) > 1_000_000:
conn.send(
json.dumps({
'result': 'Too many attempts to connect!'
}).encode('utf8'))
break
if not data:
break
Each connection requires a client, which initiates the connection, and a server, which listens for the incoming connection from the client. The code you have shown is for the client end of the connection. In order for this to run successfully you will need a server listening for the connection you are trying to create.
In the code you showed us you have the lines
hostname = '127.0.0.1'
port = 9090
address = (hostname, port)
client_socket.connect(address)
These are the lines that define what server you are connecting to. In this case it is a server at 127.0.0.1 (which is localhost, the same machine you are running the code on) listening on port 9090.
If you want to make your own server then you can look at the documentation for Python sockets and the particular functions you want to know about are bind, listen, and accept. You can find examples at the bottom of that same page.
Given that you appear to have found this code as part of a course, I suspect they may provide you with matching server code at some point in order to be able to use this example.
I am trying to gather data from sensors connected to a raspberry pi and send them over to my laptop for some processing. I have written a very basic matlab server (for on my laptop)
t = tcpip('127.0.0.1', 42069, 'NetworkRole', 'server');
fopen(t);
flag = true;
while flag
if t.BytesAvailable > 0
t.BytesAvailable
raw_data = fread(t, t.BytesAvailable);
data = typecast(uint8(raw_data), 'double');
current_x = data(1);
current_y = a.cell_size*a.rows - data(2);
current_th = -data(3);
flag = false;
end
end
.
.
.
fclose(t)
On my PI I have written the following class to handle sending the data over.
class LocalizationClient():
#TCP_IP = '127.0.0.1'
TCP_IP = '192.168.1.5'
TCP_PORT = 42069
BUFFER_SIZE = 1000
# MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def __init__(self):
self.s.connect((self.TCP_IP, self.TCP_PORT))
print("connected to server")
def sendData(self,MESSAGE):
try:
self.s.send(MESSAGE)
except BrokenPipeError as e:
print(e)
self.close()
raise RuntimeError()
In my driver code I create an object and try to send a message like so:
lo_c = lc.LocalizationClient()
lo_c.sendData(np.array([float(x), float(y), float(th)]))
.
.
.
for x in range(50):
measures = lidar.measures
measures = np.append([float(dx), float(dy), float(dth)], measures)
lo_c.sendData(measures)
time.sleep(.2)
All of this was working fine and dandy while I was just testing with loopback on my laptop, but when I tried to put it on the pi I get the following error on the python client side:
connected to server
[Errno 32] Broken pipe
Traceback (most recent call last):
File "/home/pi/Desktop/EXAMPLES/LocalizationClient.py", line 21, in sendData
self.s.send(MESSAGE)
BrokenPipeError: [Errno 32] Broken pipe
It seems that connecting still works but when I try to send to the server the client throws an error. The server seems fine and Im not trying to send any data back over to the client yet. I have been banging my head into this one for a while now and any help would be appreciated.
ps some details about the network setup if it helps, I have put the pi in ad-hoc mode with IP statically assigned as 192.168.1.1 and connected my macbook to the network it created. My Mac is assigned static IP 192.168.1.5.
So I figured out the issue. While I could see the port was open the way the matlab TCPIP object works is that it will silently refuse any connection that does not come from the IP passed into the constructor. So I was able to construct the object which would listen for a connection on the port. On the python side my client would see this "connect" but really the server was refusing the connection causing broken pipe. (this is also why it was working fine on local host but not remote)
Fix is easy just change:
t = tcpip('127.0.0.1', 42069, 'NetworkRole', 'server');
fopen(t);
to:
t = tcpip('0.0.0.0', 42069, 'NetworkRole', 'server');
fopen(t);
This will allow matlab server to accept a connection from any ip on LAN on specified port. Alternatively one could supply matlab server with clients IP to only accept connections from the one device but if IP is not static then it might change on you. Also is important to disable firewalls on devices.
I am currently building an automated trash bin using Raspberry Pi 3 B+ with Android application support where I would use a servo motor as an actuator for the lid and the Android application as a form of wireless remote control. Everything went on smoothly until I've encountered a problem that whenever I attempt to press a button on my Android application, the Python shell program has errors during testing. I've used a reference video (https://www.youtube.com/watch?v=t8THp3mhbdA&t=1s) and followed everything thoroughly until I've hit this roadblock.
The results to me that keeps appearing are:
Waiting for connection
...connected from :
Where the supposed result, according to the reference video, is:
Waiting for connection
...connected from : ('192.168.1.70', 11937)
Increase: 2.5
As you can see, the IP address, the port, and 'Increase' text doesn't appear, meaning there is something wrong with the code.
According to some comments that was made by the people who watched the video, this code is outdated, using Python 2, and the latest version we have now is Python 3, and that we need to use a ".encode()" line in a condition. However, as someone who is still new to Python, I'm afraid that I still don't have the knowledge to apply this on the code.
Here is the code that was used in the video:
import Servomotor
from socket import *
from time import ctime
import RPi.GPIO as GPIO
Servomotor.setup()
ctrCmd = ['Up','Down']
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print 'Waiting for connection'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from :', addr
try:
while True:
data = ''
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
if data == ctrCmd[0]:
Servomotor.ServoUp()
print 'Increase: ',Servomotor.cur_X
if data == ctrCmd[1]:
Servomotor.ServoDown()
print 'Decrease: ',Servomotor.cur_X
except KeyboardInterrupt:
Servomotor.close()
GPIO.cleanup()
tcpSerSock.close();
I have already changed the text strings that used the ' ' format into the (" ") format since it also produced some errors in the code which I corrected immediately.
Any help will be greatly appreciated and thank you in advance!
Here's a Python3 version, edited a tiny bit for better clarity and good practice:
import Servomotor
import RPi.GPIO as GPIO
import socket
# Setup the motor
Servomotor.setup()
# Declare the host address constant - this will be used to connect to Raspberry Pi
# First values is IP - here localhost, second value is the port
HOST_ADDRESS = ('0.0.0.0', 21567)
# Declare the buffer constant to control receiving the data
BUFFER_SIZE = 4096
# Declare possible commands
commands = 'Up', 'Down'
# Create a socket (pair of IP and port) object and bind it to the Raspberry Pi address
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(HOST_ADDRESS)
# Set the socket to listen to an incoming connection (1 at a time)
server_socket.listen(1)
# Never stop the server once it's running
while True:
# Inform that the server is waiting for a connection
print("Waiting for connection to the following address: {}...".format(HOST_ADDRESS))
# Perform a blocking accept operation to wait for a client connection
client_socket, client_address = server_socket.accept()
# Inform that the client is connected
print("Client with an address {} connected".format(client_address))
# Keep exchanging data
while True:
try:
# Receive the data (blocking receive)
data = client_socket.recv(BUFFER_SIZE)
# If 0-byte was received, close the connection
if not data:
break
# Attempt to decode the data received (decode bytes into utf-8 formatted string)
try:
data = data.decode("utf-8").strip()
except UnicodeDecodeError:
# Ignore data that is not unicode-encoded
data = None
# At this stage data is correctly received and formatted, so check if a command was received
if data == commands[0]:
Servomotor.ServoUp()
print("Increase: {}".format(Servomotor.cur_X))
elif data == commands[1]:
Servomotor.ServoDown()
print("Decrease: {}".format(Servomotor.cur_X))
elif data:
print("Received invalid data: {}".format(data))
# Handle possible errors
except ConnectionResetError:
break
except ConnectionAbortedError:
break
except KeyboardInterrupt:
break
# Cleanup
Servomotor.close()
GPIO.cleanup()
client_socket.close()
# Inform that the connection is closed
print("Client with an address {} disconnected.".format(client_address))
To show you the code in action, I have hosted a local server on my machine and connected to it using Putty. Here are the commands I have entered:
Here is the output of the server (I have swapped the Servo-related functions to print statements):
Waiting for connection to the following address: ('0.0.0.0', 21567)...
Client with an address ('127.0.0.1', 61563) connected.
Received invalid data: Hello
Received invalid data: Let's try a command next
Running ServoUp
Increase: 2.5
Running ServoDown
Decrease: 2.5
Received invalid data: Nice!
Client with an address ('127.0.0.1', 61563) disconnected.
Waiting for connection to the following address: ('0.0.0.0', 21567)...
I've got a Python 3 server script which runs a TCP socket server, detecting and responding to incoming data using select.select()
I'm using select.select() to handle multiple connections without threading and the server is mainly reactive (only waits for data and responds to that). It keeps a dictionary for each connection and parameters of the device at the other end; each device's entry is deleted upon its connection being closed.
My problem is my clients will sometimes lose connection without actually closing the TCP socket, I can't work out how to catch or create a timeout to close the sockets and remove old connections from the dictionary.
Is there a good way to do this?
Here's a simplified copy of the script:
host = '192.168.0.252'
port = 9989
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host,port))
server.listen(16)
socks = [server]
devices = {}
while True:
readable,writable,exceptionavailable = select.select(socks,[],[])
for s in readable:
if(s == server):
client, address = server.accept()
socks.append(client)
else:
try: data = s.recv(1024)
except ConnectionResetError: data = 0
if data:
print(data) # Would append device to "devices" dictionary
else:
s.close()
socks.remove(s)
del(devices[did]) # did is the ID that needs deleting from dictionary
Any help would be much appreciated.
Edit: Updated with better code per #Daniel's comment.
Let's say you want to close a connection if you haven't read from it in X seconds. Then you have to:
For each socket keep track of the last time you read from it.
Each time select returns update the last read time and close the connections which have timed-out.
In this code a connection's timeout is set to 300 seconds.
lastread = {} # a dictionary with sockets as keys
...
readable,_,_ = select.select(socks,[],[], 60)
now = time()
for s in readable:
... read from the socket s and process input ...
lastread[s] = now
closed = []
for s in lastread:
if s not in readable and now - lastread[s] > 300:
... close connection ...
closed.append(s)
for s in closed: del lastread[s]
Notes:
The timeout passed to select (60 in this case) doesn't have much to do with the timeout for a connection. It just says that you want control handed back to you after at most 60 seconds.
Be sure to initialize lastread[s] when you create the socket s and delete the key when you close the connection.
Some more resources:
A tutorial on using select with a timeout (link)
An article which discusses the dropped TCP connection problem and some other solutions: (link)