rpiarduinomusings

Raspberry Pi, Arduino, Sensors and the data they produce

Python code for TCP Communications

Introduction

This post presents the base Python code required for a client/server relationship between two programs communicating using TCP.

 

The server program

The Python code for the server program is presented here. Please note that the variable HOST will have to change to match the IP address of the machine on which this program is running. This is the only modification required to run these demo programs on your machine.

 
#**********************************************************************
# Program      : TCPServer.py
# Date         : 20160613 
#
# https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=49204
#
#**********************************************************************
import socket
import sys
from thread import *
 
#**********************************************************************
#*****                      VARIABLES                             *****
#**********************************************************************
HOST = 'notInitialized'   
PORT = 8888

#**********************************************************************
#*****                 FUNCTION DECLARATIONS                      *****
#**********************************************************************
def readConfigFileValues():

    #use the global variables
    global HOST
 

    parser = SafeConfigParser()
    parser.read('/home/pi/PythonDev/TCPServer.txt')
    HOST = parser.get('sendEmailConfig', 'emailAddress')
     


def clientthread(conn):
    #Sending message to connected client
    conn.send('Welcome to the server. Receving Data...\n')

    #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()


#**********************************************************************
#*****        M A I N L I N E    C O N T R O L L E R              *****
#**********************************************************************
print '**********'
print '* SERVER *'
print '**********'

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'
	
	
#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()


#**********************************************************************
#**********************************************************************
#*****               E N D   O F   S O U R C E                    *****
#**********************************************************************
#**********************************************************************	

 

 

The client program

The Python code for the client program is presented here.

 
#**********************************************************************
# Program      : TCPClient.py
# Date         : 20160613 
#
# https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=49204
#
#**********************************************************************
import socket   
import sys 
import struct
import time
 
#**********************************************************************
#*****                      VARIABLES                             *****
#**********************************************************************


#**********************************************************************
#*****                 FUNCTION DECLARATIONS                      *****
#**********************************************************************

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)

 


#**********************************************************************
#*****        M A I N L I N E    C O N T R O L L E R              *****
#**********************************************************************

print '**********'
print '* CLIENT *'
print '**********'

# When the Python interpreter reads a source file, it executes all of 
# the code found in it. Before executing the code, it will define a few 
# special variables. For example, if the python interpreter is running 
# that module (the source file) as the main program, it sets the special
# __name__ variable to have a value "__main__". If this file is being 
# imported from another module, __name__ will be set to the module's 
# name.

#--------------------------------------------------
# main function
#--------------------------------------------------
if __name__ == "__main__":

    #if(len(sys.argv) < 2) :
    #    print 'Usage : python client.py hostname'
    #    sys.exit()
    #host = sys.argv[1]
    
    host = '192.168.129.211' 
    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 )
    remote_ip = socket.gethostbyaddr( 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()

#get reply and print
print recv_timeout(s)

s.close()

#**********************************************************************
#**********************************************************************
#*****               E N D   O F   S O U R C E                    *****
#**********************************************************************
#**********************************************************************	

 

Running the server

Run the server program in one instance of IDE (Geany in this case). It will sit there, listening for data to be sent by client program.
PythonTCPServer

 

Running the client

Run the client program in another IDE, (also Geany) It will send the test message and print what was sent until you cancel the run.
PythonTCPClient

 

Back to the server

The server is now showing the messages that have been sent by the client.
PythonTCPClientServerTest

 

I’m on a Horse

The first application has nothing to do with a horse. What actually comes to mind relates to a multiple Pi environment. Let’s say you have at least one Pi that is running the important stuff like an email application or a NAS using Samba or the Minecraft thing for the kids. If utility power was cut and this server wasn’t on a UPS it will crease to operate. Not good, because we already know that Linux isn’t real happy about that sort of thing and the health of the SD card then gets compromised. It would be best to have that Pi on a UPS so that you get an opportunity to shut it down gracefully. But, what if you’re not home? Battery power doesn’t last for much more than an hour. To save itself, the server would need to know that utility power has been cut. This is where the other Pi comes into play.

First, there is going to be a relationship between the Server Pi on a UPS and another Pi that will not be on a UPS. This last Pi is Client Pi. Both will communicate with each other using TCP over WIFI. It is helpful to think of Client Pi as a sensor and its SD card is a disposable commodity. Configuration of Client Pi is relatively simple (we’ll talk about that in another post) so if the SD card is corrupted while serving this role to save the important server, that’s ok. The Client Pi has saved the day.

Operation wise, on a periodic basis, the Server Pi can send a message to Client Pi which acts as in inquiry regarding its state. If the Client Pi is not running because electrical power has been cut, it will not be able to send an acknowledgement back to Server Pi reporting that all is well. In this event Server Pi could start a timer that would span say, 30 minutes. If within that time inquiries to Client Pi continue to indicate all is not well, Server Pi can then issue a os.system(“sudo shutdown -h now”) command. However, if utility power returns within that time span, Server Pi resets the timer and continues on with its life.

You might think of other applications for a TCP Client/Server Pi Network. Let us know what they are.

 

Summary

This post presented two Python programs that can be used as the basis for TCP communications over a network between two Raspberry Pi.

2 responses to “Python code for TCP Communications

  1. Bruce Lunde June 27, 2016 at 12:43 pm

    This is a good post. Do you use this for multiple Raspberry Pi’s or just one to one communications?

    Like

  2. Raul Mendez June 30, 2016 at 6:09 pm

    In theory, you could have multiple RPis talking and listening.

    Like

Leave a comment