I'm new to socket programming but with the help of a tutorial i wrote a simple Server and Client. It works
if i connect to the server from the same device the server runs on but if i try to connect from another device it doesn't work. I tried to disable my firewall and some other tips on similar questions but it doesn't work.
This is the Server:
import threading
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOSTNAME = socket.gethostbyname(socket.gethostname())
PORT = 50000
print(HOSTNAME, PORT)
s.bind((HOSTNAME, PORT))
s.listen()
clientList = []
def func():
while True:
conn, addr = s.accept()
conn.send(str.encode("Connected"))
print(addr, " connected")
clientList.append(conn)
t = threading.Thread(target=func2, args=(conn, addr,)).start()
def func2(x, y):
print(bytes.decode(x.recv(1024)))
x.send(str.encode("Type your name"))
y = bytes.decode(x.recv(1024))
for z in clientList:
z.send(str.encode(y + " connected"))
while True:
try:
v = bytes.decode(x.recv(1024))
q = str(y)
h = q + " sent: " + v
print(h)
for z in clientList:
z.send(str.encode(h))
if v == "disconnect":
x.send(str.encode("disconnect"))
clientList.remove(x)
x.close()
threading.current_thread()._delete()
break
time.sleep(0.01)
except:
clientList.remove(x)
for z in clientList:
z.send(str.encode(y + " disconnected"))
print(y + " disconnected")
x.close()
threading.current_thread()._delete()
break
func()
This is the Client:
import socket
import threading
import time
HOSTNAME = "192.168.56.1" # server local ip
PORT = 8080
def Listen(i):
while True:
try:
k = bytes.decode(i.recv(1024))
if k == "disconnect":
i.close()
threading.current_thread()._delete()
break
print(k)
time.sleep(0.01)
except:
print("Disconnected")
i.close()
threading.current_thread()._delete()
break
def Activate(i):
t = threading.Thread(target=Listen, args=(i,))
t.start()
def InputHandler():
while True:
time.sleep(1)
v = input("")
if v == "connect":
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOSTNAME, PORT))
s.send(str.encode("connected"))
Activate(s)
time.sleep(1)
except:
print("Failed")
elif v == "close":
try:
s.send(str.encode("disconnect"))
break
except:
break
else:
try:
s.send(str.encode(v))
except:
print("Failed")
InputHandler()
any ideas what's wrong? please let me knwow.
According to my knowledge, you shouldn't need port forwarding for the simple case you are describing
(that is: if both machines are on the same LAN).
But the link provided by #AvivYaniv in the comments though has some notes about what you are asking which are:
If you're trying to connect from inside the same LAN, there's a very easy solution: use the server's real internal address, not the router's external address.
It seems like you already know what is the IP address of the server machine,
because in the client you write the HOSTNAME variable as equal to 192.168.56.1.
Anyway though try setting your server's bind address to empty. ie instead of:
HOSTNAME = socket.gethostbyname(socket.gethostname())
try:
HOSTNAME = ''
at the server side.
Also there are some useful notes on this tutorial like:
A couple things to notice: we used socket.gethostname() so that the socket would be visible to the outside world. If we had used s.bind(('localhost', 80)) or s.bind(('127.0.0.1', 80)) we would still have a "server" socket, but one that was only visible within the same machine. s.bind(('', 80)) specifies that the socket is reachable by any address the machine happens to have.
Edit 1:
If you are not using VMs, then no problem: just find the IP of the server machine and put into the HOSTNAME of the client. If you set the server's HOSTNAME to empty then the client should connect to the IP of the server. Try finding your IP (NOT the router's external IP but your server's machine LAN IP). For example if your are on Windows, go to Control Panel like shown in this tutorial.
This question already has answers here:
Utilising bluetooth on Mac with Python
(2 answers)
Closed 4 years ago.
I am using a mac to try and send a string wirelessly to a raspberry pi using Bluetooth with python. However, I was not able to find an API that works with mac. I have tried options like pybluez and lightblue, but it seems like they don't work with mac. Is there a solution available for this? Bluetooth communication would be preferable, but I am open to other suggestions. Thanks in advance
Updated Answer
Still using netcat approach as below, but this is the sender implemented in Python adapted from this answer and works with the receiver below:
#!/usr/local/bin/python3
import socket
def netcat(host, port, content):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, int(port)))
s.sendall(content.encode())
s.shutdown(socket.SHUT_WR)
while True:
data = s.recv(4096)
if not data:
break
print(repr(data))
s.close()
netcat('192.168.0.131', 40000, 'Hi')
Here is a matching listener/server as implemented here that works with the sender above or the simple netcat sender from the command line.
#!/usr/bin/env python
import socket
import select
class SocketServer:
""" Simple socket server that listens to one single client. """
def __init__(self, host = '0.0.0.0', port = 2010):
""" Initialize the server with a host and port to listen to. """
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.host = host
self.port = port
self.sock.bind((host, port))
self.sock.listen(1)
def close(self):
""" Close the server socket. """
print('Closing server socket (host {}, port {})'.format(self.host, self.port))
if self.sock:
self.sock.close()
self.sock = None
def run_server(self):
""" Accept and handle an incoming connection. """
print('Starting socket server (host {}, port {})'.format(self.host, self.port))
client_sock, client_addr = self.sock.accept()
print('Client {} connected'.format(client_addr))
stop = False
while not stop:
if client_sock:
# Check if the client is still connected and if data is available:
try:
rdy_read, rdy_write, sock_err = select.select([client_sock,], [], [])
except select.error:
print('Select() failed on socket with {}'.format(client_addr))
return 1
if len(rdy_read) > 0:
read_data = client_sock.recv(255)
# Check if socket has been closed
if len(read_data) == 0:
print('{} closed the socket.'.format(client_addr))
stop = True
else:
print('>>> Received: {}'.format(read_data.rstrip()))
if read_data.rstrip() == 'quit':
stop = True
else:
client_sock.send(read_data)
else:
print("No client is connected, SocketServer can't receive data")
stop = True
# Close socket
print('Closing connection with {}'.format(client_addr))
client_sock.close()
return 0
def main():
server = SocketServer(port=40000)
server.run_server()
print('Exiting')
if __name__ == "__main__":
main()
Original Answer
Try using netcat or nc.
On RaspberryPi, listen on port 40,000 using TCP:
nc -l 40000
On Mac, assuming RaspberryPi has IP address of 192.168.0.131:
echo "hi" | /usr/bin/nc 192.168.0.131 40000
RaspberryPi shows:
hi
I am having some problems adding in a logging file for my python TCP server code.
I've looked at some examples, but as I don't have much experience in writing my own scripts/codes, I'm not very sure how to go about doing this. I would appreciate if someone could guide me in the right direction with explanation and some examples if possible.
I am using HERCULES SETUP UTILITY , which acts as my TCP client, while my visual studio python code acts as a SERVER. My SERVER can receive the data which is sent by the client by now , I just can't seem to add in a logging file which can save the sent data into text file.Can someone please show me some examples or referance please? Your help would mean alot. This is my code so far :
from socket import *
import thread
BUFF = 1024 # buffer size
HOST = '172.16.166.206'# IP address of host
PORT = 1234 # Port number for client & server to recieve data
def response(key):
return 'Sent by client'
def handler(clientsock,addr):
while 1:
data = clientsock.recv(BUFF) # receive data(buffer).
print 'data:' + repr(data) #Server to recieve data sent by client.
if not data: break #If connection is closed by client, server will break and stop recieving data.
print 'sent:' + repr(response('')) # respond by saying "Sent By Client".
if __name__=='__main__':
ADDR = (HOST, PORT) #Define Addr
serversock = socket(AF_INET, SOCK_STREAM)
serversock.bind(ADDR) #Binds the ServerSocket to a specific address (IP address and port number)
serversock.listen(0)
while 1:
print 'waiting for connection...'
clientsock, addr = serversock.accept()
print '...connected from:', addr #show its connected to which addr
thread.start_new_thread(handler, (clientsock, addr ))
In context, maybe something like this?
#!/usr/local/cpython-2.7/bin/python
import socket
import thread
BUFF = 1024 # buffer size
HOST = '127.0.0.1'
PORT = 1234 # Port number for client & server to recieve data
def response(key):
return 'Sent by client'
def logger(string, file_=open('logfile.txt', 'a'), lock=thread.allocate_lock()):
with lock:
file_.write(string)
file_.flush() # optional, makes data show up in the logfile more quickly, but is slower
def handler(clientsock, addr):
while 1:
data = clientsock.recv(BUFF) # receive data(buffer).
logger('data:' + repr(data) + '\n') #Server to recieve data sent by client.
if not data:
break #If connection is closed by client, server will break and stop recieving data.
logger('sent:' + repr(response('')) + '\n') # respond by saying "Sent By Client".
if __name__=='__main__':
ADDR = (HOST, PORT) #Define Addr
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind(ADDR) #Binds the ServerSocket to a specific address (IP address and port number)
serversock.listen(0)
while 1:
logger('waiting for connection...\n')
clientsock, addr = serversock.accept()
logger('...connected from: ' + str(addr) + '\n') #show its connected to which addr
thread.start_new_thread(handler, (clientsock, addr))
HTH
It sounds to me like your question would be better rephrased as “How do I read and write files within Python?”.
This is something well documented at: http://docs.python.org/2.7/tutorial/inputoutput.html#reading-and-writing-files
Example:
f = open('/tmp/log.txt', 'a')
f.write('Doing something')
do_something()
f.write('Other stuff')
other_stuff()
f.write('All finished')
f.close()
How can I know if a certain port is open/closed on linux ubuntu, not a remote system, using python?
How can I list these open ports in python?
Netstat:
Is there a way to integrate netstat output with python?
You can using the socket module to simply check if a port is open or not.
It would look something like this.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('127.0.0.1',80))
if result == 0:
print "Port is open"
else:
print "Port is not open"
sock.close()
If you want to use this in a more general context, you should make sure, that the socket that you open also gets closed. So the check should be more like this:
import socket
from contextlib import closing
def check_socket(host, port):
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
if sock.connect_ex((host, port)) == 0:
print("Port is open")
else:
print("Port is not open")
For me the examples above would hang if the port wasn't open. Line 4 shows use of settimeout to prevent hanging
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2) #2 Second Timeout
result = sock.connect_ex(('127.0.0.1',80))
if result == 0:
print 'port OPEN'
else:
print 'port CLOSED, connect_ex returned: '+str(result)
If you only care about the local machine, you can rely on the psutil package. You can either:
Check all ports used by a specific pid:
proc = psutil.Process(pid)
print proc.connections()
Check all ports used on the local machine:
print psutil.net_connections()
It works on Windows too.
https://github.com/giampaolo/psutil
Here's a fast multi-threaded port scanner:
from time import sleep
import socket, ipaddress, threading
max_threads = 50
final = {}
def check_port(ip, port):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
#sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
socket.setdefaulttimeout(2.0) # seconds (float)
result = sock.connect_ex((ip,port))
if result == 0:
# print ("Port is open")
final[ip] = "OPEN"
else:
# print ("Port is closed/filtered")
final[ip] = "CLOSED"
sock.close()
except:
pass
port = 80
for ip in ipaddress.IPv4Network('192.168.1.0/24'):
threading.Thread(target=check_port, args=[str(ip), port]).start()
#sleep(0.1)
# limit the number of threads.
while threading.active_count() > max_threads :
sleep(1)
print(final)
Live Demo
I found multiple solutions in this post. But some solutions have a hanging issue or takeing too much time in case of the port is not opened.Try below solution :
import socket
def port_check(HOST):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2) #Timeout in case of port not open
try:
s.connect((HOST, 22)) #Port ,Here 22 is port
return True
except:
return False
port_check("127.0.1.1")
In case when you probing TCP ports with intention to listen on it, it’s better to actually call listen. The approach with tring to connect don’t 'see' client ports of established connections, because nobody listen on its. But these ports cannot be used to listen on its.
import socket
def check_port(port, rais=True):
""" True -- it's possible to listen on this port for TCP/IPv4 or TCP/IPv6
connections. False -- otherwise.
"""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', port))
sock.listen(5)
sock.close()
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(('::1', port))
sock.listen(5)
sock.close()
except socket.error as e:
return False
if rais:
raise RuntimeError(
"The server is already running on port {0}".format(port))
return True
Building upon the psutil solution mentioned by Joe (only works for checking local ports):
import psutil
1111 in [i.laddr.port for i in psutil.net_connections()]
returns True if port 1111 currently used.
psutil is not part of python stdlib, so you'd need to pip install psutil first. It also needs python headers to be available, so you need something like python-devel
Agree with Sachin. Just one improvement, use connect_ex instead of connect, which can avoid try except
>>> def port_check(ip_port):
... s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
... s.settimeout(1)
... return s.connect_ex(ip_port) == 0
...
>>> port_check(loc)
True
>>> port_check(loc_x)
False
>>> loc
('10.3.157.24', 6443)
>>>
Just added to mrjandro's solution some improvements like automatic resource management (making sure that the opened socket also gets closed), handling timeouts, getting rid of simple connection errors / timeouts and printing out results:
import socket
from contextlib import closing
hosts = ["host1", "host2", "host3"]
port = 22
timeout_in_seconds = 2
hosts_with_opened_port = []
hosts_with_closed_port = []
hosts_with_errors = []
def check_port(host, port, timeout_in_seconds):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout_in_seconds)
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
try:
result = sock.connect_ex((host, port))
if result == 0:
print("Port {} is *** OPEN *** on host: {}".format(port, host))
hosts_with_opened_port.append(host)
else:
print("Port {} is not open on host: {}".format(port, host))
hosts_with_closed_port.append(host)
except socket.gaierror:
print("Port {} check returns a network *** ERROR *** on host: {}".format(port, host))
hosts_with_errors.append(host)
for host in hosts:
check_port(host, port, timeout_in_seconds)
print("\nHosts with opened port:")
print(hosts_with_opened_port)
print("\nHosts with closed port:")
print(hosts_with_closed_port)
print("\nHosts with errors:")
print(hosts_with_errors)
Netstat tool simply parses some /proc files like /proc/net/tcp and combines it with other files contents. Yep, it's highly platform specific, but for Linux-only solution you can stick with it. Linux kernel documentation describes these files in details so you can find there how to read them.
Please also notice your question is too ambiguous because "port" could also mean serial port (/dev/ttyS* and analogs), parallel port, etc.; I've reused understanding from another answer this is network port but I'd ask you to formulate your questions more accurately.
Please check Michael answer and vote for it. It is the right way to check open ports. Netstat and other tools are not any use if you are developing services or daemons. For instance, I am crating modbus TCP server and client services for an industrial network. The services can listen to any port, but the question is whether that port is open? The program is going to be used in different places, and I cannot check them all manually, so this is what I did:
from contextlib import closing
import socket
class example:
def __init__():
self.machine_ip = socket.gethostbyname(socket.gethostname())
self.ready:bool = self.check_socket()
def check_socket(self)->bool:
result:bool = True
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
modbus_tcp_port:int = 502
if not sock.connect_ex((self.machine_ip, modbus_tcp_port)) == 0:
result = False
return result
This will find a random port in the given range:
import socket
import random
from typing import Tuple
def find_listening_port(
port_range:Tuple[int,int]=None,
host='',
socket_type='tcp',
default:int=None
) -> int:
"""Find an available listening port
Arguments:
port_range: Optional tuple of ports to randomly search, ``[min_port, max_port]``
If omitted, then randomly search between ``[6000, 65534]``
host: Host interface to search, if omitted then bind to all interfaces
socket_type: The socket type, this should be ``tcp`` or ``udp``
default: The port to try first before randomly searching the port range
Returns:
Available port for listening
"""
def _test_port(host, port, socket_protocol):
with socket.socket(socket.AF_INET, socket_protocol) as sock:
try:
sock.bind((host, port))
if socket_type == 'tcp':
sock.listen(1)
return port
except:
pass
return -1
if port_range is None:
port_range = (6000,65534)
if socket_type == 'tcp':
socket_protocol = socket.SOCK_STREAM
elif socket_type == 'udp':
socket_protocol = socket.SOCK_DGRAM
else:
raise Exception('Invalid socket_type argument, must be: tcp or udp')
searched_ports = []
if default is not None:
port = _test_port(host, default, socket_protocol)
if port != -1:
return port
searched_ports.append(default)
for _ in range(100):
port = random.randint(port_range[0], port_range[1])
if port in searched_ports:
continue
port = _test_port(host, port, socket_protocol)
if port != -1:
return port
searched_ports.append(port)
raise Exception(f'Failed to find {socket_type} listening port for host={host}')
Example usage:
# Find a TCP port,
# first check if port 80 is availble
port = find_listening_port(
port_range=(4000, 60000),
host='',
socket_type='tcp',
default=80
)
print(f'Available TCP port: {port}')
I have uploaded the server script to the public directory on the server machine. Then I try to connect to the server by a client, but I am not being connected. Here is my code snippets:
# Echo client program
import socket
HOST = 'www.dotpy.ir/server.py' # The remote host
PORT = 50007 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
server:
# Echo server program
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
conn.send(data)
conn.close()
These scripts seem to work well.
However, the script at the server must be run on the server for this to work. It's not enough for it to be uploaded to the public file area. What access do you have to the servers? Can you have scripts running on them?
If you succeed in running the script, then you will have to change the client script from:
HOST = 'www.dotpy.ir/server.py' # The remote host
to
HOST = 'www.dotpy.ir' # The remote host
The reason is that you will connect to the host itself. There the script will be running, listening to any inbound connections on the port specified. You can't conect to a specific script.
Good luck!