PC to raspberry Pi via TCP/IP socket - python

I am trying to do wireless communications between a PC (macbook) and a Raspberry Pi 2 using python's socket module (python 2.7). The server is the PC and the client is the Pi.
When I run the code (server first then client) both scripts get stuck on the socket.accept() and socket.connect() methods respectfully.
What is funny is that when I do the reverse (Pi being the server and PC being the client) the code works fine, with data been sent correctly.
The scripts below are meant to loop forever whilst incrementing a counter sent over (I increment the port's after each succesful transfer to avoid '[Errno 48] Address already in use' (probably terrible practice I know))
My client script:
import socket
import sys
def read(port):
s = socket.socket()
host = '10.19.92.44' #(IP address of PC (server))
s.connect((host,port))
try:
msg = s.recv(1024)
s.close()
except socket.error, msg:
sys.stderr.write('error %s'%msg[1])
s.close()
print 'close'
sys.exit(2)
return msg
if __name__ == '__main__':
port = 1025
while True:
print 'hey, checking TCP socket'
data = read(port)
print 'i just read %s' % data
print 'port num is: %d' % port
port = port + 1
My server script:
import socket
import time
def send(data, port):
s = socket.socket()
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print 'Got connection from',addr
c.send(data)
c.close()
if __name__ == '__main__':
port = 1025
num = 1
while True:
print 'hey, sending data'
words = 'helloWorld'
data = words + str(num)
print 'send data: %s' % data
send(data,port)
port = port + 1
num = num + 1
As I mentioned when I swap roles (and replace the server IP address in the client script to the Pis 172.17.33.125) the code works fine...
Any ideas/suggestions?
Thank you very much

I don't have an immediate answer, but I have a couple of ideas.
Your PC and Pi seem to be in different networks. The PC's address is 10.19.92.44, while Pi's is 172.17.33.125. There's a probability that 10.19.92.44 isn't the address you need. In order to find out what is the correct PC IP address to use in the application:
Issue networksetup -listallhardwareports to figure out the name of your wifi interface (should be like en0, en1).
Issue ifconfig, find the wifi interface. The IP address attached to this interface is the one you need.
Another option is to install wireshark on the PC, set up a working system (server-Pi, client-PC) and use wireshark to capture the traffic between the PC and Pi. Wireshark makes it easy to figure out IP addresses of both parties. I would advise to have this program installed whenever you want to debug a complicated networking issue.

Related

How can i connect two computers with python socket?

im new here!
I have a problem with connection between two computers connected with different wi-fi's. After about 20 seconds i get information that connection can't be done.
There is my code:
SERVER:
from socket import *
lista = ['computer']
s = socket(AF_INET, SOCK_STREAM)
port = 21312
s.bind(('my ipv4', port))
s.listen(5)
while True:
for i in range (0, len(lista)):
a = str(lista[i]).encode()
c, addr = s.accept()
print("CONNECTION WITH",addr)
c.send(a)
print(a)
c.close()
CLIENT:
import socket
from socket import *
port = 21312
while True:
s = socket(AF_INET,SOCK_STREAM)
s.connect(('my ipv4', port))
odebrana = (s.recv(1024))
decoded = odebrana.decode()
print(decoded)
s.close()
Likely you are experiencing an issue because your server sits behind a Network Address Translator (NAT). This way your client cannot use the server's IP directly since it is not reachable. There are a few ways around it.
The easiest and not very practical one is: get both machines in the same network, then it should work.
Get a public IP address for the server. You can do that by hosting it on a cloud server that provides you with a public IP, e.g., aws, azure, google cloud etc.
In the old days we used hamachi to get a VPN that would connect both machines. Then they can identify each other over that VPN. Simply turn on hamachi (or any other VPN solution), run your server, then from your client (connected to the VPN), use the VPN's server IP (hamachi will provide you with one when you setup a network).
Disclaimer: I have not used hamachi in about 15 years, but just went through the process because of one of the comments below.
Seems like you can create an account, then once you turn it on you should see your v4 and v6 addresses as shown below:
Highlighted is my v4 address. I suspect you need to create a network, join both PCs in the same network and then use hamachi's IP to emulate behaviour as if they were connected via LAN.
So I faced the similar problem while sending image files between 2 computers using python sockets. I solved the issue by following this way:
First I completed writing the connection code of both server.py and client.py
Note: server.py should be in one computer and client.py should be in another computer.
server.py
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
print(host)
server.bind((host, 12000))
server.listen()
client_socket, client_address = server.accept()
file = open('server_image.jpg','wb')
image_chunk = client_socket.recv(2048)
while image_chunk:
file.write(image_chunk)
image_chunk = client_socket.recv(2048)
file.close()
client_socket.close()
client.py
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET = IP, SOCK_STREAM = TCP
server_host = 'LAPTOP-1231' # Replace this hostname with hostname printed in server.py
client.connect((server_host, 12000)) # 127.0.0.1
file = open('That_Sinking_Feeling_27.jpg', 'rb')
image_data = file.read(2048)
while image_data:
client.send(image_data)
image_data = file.read(2048)
file.close()
client.close()
Now you should add the image in the directory where client.py is located, so that you can send it to another computer (server). Rename it to img.jpg
Then, you need to run server.py in your another computer. It will print the hostname in terminal. Then copy that hostname and paste it in client.py (server_host = hostname_from_server)
Then run client.py
Finally the image will be transferred to new computer (server)

Python server TCP server accessable from anywhere (via external IP, port forwarding is done)

I am new here, so please, don't be angry if I am stupid - but I don't know about it.
I would like to make a python TCP server, which can be accessed from anywhere via external (public) IP. I have done simple server (it works) in local network from this tutorial:
https://www.youtube.com/watch?v=XiVVYfgDolU
The client sends string and the server sends back that string but with uppercase.
Now I want to do the same but accessable from anywhere. I read a lot about it. I have Raspberry Pi, where I set up static IP address and I did the port forward (on port 42424). I am just looking for some tutorial, you can direct me anywhere - thats all I need. Or you can tell me how to do it step by step, but I know that it takes a lot of time to write answer. I tried googling, but I didn't find anything. And if I did, it was a person who didn't know what the external IP and the port forwarding is so the end of the conversation was: Learn what is port forwarding.
So please, give me some tips how to do it, or direct me somewhere. Thanks!
The code
Server:
import socket
def Main():
host = '10.0.0.140'
port = 42424
s = socket.socket()
s.bind((host, port))
s.listen(1)
c, addr = s.accept()
while True:
data = c.recv(1024)
if not data:
break
data = str(data).upper()
c.send(data)
c.close()
if __name__ == '__main__':
Main()
Client:
import socket
def Main():
host = '10.0.0.140'
port = 42424
s = socket.socket()
s.connect((host,port))
message = raw_input("->")
while message != 'q':
s.send(message)
data = s.recv(1024)
message = raw_input("->")
s.close()
if __name__ == '__main__':
Main()
When connecting to a server behind a NAT firewall/router, in addition to port forwarding, the client should be directed to the IP address of the router. As far as the client is concerned, the IP address of the router is the server. The router simply forwards the traffic according to the port forwarding rules.

Send/receive Packets with TCP sockets

Recently, I managed to create sockets on my PC and my Raspberry Pi to enable communication between both devices. Currently, the client is able to automatically send messages to the server. I was wondering, if it is possible to modify the scripts to send tcp data packets instead of purely text messages, as I would very much like to control the raspberry pi using my PC in the future without having the need to ssh/etc.
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.
Anyway here is the server/client script I'm running at the moment:
Client:
import socket
import sys
import struct
import time
#main function
if __name__ == "__main__":
if(len(sys.argv) < 2) :
print 'Usage : python client.py hostname'
sys.exit()
host = sys.argv[1]
port = 8888
#create an INET, STREAMing socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print 'Socket Created'
try:
remote_ip = socket.gethostbyname( host )
s.connect((host, port))
except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
#Send some data to remote server
message = "Test"
try :
#Set the whole string
while True:
s.send(message)
print 'Message sent successfully'
time.sleep(1)
print 'Sending...'
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
def recv_timeout(the_socket,timeout=2):
#make socket non blocking
the_socket.setblocking(0)
#total data partwise in an array
total_data=[];
data='';
#beginning time
begin=time.time()
while 1:
#if you got some data, then break after timeout
if total_data and time.time()-begin > timeout:
break
#if you got no data at all, wait a little longer, twice the timeout
elif time.time()-begin > timeout*2:
break
#recv something
try:
data = the_socket.recv(8192)
if data:
total_data.append(data)
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
except:
pass
#join all parts to make final string
return ''.join(total_data)
#get reply and print
print recv_timeout(s)
s.close()
Server:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10)
print 'Socket now listening'
#Function for handling connections
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Receving Data...\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'Message Received at the server!\n'
print data
if not data:
break
conn.sendall(reply)
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread
start_new_thread(clientthread ,(conn,))
s.close()
socket.socket(socket.AF_INET, socket.SOCK_STREAM) already creates a connection that provides a reliable stream of bytes between two machines. This uses TCP, which is on top of IP and Ethernet. The latter two are package-based, while TCP creates a stream of continuous bytes on top of it. It also adds some error checking and error correction, so it is pretty reliable.
I honestly don't understand what you want to achieve with what you call "send packets". What you don't want to do is to create an implementation of TCP yourself, as that's a non-trivial task, so sending RAW packets is out. In general, even using TCP is already relatively low-level and should be avoided unless really necessary.
Using e.g. ZeroMQ you get a message-based interface that does all the transmission for you. It does so on top of TCP (or other transports) and adds more error correction for e.g. disconnects. There, you also have something like "packets", but those are independent of how many TCP or IP packets were required to send it underneath. If you don't want to implement a specific protocol, I'd suggest you use this framework instead of lowlevel TCP sockets.
Another simple alternative is to use HTTP, for which there is also existing code in Python. The downside is that it is always one side that initiates some communication and the other side only replies. If you want some kind of active notification, you either have to poll or use hacks like delaying an answer.
You are already sending data packets - those packets juts happen to contain text data at the moment. Try looking into pickle in the standard libraries and into pyro.

Arduino, python, pyserial and socket

I am trying to write a simple webserver on an Arduino to test a few things, but I couldn't find my Arduino with Ethernet on it.
"No worries" I thought, "I'll just write a socket server in python that acts as a proxy for the serial connection".
import socket
import serial
host = ''
port = 8001
buffSize= 1024
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((host, port))
serverSocket.listen(1)
ser = serial.Serial('COM3', 115200, timeout=None, dsrdtr =False,rtscts =False,xonxoff =False)
print "Listening..."
send = ""
while 1:
conn, remoteAddr = serverSocket.accept()
print "Connection...."
data = conn.recv(buffSize)
print "Recieved"
ser.write("%s\n"%data)
print "Sent"
print "Attempting to get reply"
while ser.inWaiting()>0:
conn.send( ser.read())
conn.close()
serverSocket.close()
However, whatever I try, it seems that the connection made by the browser resets randomly and I'd get multiple rows of data. And the script resets the Arduino each time it connects or disconnects from the serial port. I tried using RealTerm and I got a proper answer, but python and serialness is just a mess.
Can anyone help me?
Use the tcp_serial_redirect.py script in the PySerial documentation. Is all you need.

Cannot run the socket programs correctly in Centos using Python

I'm currently working on with Sockets using Python.
As a starter, I tried copying first the examples given in this (17.2.2. Example) tutorial
I put the client and the server scripts in two different machines (of course)
Now, I want to try if it works, but I'm kind of lost.
I'm thinking of running the server program continuously so that it will keep on receiving the data sent by the client program. However, when I tried to run the Server program, it is giving me this error
socket.error: (99, 'Cannot assign requested address')
and When I tried running the client program, it doesnt give me errors, however, it is printing random data, which is different from what I'm expecting because I sent the String "Hello World", So im expecting that it will receive and print "Hello World"
Shown below is the server program
# Echo server program
import socket
HOST = '192.168.104.112' # 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.sendall(data)
conn.close()
and the one below is the client program
# Echo client program
import socket
HOST = '192.168.104.111' # 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.sendall('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
Assuming that the IP of the machine that runs the server program is : 192.168.104.111
while the Client program is : 192.168.104.112
Im not really sure where to get the port number so I just used the port showed in the rpyc in the terminal. how do I get the correct port number anyway?
I know I made a lot of mistakes here. I just don't which part. Could you point me the mistakes that i've done and how to correct them? and how do I run these programs?
BTW, i'm using Centos.
On the server, HOST should be either 0.0.0.0 or the server's own IP address. The server needs to bind its listening port to its own interface(s). The client connects to the server.
Your client program doesn't check for errors. So if it can't connect to the server, things go awry.

Categories