Python socket.accept() blocking code before call? - python

I am trying to learn Python sockets and have hit a snare with the socket.accept() method. As I understand the method, once I call accept, the thread will sit and wait for an incoming connection (blocking all following code). However, in the code below, which I got from https://docs.python.org/2/library/socket.html and am using localhost. I added a print('hello') to the first line of the server. Yet the print doesn't appear until after I disconnect the client. Why is this? Why does accept seem to run before my print yet after I bind the socket?
# Echo server program
import socket
print('hello') # This doesn't print until I disconnect the client
HOST = 'localhost'
PORT = 50007
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()
# Echo client program
import socket
HOST = 'localhost' # 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)

You are likely using an output device on a system that Python's IO doesn't recognize as interactive. As a workaround, you can add sys.stdout.flush() after the print.
The standard output is a buffered stream, meaning that when you print something, the output sticks around in an internal buffer until you print enough data to fill the whole buffer (unlikely in a small program, the buffet is several kilobytes in size), or until the program exits, when all such buffers are automatically flushed. Normally when the output is a terminal service, the IO layer automatically switches to line buffering, where the buffer is also flushed whenever a newline character is printed (and which the print statement inserts automatically).
For some reason, that doesn't work on your system, and you have to flush explicitly. Another option is to run python -u, which should force unbuffered standard streams.

Related

Send a string between python programs

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.

Python socket loop does not break

I created socket for two PC, one is Raspberry Pi and the other one is my laptop. I just connected two then I send string to test the connection. If I send a character "q" from the RPi, my PC should break out of the loop and close the connection but it does not. The part print("Listening") is still running. Why? See code below.
import socket
import time
# IP address of this PC.
TCP_IP = '192.168.137.1'
# Port.
TCP_PORT = 5005
# Size of buffer.
BUFFER_SIZE = 1024
# Create a socket, connect and listen to it.
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:
print("Listening")
data = conn.recv(BUFFER_SIZE)
data = data.decode()
if data=='q':
break
if data:
print ("Received data:", data)
# Echo back.
conn.send(data.encode())
time.sleep(1)
print("It breaks.")
conn.close()
s.close()
TCP is a stream oriented protocol. So data transmitted is a stream not a sequence of messages. So when you expect data to be q it actually is some_data_sent_before_q_and_finally_q.
The simplest way to repair the code is to use if data.endswith('q') instead of if data=='q'. May work and may not depending on how you actually use the connection. For example, this approach may fail with some_data_sent_before_q pretty long pause more_data_and_q and with some_data_sent_before_q_and_finally_q_plus_something_else_why_not.
Little bit more advanced way to solve the problem is to divide the stream into messages with separators - message_1<separator>message_2<separator>q<separator>. This method will allow you to treat every message separately.

Server send data in python

I'm writing a simple client server app in python, where the client is listening every type of data entering in the specific port, and I want to when receiving a data flow, send back to the connected client (which have a dinamic ip) a string, in this case "001". But when I try to send the message, it fails!
#!/usr/bin/env python
import socket
TCP_IP = '192.168.1.115'
TCP_PORT = 55001
BUFFER_SIZE = 1024
MESSAGE = '01'
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
print ('Sending data to client...')
addr change every connection .. i cannot manage this!
s.connect((addr, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
(Connected stream) sockets are bidirectional, so there's no need to call connect to get a connection to the client—you already have one.
But you want to know why your code fails. And there are at least three problems with it.
First, after you call listen or connect on a socket, you can't call connect again; you will get an exception (EISCONN on POSIX, something equivalent on Windows). You will have to create a new socket.
Second, is client actually binded and listening for a connection on the same port as the server? If not, your connect can't work. If so, the bind will fail if the client and server are on the same machine.
Third, the addr you get back from accept is a (host, port) pair, not just a host. So, as written, you're trying to connect((('192.168.1.115', 12345), 55001)), which obviously isn't going to work.
You are trying to reply to the client using the server listening socket (s). This is only possible in UDP Servers. Since this is a TCP Server you have to use the conn which is crated using s.accept() to communication with remote client.

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.

Python initial read from socket returns some unexpected characters

I have a Python socket server that I'm trying to read text commands from a line at a time, code is below. The first time it is run, line contains what look like some garbage characters before the data. On subsequent calls to readline I get the exact data I typed in from the telnet client (Putty). Why am I getting these first few apparent garbage characters. E.g. if I type in _return_, line contains \u18\u01\u03d\r\n
'
HOST = ''
PORT = 27001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
while True:
conn, address = s.accept()
print 'Got new CLI connection'
f = conn.makefile()
f.flush()
while True:
try:
self.PrintBanner(conn)
self.PrintMenu(conn)
line = f.readline()
if line.lower()[:1] == 'd':
self.MenuFieldRequestStatus(conn)
f.readline()
except:
s.close()
You need to make sure and use "RAW" mode in this case. Otherwise, your telnet client is trying to discover and negotiate with a telnet server. See this link for more info:
3.6 Making raw TCP connections
You could probably switch "Telnet negotiation mode" to passive in the Telnet settings area too.

Categories