Search code examples
pythonsocketswhile-looptcpclient

How to break the while loop if data is not receiving and data length is unknow in python [TCP]


I am new in python and socket programming. I am trying to send data to the client, and the length of data is unknown. After receiving all the data on client side, the program is not terminating because of a while loop (See below code). I also use the command (if not message: break) but it is also not working. The second one is the packet loss issue. When I do not give time. Sleep () at the sender side then receiver miss some packet(does not receive all packets at receiver side where the sender sends all packets). How I can come out from while loop without sys.exit command?. and ....How I can handle the second issue without using time.sleep function. It is appreciable if anybody can help me. Thanks

[Receiver Node]

import socket
import os,sys


def frame_reception_function ():
    while True:
        PORT = 123
        s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        s.bind(('',PORT))
        s.listen()
        conn,address=s.accept()
        message=conn.recv(4096).decode()
        print (message)
        conn.close()
frame_reception_function()

[Sender node]

import os,sys
import socket
import time


MyNeighborSet_ip= ['192.168.1.2']


Data_transfer_listt = [['192.168.1.1', '192.168.1.2'], ['192.168.1.2', '192.168.1.3'], ['192.168.1.2', '192.168.1.4'], ['192.168.1.4', '192.168.1.5'], ['192.168.1.4', '192.168.1.6']]



def sending_Neighobr_ip_list():    
    #nn1=n1
    message='Neighbor_list_sending'
    #print (len(Data_transfer_listt))

    for i in range(len(Data_transfer_listt)):
        receiver_ip=Data_transfer_listt[i][0]
        receiver_node_list=Data_transfer_listt[i][1]
        T_message= message + ";" + receiver_ip + ";" + receiver_node_list
        T_message_bytes= bytes(T_message,'utf-8')
        PORT = 123
        print ("just after socket")
        for k in range (len(MyNeighborSet_ip)):
            s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
            s.connect((MyNeighborSet_ip[k],PORT))
            s.sendall (T_message_bytes) 
            s.close()
            time.sleep(0.01)


sending_Neighobr_ip_list()

Solution

  • It is very resource intensive to keep opening and closing a socket, I am going to take those out of the while loop. Also, I can't remember if recv is a blocking function or not. But this should help you break out of the while loop properly and solve your first problem.

    Receiver:

    def frame_reception_function ():
        data = []
        PORT = 123
        s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        s.bind(('0.0.0.0',PORT))
        s.listen(1)
        conn,address=s.accept()  # accept an incoming connection using accept() method which will block until a new client connects
        while True:
            datachunk=conn.recv(1024) # reads data chunk from the socket in batches of 4086 bytes using method recv() until it returns an empty string
            if not datachunk:
                break  # no more data coming in, so break out of the while loop
            data.append(datachunk)  # add chunk to your already collected data
    
        conn.close()
        print(data)
        return
    
    frame_reception_function()
    

    Sender:

    import os,sys
    import socket
    import time
    
    MyNeighborSet_ip= [<THE IP ADDRESS OF YOUR RECEIVER>]
    
    Data_transfer_listt = [['192.168.1.1', '192.168.1.2'], ['192.168.1.2', '192.168.1.3'], ['192.168.1.2', '192.168.1.4'], ['192.168.1.4', '192.168.1.5'], ['192.168.1.4', '192.168.1.6']]
    
    def sending_Neighobr_ip_list():
        #nn1=n1
        message='Neighbor_list_sending'
        #print (len(Data_transfer_listt))
        PORT = 123
    
        for k in range (len(MyNeighborSet_ip)): 
            s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((MyNeighborSet_ip[k],PORT))
            s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    
            for i in range(len(Data_transfer_listt)):
                receiver_ip=Data_transfer_listt[i][0]
                receiver_node_list=Data_transfer_listt[i][1]
                T_message= message + ";" + receiver_ip + ";" + receiver_node_list
                T_message_bytes= bytes(T_message)
    
                print("sending message")
                s.sendall (T_message_bytes)
    
            s.close()
    
    sending_Neighobr_ip_list()
    

    For THE IP ADDRESS OF YOUR RECEIVER, I used my local IP address (192.168.x.x).

    This is the output on the receiver side:

    ['Neighbor_list_sending;192.168.1.1;192.168.1.2', 'Neighbor_list_sending;192.168.1.2;192.168.1.3', 'Neighbor_list_sending;192.168.1.2;192.168.1.4', 'Neighbor_list_sending;192.168.1.4;192.168.1.5', 'Neighbor_list_sending;192.168.1.4;192.168.1.6']
    

    The problem is on the sender side, you are closing the socket every iteration. That makes the receiver close its connection too. So sender successfully sends the first message, then errors out on the second connection cause receiver has been closed and is not looking for a connection. Instead, switch the for loops order. make the connection first, then send your messages, then close the connection.