Python socket server, limiting data received - python

When trying to send a file with sockets from one device on my network to another it is throttling the data to 2760 bytes and not receiving the whole file on the server side
Here is the code of my server on my raspberry pi:
import socket
import os
host = "my_ip"
port = "my_port"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen()
def send(mess):
con.send(bytes(mess, "utf-8"))
def receive():
global message
message = con.recv(22000).decode('utf-8')
while True:
try:
con, address = s.accept()
print(f"Connection to {address} made successfully")
receive()
if message == "quit":
break
else:
send("received")
print(len(message))
with open("file.py", 'w', encoding='utf-8')as a:
a.write(message)
os.system("python3 file.py")
except:
pass
And here is the code of my client on another device
with open('file.py', 'r', encoding = 'utf-8')as f:
python_file = f.read()
print(len(python_file))
#returns 20940
import socket
host = "my_ip"
port = my_port
def send(mess):
s.send(bytes(mess, 'utf-8'))
def receive():
message = s.recv(1024).decode('utf-8')
print(message)
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
send_it = input("Send File?[y/n]: ")
if send_it == "y":
try:
s.connect((host, port))
send(python_file)
recieve()
except:
pass
if send_it == "quit":
try:
s.connect((host, port))
send(send_it)
recieve()
except:
pass
else:
pass
When i take off the try loop it doesn't give any errors or reason as to why im only receiving part (2760 bytes) of the file. Also it will randomly(rarely) send more than 2760 bytes or it will sometimes send all the bytes. Its pretty consistently only sending 2760 bytes though.

Maybe you want to use sendall() instead of send(). Basically sendall() guarantees that all data will be sent unless an exception is raised and it's a python feature that is offered by other high level languages as well.
In order to receive all bytes sent, it's a good idea to do that using a loop:
data = bytearray(1)
# loop until there is no more data to receive.
while data:
data = socket.recv(1024) # Receive 1024 bytes at a time.
There is a well explained answer on what the difference between send() and sendall() is in python here.

Related

Socket python doesn't send data if program is alive

I'm trying to run a client/server script, where the client sends a file to the server and waits for responses until the server sends a stop message.
The problem is: once the connection is established the client starts sending data but until I press CTRL-C the server cannot recreate the file. Only after CTRL-C print "file is fully created" and the file becomes visible, instead, before it's seems to be waiting for something. idk where the problem is. Also tried changing condition on send loop using len(), but doesn't work. Anyone know how to fix it ?
client.py :
import socket # Import socket module
# from threading import Thread
s = socket.socket() # Create a socket object
HOST = "101.xx.x.xxx" # public IP address
PORT = 4243 # Reserve a port for your service.
PDF_PATH = "exam.pdf"
s.connect((HOST, PORT))
def send():
f = open(PDF_PATH, "rb")
while data := f.read(4096):
s.send(data)
f.close()
return
def receive():
while 1:
exercise = s.recv(4096)
if exercise == "stop!":
s.close()
break
f = open(f"{exercise}.txt", "wb")
while data := f.read(4096):
f.write(data)
return
def main():
send()
receive()
if __name__ == "__main__":
main()
server.py :
import socket
from threading import Thread
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
HOST = socket.gethostname()
IP = socket.gethostbyname(HOST)
PORT = 4243
s.bind(('', PORT))
s.listen(5)
def receive_file(conn, i):
f = open(f"exam.pdf", "wb")
while received := conn.recv(4096):
f.write(received)
print("File is fully copied\n")
f.close()
def send_result(conn,i):
while 1:
nbr = str(input("which exercise? "))
if nbr == "stop!":
break
f = open(f"exercise{nbr}.txt", "rb")
conn.send(bytes(f"exercise{nbr}.txt", encoding="utf-8"))
while data := f.read(4096):
conn.send(data)
f.close()
def main():
try:
while 1:
i = 0
conn, addr = s.accept()
print("Got connection from", addr)
# c.send(b"Thank you for connecting")
t = Thread(target=receive_file, args=(conn, i))
t.start()
t.join()
t = Thread(target=send_result, args=(conn, i))
t.start()
t.join()
except KeyboardInterrupt:
print("interrupting \n")
conn.close()
s.close()
if _name_ == '_main_':
main()
conn.recv() in the server won't return '' (no more data) unless the client closes the connection or calls shutdown(SHUT_WR) to indicate sends are complete:
def send():
with open(PDF_PATH, "rb") as f:
while data := f.read(4096):
s.sendall(data)
s.shutdown(socket.SHUT_WR)
An alternative is to design a protocol that sends the length of data before the data so you know when you've received the complete transmission. This would be required if you need to send more than one thing without closing the socket or shutting down sends. You're going to need this to make the receive portion of the server work if you want to send more than one exercise file.
Refer to this answer for an example of sending multiple files over a socket.

Python socket accept() does not accept a connection

A quite basic problem, but I can't find my mistake. I bascially used this tutorial code to implement my own client-server program: Client sends some data, the server displays it (instead of echoing data like in the tutorial)
The echoing tutorial code works, but my adjusted code to print data on the server doesn't. I added some delimiter mechanism to detect the entire message. My code:
Server.py:
class ThreadedServer:
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
print("Server bound on Port "+str(port))
def listen(self):
self.sock.listen(5)
while True:
print("Waiting for incoming connections...")
client, address = self.sock.accept()
client.settimeout(60)
print("Starting Working thread.")
threading.Thread(target=self.listenToClientDelimiter, args=(client, address)).start()
def listenToClientDelimiter(self, client, address):
print("Connect to client "+address)
length = None
buffer = ""
while True:
data = client.recv(1024)
print("Received raw data: "+str(data))
if not data:
break # connection closed
buffer += data
while True:
if length is None:
if LENGTH_DELIMITER not in buffer:
break # delimiter not found, wait for next data package
length_str, _, buffer = buffer.partition(LENGTH_DELIMITER)
length = int(length_str)
if len(buffer) < length:
break # wait until full length got received before we proceed
message = buffer[:length]
buffer = buffer[length:]
length = None
# PROCESS MESSAGE HERE
print(message)
client.close()
if __name__ == "__main__":
ThreadedServer('', 65432).listen()
Client.py:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(("127.0.0.1", 65432))
connect_user_cmd = "18:CONNECT_USER;Peter"
print("Trying to send data: "+connect_user_cmd.decode())
print(s.send(connect_user_cmd))
I run the server, then the client. The output from the server:
Server bound on Port 65432
Waiting for incoming connections...
As you see, I expect some log messages and of course my sent message. The client outputs this:
Trying to send data: 18:CONNECT_USER;Peter
21
Process finished with exit code 0
This gets outputted from the client even when I don't start the server. The weird thing is that the echoing part did indeed work. Could someone hint me into the right direction? Thank you!

connect two socket client connected by different threads as client server pair via a central server

I want to send a file from one connected client to other(both connected to a central server and running in different threads) such that the client sending becomes a server and other becomes the client. My code from main object is:
lin=link()
self.c.send(str('true').encode())
print("sent conf")
lin.create_server(new.ip_address,path)
the create_server function is
def create_server(self,ip,path ):
connection_list = []
#ip='127.0.0.1'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((ip, 12345))
print("server created")
connection_list.append(sock)
sock.listen(1)
#offset = 0
file = open(path, "rb")
print("file opened")
while True:
conn, addr = sock.accept()
connection_list.append(conn)
read_sockets,write_sockets,error_sockets = select.select(connection_list,[],[])
chunk = file.read(4096)
print("chunk read")
if not chunk:
break # EOF
sock.send(chunk)
print("chunk sent")
print("Transfer complete")
#sock.shutdown()
sock.close()
and for creating client is:
def create_client(self,ip,file ):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#ip='127.0.0.1'
print(str(file))
client.connect((ip, 12346 ))
print("client created")
with open(str(file), 'wb') as f:
socket_list = [client]
print("file opened")
while True:
read_sockets,write_sockets,error_sockets = select.select(socket_list,[],[])
data=client.recv(4096)
print("recieved data")
if not data:
break
f.write(data)
print("Transfer complete")
f.close()
time.sleep(5)
#client.shutdown()
client.close()
and the main server part that I am using to contact the client socket is
for i in self.list_of_conns:#[conn,addr] appended every time a connection is made to main server
if i[1][0]==cli_ip:
k=i[0] #the conn from conn,addr=server.accept() part
m=1
break
and after some code:
k.send(str(addr[0]+' '+filename).encode())
print("sent to k")
The server is created and file to be sent is opened and the main server is also sending the ip to k(the last snippet) but the connection that is supposed to be client is not recieving it. Where am I going wrong?
P.S:I am currently using only one system and so only one local IP for all sockets.
You've messed up your sockets.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((ip, 12345))
sock.listen(1)
sock is a socket only used to listen for incoming connections. You cannot read or write to this socket.
This while loop is for files larger than 4096 bytes, but each time through, you are waiting for a DIFFERENT connection, so the first chunk is processed for the first connection, the next chunk for the second connection and so on.
while True:
conn, addr = sock.accept()
chunk = file.read(4096)
if not chunk:
break # EOF
sock.send(chunk)
Again, you can't send to a listening socket! Perhaps you wanted conn.send(chunk).
What you really wanted was a loop more like:
conn, addr = sock.accept()
while True:
chunk = file.read(4096)
if not chunk:
break
conn.send(chunk)
conn.close()
Unfortunately, the above won't work, because the socket buffer will quickly become full, and stop accepting data no matter how fast the program writes to it.
You need to check the return value from conn.send(chunk) to find out how many bytes were sent. If that is less than the length of the chunk, you need to remove that many bytes from the start of the chunk, and try to send the remainder. Repeat until the whole chunk is sent.
Or ... simply use conn.sendall(chunk), which blocks until all the data has been accepted into the socket buffer.

Message transmission on TCP/IP server with ctrl+c int handling, Python3

i'm just started to learn Python, and i can't implement a good solution.
I want to write a client/server which allows you to send messages (like: texted, entered, texted, entered) on server until you press Ctrl+C interruption, and this int should close the socket both on server and client.
My very basic and, i suppose, very common client/server example on Python, but as you know - this pair is for single shot, and program is closing.
client.py
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFERSIZE = 1024
sock = socket.socket()
sock.connect((TCP_IP, TCP_PORT))
msg = input('Enter your text: ')
sock.send(msg.encode())
data = sock.recv(BUFFERSIZE).decode()
sock.close()
print('Recieved data: ',data)
server.py
import socket
import sys
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024
sock = socket.socket()
sock.bind((TCP_IP, TCP_PORT))
sock.listen(1)
conn, addr = sock.accept()
print('Connection address:\nIP:',addr[0])
print('Port:',addr[1])
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
msg = data.decode()
print('Recieved data: ', msg)
conn.send(data)
conn.close()
Any suggestions?
Add a try...finally to the bottom part like so:
try:
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
msg = data.decode()
print('Recieved data: ', msg)
conn.send(data)
finally:
conn.close()
Ctrl+C raises KeyboardInterrupt exception. When it does, the finally will be called, and safely close the socket.
The same can be done to the client in order to close it client-side:
try:
msg = input('Enter your text: ')
sock.send(msg.encode())
data = sock.recv(BUFFERSIZE).decode()
finally:
sock.close()

Reuse the same socket to send and receive (Python)

I have written a simple script to send and receive messages using the Python socket module. I want to first send a message using sendMsg and then receive a response using listen. sendMsg works fine but when my server sends a response I receive the error:
"[WinError 10038] An operation was attempted on something that is not a socket"
I close the socket connection in sendMsg and then try to bind it in listen, but it's at this line that the error is produced. Please could someone show me what I am doing wrong!
import socket
port = 3400
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), port))
def sendMsg():
print("\nSending message:\n\n")
msg = ("Sample text").encode("utf-8")
s.send(msg)
s.close()
def listen():
s.bind(("", port))
s.listen(1)
serverSocket, info = s.accept()
print("Connection from", info, "\n")
while 1:
try:
buf = bytearray(4000)
view = memoryview(buf)
bytes = serverSocket.recv_into(view, 4000)
if bytes:
stx = view[0]
Size = view[1:3]
bSize = Size.tobytes()
nTuple = struct.unpack(">H", bSize)
nSize = nTuple[0]
message = view[0:3+nSize]
messageString = message.tobytes().decode("utf-8").strip()
messageString = messageString.replace("\x00", "")
else:
break
except socket.timeout:
print("Socket timeout.")
break
sendMsg()
listen()
Note: I have implemented listen in a separate client and used the line
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 3)
before s.bind() and s.connect(). This works OK. It would be nice to have it all in one client though.
As per the docs the socket.close() will close the socket and no further operations are allowed on it.
So in your code this line s.close() is closing the socket.
Because of that the s.bind(("", port)) will not work as the socket s is already closed!

Categories

Resources