Search code examples
pythonsocketsloopspython-3.xindexoutofboundsexception

"IndexError: string index out of range" when loop is already ended! - Python 3


I'm recently studiying sockets trying to make them work inside a Python script (Python3), inside Windows.

Here the Python script of the server side.

import socket
import time

MSGLEN = 2048
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 8000))
server.listen(1)

while 1:
    #accept connections from outside
    (clientsocket, address) = server.accept()

    chunks = []
    bytes_recd = 0
    while bytes_recd < MSGLEN:

        chunk = clientsocket.recv(min(MSGLEN - bytes_recd, 2048)) #should enough this row without checks if transmission guaranteed inside buffer dimension
        #print(chunk)
        #i=0
        chunk = chunk.decode()
        bytes_recd = bytes_recd + len(chunk)
        chunks.append(chunk)
        for i in range(bytes_recd):
            if(chunk[i] == "_"):
                print("Breaking(_Bad?)")
                break

        buff_str = chunk[:i]
        print(buff_str)
        if chunk == '':
            print("Server notification: connection broken")
            break


    mex = ''.join(chunks)
    print("Server notification: \n\tIncoming data: " + mex)
    i=1;
    while i==1:
        chunk = clientsocket.recv(128)
        chunk = chunk.decode()
        if chunk == '':
            i = 0

    totalsent = 0
    msg = "Server notification: data received"
    while totalsent < MSGLEN:
        sent = clientsocket.send(bytes(msg[totalsent:], 'UTF-8'))
        if sent == 0 :
            print ("Server notification: end transmitting")
            break
        totalsent = totalsent + sent

I'm checking when a "_" is received and make some decision in it. This because I'm using blocking sockets. You should forget the very last part and the whole program functionality since I'm working on it and the incriminated part is here:

        for i in range(bytes_recd):
        if(chunk[i] == "_"):
            print("Breaking(_Bad?)")
            break

    buff_str = chunk[:i]

Something weird happens: the check works fine and break the loop by printing the rest at the right index value. BUT! This wild and apparently non-sense error appears:

>>>
    Breaking(_Bad?), i:  2
13
Traceback (most recent call last):
  File "C:\Users\TheXeno\Dropbox\Firmwares\Altri\server.py", line 24, in <module>
    if(chunk[i] == "_"):
IndexError: string index out of range

As you can see from the console output, it finds the number before the "_", in this case is the string "13" and is located at i = 2, which is compliant with the receiving string format form the socket: "charNumber_String". But seems to keep counting until exit from bounds.

EDIT: I will not rename the variables, but next time, better use improved names, and not "chunk" and "chunks".


Solution

  • Let's look at this block of code:

    while bytes_recd < MSGLEN:
        chunk = clientsocket.recv(min(MSGLEN - bytes_recd, 2048)) 
        chunk = chunk.decode()
        bytes_recd = bytes_recd + len(chunk)
        chunks.append(chunk)
        for i in range(bytes_recd):
            if(chunk[i] == "_"):
                print("Breaking(_Bad?)")
                break
    

    Lets say you read 100 bytes, and lets assume that the decoded chunk is the same length as the encoded chunk. bytes_recd will be 100, and your for loop goes from zero to 99, and all is well.

    Now you read another 100 bytes. chunk is again 100 bytes long, and chunks (with an "s") is 200 bytes. bytes_recd is now 200. Your for loop now goes from 0 to 199, and you're checking chunk[i]. chunk is only 100 bytes long, so when i gets past 99, you get the error.

    Maybe you meant to compare chunks[i] (with an "s")?