I never use python, so I can't reliably help there.
However, mind that TCP is TCP - it doesn't send packets, it sends messages, and the boundary between messages is something you have to detect by yourself.
Explanation. Suppose that node A sends 450.000 bytes with one single Send (note: it might fail for the reasons below). The receiver socket will trigger the function bound by SetRecvCallback multiple times (a LOT of calls) with data size smaller than the original message (of course). It's the receiver's responsibility to understand when the message is over, and if there's another message afterwards. Note that two consecutive messages might be concatenated in the packetization...
A stupid strategy is to close the socket, which will trigger another callback (see SetCloseCallbacks), something that was done by HTTP 1.0, and - indeed - was super-inefficient.
A more intelligent way is to write in the message what's the message size, so that the receiver can rebuild it as a whole. Again, your responsibility to do it.
A final caveat. by reading the code (but I didn't test it), it seems that the upper limit is 128kB:
TypeId("ns3::TcpSocket")
.SetParent<Socket>()
.SetGroupName("Internet")
.AddAttribute(
"SndBufSize",
"TcpSocket maximum transmit buffer size (bytes)",
UintegerValue(131072), // 128k
MakeUintegerAccessor(&TcpSocket::GetSndBufSize, &TcpSocket::SetSndBufSize),
MakeUintegerChecker<uint32_t>())
So you'll have to send your message using multiple calls - and also to check when you use Send that the call was - indeed - successful (check the Send function carefully).
BTW, also sending 128 kB at a time is idiotically inefficient because... well, this is kinda obvious and I'll leave to you to find out why.