As context to my question, I am a computing student getting started with Python for the first time. Before this, I've worked mostly with Java and I am most comfortable with Java conventions and practices right now.
Background
An assignment for socket programming asks that we send strings between a server and client locally on the machine. We are provided sample (Python 2) code that instantiates a server and client. Outside of the context of the assignment, I wanted to create a version of this code that also runs in Python 3, but I was having problems getting the client to work the same in Python 3.
Changing server and client
Originally, the server required little changes and I was able to get it working. My code for the server is as follows:
#!/usr/bin/python3
import socket
HOST=''
PORT=5870
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
conn, addr = sock.accept()
print('Connected by ', addr)
conn.sendto("Welcome to the server!", (HOST, PORT))
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
conn.close()
I'm not able to convert the client side to code that runs and functions within Python 3. I've tried digging deeper into the issue, but other online resources are not helpful for me (or at least, at my experience level). My server code is as follows.
#!/usr/bin/python3
import socket
HOST='127.0.0.1'
PORT=5870
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
data = sock.recv(1024)
print('Server sent', data)
sock.sendto("Hello world".encode(), (HOST, PORT))
data = sock.recv(1024)
print("Server sent", data)
sock.sendto("This is the second message".encode(), (HOST, PORT))
data = sock.recv(1024)
print('Server sent ', data)
sock.close()
The actual problem
Originally, this code for both the server and client used sendall() instead of sendto(), but I changed it after getting a TypeError in the client and reading this question. I'm still not exactly sure why this works or why I have to do this (although I would appreciate an explanation).
Now, when I run the client code, I'll get the same TypeError on the server even when I'm using sendto(), but I'm not sure how to resolve this problem in Python 3. The stacktrace I receive for the server as follows (I get a broken pipe on the client):
$ python3 mail_server.py
Connected by ('127.0.0.1', 41866)
Traceback (most recent call last):
File "mail_server.py", line 14, in <module>
conn.sendto("Welcome to the server!", (HOST, PORT))
TypeError: a bytes-like object is required, not 'str'
What am I doing wrong and how am I able to get this working in Python 3? Background context as to why this is would be especially helpful as I think part of my problem is that I'm not seeing why this change is necessary to begin with. Thanks!
Don't use sendto() on a stream socket. Once a socket is connected (and with stream sockets you can't do any data transfer until after connecting), you can't specify the destination, it's always sent to the remote address/port to which it's connected.
So use send() or sendall():
socket.sendall("Hello world".encode());
Related
I am new to socket programming. I was able to communicate between 2 system with socket communication. But suddenly started facing this issue. Connection is getting established and accepted but when cursor reaches conn.receive(1024) it is stuck at this point. I am not getting neither data nor any error. Can anyone suggest what is going wrong? What are the possible system settings might affect the code? Not able to figure out whether issue is at server or client side.
import socket
HOST = ''
PORT = 2048
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
s.bind((HOST, PORT))
print('Socket bind complete')
s.listen(10)
print('Socket now listening')
while True:
conn, addr = s.accept()
# Retrieve message size
data = conn.recv(1024).decode()
I figured out the answer!!!!!!!. Since the client side was in java it was seen that flush() command was not used. Once flush() command added it started working.
Thanks for the hint #mama 🙂
I want to send some simple information, like an int or a string, between two Python programs. I thought of doing it by having the programs read and write from a single-line file. But that doesn't seem to work, since one file seems to block the file. Especially since I want to check for updates every 1/12 of a second or so.
If it did work, my idea use case would be for one program to send a message with
with open('input.py','w') as file:
file.write('hello')
and receive it with
with open('input.py','r') as file:
print(file.read())
I've been looking into how to do it with sockets, but every 'simple' tutorial seems to be targeted some much more complex use case. So how do I do what I need to do in a way that'll actually work?
The best route to go is to use the socket library. This creates a client-server connection, where you can send strings between programs from there.
server.py:
import socket
s = socket.socket()
print "Socket successfully created"
port = 12345 # Reserve a port on your computer...in our case it is 12345, but it can be anything
s.bind(('', port))
print "Socket binded to %s" %(port)
s.listen(5) # Put the socket into listening mode
print "Socket is listening"
while True:
c, addr = s.accept() # Establish connection with client
print 'Got connection from', addr
c.send('Thank you for connecting') # Send a message to the client
c.close()
client.py:
import socket
s = socket.socket()
port = 12345 # Define the port on which you want to connect
s.connect(('127.0.0.1', port)) # Connect to the server on local computer
print s.recv(1024) # Receive data from the server
s.close()
From the terminal/shell:
# start the server:
$ python server.py
Socket successfully created
Socket binded to 12345
Socket is listening
Got connection from ('127.0.0.1', 52617)
# start the client:
$ python client.py
Thank you for connecting
As you can see, the client was able to receive the string "Thank you for connecting" by the server, thanks to the send() and recv() methods from the socket library.
In trying to familiarize myself with the socket library, I have a simple server and client setup. Basically I've stumbled through and am able to set up connection and get the server and client to talk to each other. To make it more interactive, I have client.py able to send text through the command line. Everything appears to be working properly (with the exception of the server side tearing down connection properly if client input is blank), if I type a message from the client side, it spits it right back out to me. In this example, I have it set up for the server side to print the text as well. What I noticed was, that the server side doesn't alway 'register' what it being sent from the client. I am trying to figure out why this is the case. For being a test, it doesn't really affect anything, I just can't figure out what is taking place behind the scenes.
EDIT:
Actually, after playing around with it for a bit, it appears every other message is being printed out to the server console. I've still yet to figure out why this is the case
Server side:
#server.py
import socket
ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ss.bind(('127.0.0.1',5000))
ss.listen(5)
while True:
conn, addr = ss.accept()
with conn:
print ('Connected by', addr)
while True:
data = conn.recv(4096)
print (data)
if not data:
print ("nothing received from client")
ss.close()
break
Client side:
#client.py
import socket
server = 'localhost'
port = 5000
s = socket. socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 5000))
s.send(bytes(b'Client has connected'))
while True:
msg = input()
s.send(bytes(input(msg),'utf-8'))
if not msg:
print ("Server should tear down connection...")
# s.close()
break
In sockets you there are no methods __exit__ implemented, so you can't use the with conn:
you need to remove this part of code.
I am currently developing a system where I need to send notification to Raspberry to run a Python file. It is much like a observer pattern design where my server is publisher and Raspberry is the observer. Worth to note that, I actually need to interact with one Raspberry at the time (even I have dozens of them). Specifically, on a specific event, I need to warn a single Raspberry that it has to take an action.
I searched for it literally for all the night but I could not find anything coming handy. Nothing really give me a clue how to implement this.
The most close answer I could find is this technology firm's product called PubNub which can actually work. However, as I need is a one-to-one interaction, this might be unnecessary because it is designed to publish a data to multiple clients.
Long story short, I need to trigger Raspberry to take some action in accordance to the some data coming from the server, whenever it receives the data.
Server is running on Amazon and implemented with Python 2.7.
Please do not hesitate to ask me for further detail, if I am missing any.
Thanks for all the supports,
EDIT
Just a recent update with an improvement to my answer. As far as I understand, sockets are able to manage this process. Such as from client (Raspberry in my case) listening for the server and server sending some data. Taken from this site, I managed to make a sample run on my computer, from my local. I used Port 5000 as their 'meeting point'.
Below is the code:
client.py
#!/usr/bin/env python
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5000
BUFFER_SIZE = 1024
MESSAGE = b"Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
print("received data:", data)
server.py
#!/usr/bin/env python
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5000
BUFFER_SIZE = 20 # Normally 1024, but we want fast response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print('Connection address:', addr)
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
print("received data:", data)
conn.send(data) # echo
conn.close()
However, I still have some questions.
Firstly, I want to learn whether the same thing work when I deploy the project and how. If that will work - lets say I have an url for the server like 'www.thisisanexampleurl.com' - simply assignign a port for it, will work?
Secondly, assuming first question is done, what is the way of making it continous so that it does not stop after receiving and sending data once. Because currently, when it makes the data transfer, it stops working.
Thanks again for the all support and again please do not hesitate to ask me for the further details i am missing any.
You should be able to do something this simple:
Run something like this on your pi:
import socket
s = socket.socket()
host = ""
port = 12345
s.bind((host, port))
s.listen(5)
while True:
try:
clientsock, addr = s.accept()
except OSError:
continue
message = clientsock.recv(20)
#the code you want to run
print("doing %s" % message)
clientsock.close()
And this on your server every time you want the pi to take action:
import socket
s = socket.socket()
host = "0.0.0.0"
port = 12345
s.connect((host, port))
s.send("foo")
s.close()
Have a look at Pyro4. It lets you avoid having to write network code at all and just write code that calls remote Python objects as if they were running on the same machine. In your case, the server could call a normal Python method on your Raspberry Pi to do something. It has many features but you can start with something extremely simple.
raspberry pi code:
import Pyro4
#Pyro4.expose
class Raspberry:
def something(self, arg):
print("called with:", arg)
return "hi from pi"
Pyro4.Daemon.serveSimple({Raspberry: "raspberry"})
server code to make the pi do something:
import Pyro4
rasp = Pyro4.Proxy("PYRONAME:raspberry")
print(rasp.something(42))
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.