Send/receive Packets with TCP sockets

50,243

Solution 1

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.

Solution 2

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.

Share:
50,243
intensified
Author by

intensified

Updated on November 29, 2020

Comments

  • intensified
    intensified over 3 years

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