I sent a scaled array using socket connection from the server to the client and it worked well now I wanted to send back the data to the server to unscale it in the server. The data is sent to the client each row at a time so I try to put them back in order in an empty array called final.
This is the server.py
import socket
import numpy as np
import pandas as pd
import sklearn
from sklearn.preprocessing import MinMaxScaler
i = 0
scaler_ti = MinMaxScaler()
test_inputs = []
test_inputs = np.array(test_inputs)
temp_in = pd.read_excel(r'K:\BachelorThesis\Data\TestingData\Mix_Data_inputs.xlsx')
test_inputs = temp_in.to_numpy()
rows = test_inputs.shape[0]
scaler_ti.fit(test_inputs)
normalized_test_inputs = scaler_ti.transform(test_inputs)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = ''
port = 62402
s.bind((host,port))
s.listen(5)
while True:
connection, clientsocket, address = s.accept()
print(f"connection from {address} has been established!")
strg = test_inputs
temp = strg.tobytes()
clientsocket.send(temp)
clientsocket.close()
if i in range(65533):
i = i + 1
msg = connection.recv(64)
out = np.frombuffer(msg)
inverse = scaler_ti.inverse_transform(out.reshape(1,8))
print(inverse)
This is the client.py
import socket
import numpy as np
import pandas as pd
import sklearn
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import load_model
import tensorflow as tf
from random import randint
i = 0
final = []
final = np.array(final)
#modelLSTM = load_model('K:\BachelorThesis\code testing\TireForces.LSTM/LSTM_model.h5')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 62402
s.connect((host, port))
while True:
if i in range(65533):
i = i + 1
msg = s.recv(64)
out = np.frombuffer(msg)
#out = out.reshape(1,8)
#out = out.reshape(1,1,8)
#prediction = modelLSTM.predict(out)
#inverse = scaler_ti.inverse_transform(prediction.reshape(1,8))
#print(prediction)
#print(inverse)
final = np.vstack(out)
print(out)
if len(msg) <= 0:
break
strg = final
temp = strg.tobytes()
s.send(temp)
#serversocket.close()
#print (final)
This is the error I get from the server.py
Traceback (most recent call last):
File "K:\BachelorThesis\code testing\server.py", line 26, in <module>
connection, clientsocket, address = s.accept()
ValueError: not enough values to unpack (expected 3, got 2)
This is the error I get from the client.py
Traceback (most recent call last):
File "K:\BachelorThesis\code testing\client.py", line 31, in <module>
final = np.vstack(out)
File "<__array_function__ internals>", line 5, in vstack
File "C:\Users\karim\AppData\Local\Programs\Python\Python39\lib\site-
packages\numpy\core\shape_base.py", line 283, in vstack
return _nx.concatenate(arrs, 0)
File "<__array_function__ internals>", line 5, in concatenate
ValueError: need at least one array to concatenate
Your main problem is that accept() always sends only two values but you expect three.
It should be
connection, address = s.accept()
and you should use connection instead of clientsocket
But it will give other problem because you close clientsocket after sending data but you need this connection also to receive data.
All this looks like you joined two codes. These codes could work separatelly but it will not work together - because both needs to close connection to inform that this is end of data but now you can't close it after sending because you need connection to receive other data.
You have to use different way to inform other side that it is end of data. You have to first send data size (as object with constant size so sending as string will not work because it may have different length for different numbers) and later send data. And then other side has to first get data size (as object with constant size) and later use thsi value to detect if it get all data.
You can use struct to convert integer size to 4 bytes (so it will have constant size for different values) and other side will have to read 4 bytes and use again struct to convert back to integer
I can't run it but here is code.
Server:
import socket
import struct
import numpy as np
import pandas as pd
import sklearn
from sklearn.preprocessing import MinMaxScaler
# --- functions ---
def send_data(connection, data):
data_size = len(data)
data_size_as_4_bytes = struct.pack('>I', data_size)
connection.send(data_size_as_4_bytes)
connection.send(data)
def recv_data(connection, chunk_size=64):
data_size_as_4_bytes = connection.recv(4)
data_size = struct.unpack('>I', data_size_as_4_bytes)[0]
data = b""
size = 0
while size < data_size:
chunk = connection.recv(chunk_size)
size += len(chunk)
data += chunk
return data
# --- main ---
scaler_ti = MinMaxScaler()
temp_in = pd.read_excel(r'K:\BachelorThesis\Data\TestingData\Mix_Data_inputs.xlsx')
test_inputs = temp_in.to_numpy()
rows = test_inputs.shape[0]
scaler_ti.fit(test_inputs)
normalized_test_inputs = scaler_ti.transform(test_inputs)
# -- send ---
HOST = '' # or '0.0.0.0'
PORT = 62402
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket() # default values are `socket.AF_INET, socket.SOCK_STREAM`
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for '[Error 89] Address already in use'. Use before bind()
s.bind((HOST, PORT))
s.listen(5)
try:
while True:
print('Waiting for client')
# wait for new client
connection, address = s.accept()
print(f"connection from {address} has been established!")
# --- send data ---
print('send:', test_inputs)
data = test_inputs.tobytes()
send_data(connection, data)
# don't close it because it is needed to receive data
#clientsocket.close()
# --- receive data ---
data = recv_data(connection)
output_data = np.frombuffer(data)
print('recv:', output_data)
# --- now you can close ---
connection.close()
except KeyboardInterrupt:
print("Stopped by Ctrl+C")
finally:
s.close()
Client:
import socket
import struct
import numpy as np
import pandas as pd
import sklearn
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import load_model
import tensorflow as tf
from random import randint
# --- functions ---
def send_data(connection, data):
data_size = len(data)
data_size_as_4_bytes = struct.pack('>I', data_size)
connection.send(data_size_as_4_bytes)
connection.send(data)
def recv_data(connection, chunk_size=64):
data_size_as_4_bytes = connection.recv(4)
data_size = struct.unpack('>I', data_size_as_4_bytes)[0]
data = b""
size = 0
while size < data_size:
chunk = connection.recv(chunk_size)
size += len(chunk)
data += chunk
return data
def some_calcuations(input_data)
# need something different
output_data = input_data
return output_data
# --- main ---
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 62402
s.connect((host, port))
# --- recv ---
data = recv_data(s)
input_data = np.frombuffer(msg)
print('recv:', input_data)
# --- calculations ---
output_data = some_calcuations(input_data)
# --- send ---
print('send:', output_data)
data = output_data.tobytes()
send_data(s, data)
# --- close ---
s.close()
BTW:
Last week there was similar question where I show working code - and it also use threading to run server for many clients at the same time.
Use socket to send image (screenshot) when GUI is runnig:
not responding in tkinter when click button completely
Use socket to send pickle:
Pickle data truncated
Use socket in threading in server to work with many clients:
How to handle multithreading with sockets in Python?
EDIT:
Version which send in loop.
After all rows it sends word end to inform that it is end of data.
Or it could send number of rows before data.
Server:
import socket
import numpy as np
import struct
# --- functions ---
def send_data(connection, data):
data_size = len(data)
data_size_as_4_bytes = struct.pack('>I', data_size)
connection.send(data_size_as_4_bytes)
connection.send(data)
def recv_data(connection, chunk_size=64):
data_size_as_4_bytes = connection.recv(4)
data_size = struct.unpack('>I', data_size_as_4_bytes)[0]
data = b""
size = 0
while size < data_size:
chunk = connection.recv(chunk_size)
size += len(chunk)
data += chunk
return data
# --- main ---
np.random.seed(0) # it will always gives the same random numbers
test_inputs = np.random.random_sample((3,5))
# -- send ---
HOST = '' # or '0.0.0.0'
PORT = 62402
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket() # default values are `socket.AF_INET, socket.SOCK_STREAM`
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for '[Error 89] Address already in use'. Use before bind()
s.bind((HOST, PORT))
s.listen(5)
try:
while True:
# --- wait for new client ---
print('Waiting for client')
connection, address = s.accept()
print(f"Connection from {address} has been established!")
# --- send ---
for row in test_inputs:
# --- send data ---
print('send:', row)
data = row.tobytes()
send_data(connection, data)
# --- receive data ---
data = recv_data(connection)
row = np.frombuffer(data)
print('recv:', row)
# information that it is end of data
send_data(connection, 'end'.encode())
# --- now you can close ---
connection.close()
except KeyboardInterrupt:
print("Stopped by Ctrl+C")
finally:
s.close()
Client:
# author: Bartlomiej "furas" Burek (https://blog.furas.pl)
# date: 2021.07.23
#
# title: receiving back data from the client
# url: https://stackoverflow.com/questions/68499599/receiving-back-data-from-the-client/68502806#68502806
import socket
import numpy as np
from random import randint
import struct
# --- functions ---
def send_data(connection, data):
data_size = len(data)
data_size_as_4_bytes = struct.pack('>I', data_size)
connection.send(data_size_as_4_bytes)
connection.send(data)
def recv_data(connection, chunk_size=64):
data_size_as_4_bytes = connection.recv(4)
data_size = struct.unpack('>I', data_size_as_4_bytes)[0]
data = b""
size = 0
while size < data_size:
chunk = connection.recv(chunk_size)
size += len(chunk)
data += chunk
return data
def some_calcuations(input_data):
# need something different
output_data = input_data
return output_data
# --- main ---
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 62402
s.connect((host, port))
while True:
# --- recv ---
data = recv_data(s)
if data == b'end':
break
input_data = np.frombuffer(data)
print('recv:', input_data)
# --- calculations ---
output_data = some_calcuations(input_data)
# --- send ---
print('send:', output_data)
data = output_data.tobytes()
send_data(s, data)
# --- close ---
s.close()
Related
I am creating a very simple rdt 2.2 socket program that transfers an image file dictated as "Cat.bmp" from client to server. Once the client reads the first line of data from the bmp file, it sends it to the server, and then the server will continue to repeat reading this same line in an infinite loop. I have no idea why this won't allow the client to send new data. Any suggestions on how to fix this would be very appreciated.
Client.py
import binascii
import struct
import sys
import hashlib
import base64
import time
from asyncio.tasks import sleep
def rdtSend(currentSequence , currentAck , data):
values = (currentACK, currentSequence, data)
UDPData = struct.Struct('I I 8s')
packedData = UDPData.pack(*values)
checksumVal = hashlib.md5(packedData).hexdigest().encode('utf-8')
sendPacket = makepacket(currentACK, currentSequence, data, checksumVal)
UDPSend(sendPacket)
def makepacket(currentACK, currentSequence, data, checksumVal):
values = (currentACK, currentSequence, data, checksumVal)
packetData = struct.Struct('I I 8s 32s')
packet = packetData.pack(*values)
return packet
def UDPSend(sendPacket):
senderSocket.sendto(sendPacket, (IP, Port))
def dataError(receivePacket):
checksum = makeChecksum(receivePacket[0], receivePacket[1], receivePacket[2])
# Compare calculated chechsum with checksum value in packet
if receivePacket[3] == checksum:
print('CheckSums is OK')
return False
else:
print('CheckSums Do Not Match')
return True
def makeChecksum(ACK, SEQ, DATA):
values = (ACK, SEQ, DATA)
packer = struct.Struct('I I 8s')
packedData = packer.pack(*values)
checksum = hashlib.md5(packedData).hexdigest().encode('utf-8')
return checksum
def isACK(receivePacket, ACKVal):
if (receivePacket[0] == ACKVal):
return True
else:
return False
IP = "127.0.0.1"
#Local Port for client and server
Port = 20001
#buffer to receive information from client
bufferSize = 1024
unpacker = struct.Struct('I I 8s 32s')
senderSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
senderSocket.connect((IP , Port))
print("UDP IP:", IP)
print("UDP port:", Port)
filename = 'Cat.bmp'
file = open(filename , 'rb')
# current data item being processed
data = file.read(bufferSize)
currentSequence = 0
currentACK = 0
while (data):
rdtSend(currentSequence, currentACK , data)
packet, addr = senderSocket.recvfrom(bufferSize)
print(packet)
print("Received from: ", addr)
receivePacket = unpacker.unpack(packet)
if(dataError(receivePacket) == False and isACK(receivePacket , currentACK) == True):
currentACK = currentACK + 1
currentSequence = (currentSequence + 1) % 2
data = file.read(bufferSize)
print("sending more data")
else:
print("Resending packet")
file.close()
senderSocket.close
Server.py
import socket
import binascii
import struct
import sys
import hashlib
import base64
import time
from asyncio.tasks import sleep
def rdtSend(currentSequence , currentAck , data):
values = (currentACK, currentSequence, data)
UDPData = struct.Struct('I I 8s')
packedData = UDPData.pack(*values)
checksumVal = hashlib.md5(packedData).hexdigest().encode('utf-8')
#This is where it gets the UDP packet
sendPacket = makepacket(currentACK, currentSequence, data, checksumVal)
UDPSend(sendPacket)
def makepacket(currentACK, currentSequence, data, checksumVal):
values = (currentACK, currentSequence, data, checksumVal)
packetData = struct.Struct('I I 8s 32s')
packet = packetData.pack(*values)
return packet
def UDPSend(sendPacket):
receiverSocket.sendto(sendPacket, (IP, Port))
def makeChecksum(ACK, SEQ, DATA):
values = (ACK, SEQ, DATA)
packer = struct.Struct('I I 8s')
packedData = packer.pack(*values)
checksum = hashlib.md5(packedData).hexdigest().encode('utf-8')
return checksum
#Function that checks the packet for corruption
def dataError(receivePacket):
# Calculate new checksum of the [ ACK, SEQ, DATA ]
checksum = makeChecksum(receivePacket[0], receivePacket[1], receivePacket[2])
# Compare calculated chechsum with checksum value in packet
if receivePacket[3] == checksum:
print('CheckSums is OK')
return False
else:
print('CheckSums Do Not Match')
return True
#IP Address for local communications
IP = "127.0.0.1"
#Local Port for client and server
Port = 20001
#buffer to receive information from client
bufferSize = 1024
# Integer, Integer, 8 letter char array, 32 letter char array
unpacker = struct.Struct('I I 8s 32s')
# Create the actual UDP socket for the server
receiverSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind the socket to the local IP address and port
receiverSocket.bind((IP, Port))
currentACK = 0
currentSequence = 0
dataFile = open('receive.bmp' , 'wb')
print("Listening")
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
#Where the previous functions are used to send the packets back to the client
while receivedPacket[2]:
print("Received from:", addr)
print("Data Received:" , receivedPacket[2])
#This compares checksums to see if there are errors
if not dataError(receivedPacket):
dataFile.write(receivedPacket[2])
# Built checksum [ACK, SEQ, DATA]
ACK = receivedPacket[0]
SEQ = receivedPacket[1]
DATA = b''
print('Packeting')
rdtSend(currentSequence , currentACK , DATA)
print('Sent')
currentACK = currentACK + 1
currentSequence = (currentSequence + 1) % 2
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
else:
print('Packet error')
checksumVal = makeChecksum(packet[0] + 1, (packet[1] + 1) % 2, b'')
packet = makepacket(packet[0] + 1, (packet[1] + 1) % 2, b'', checksumVal)
print('Packeting')
receiverSocket.sendto(packet, addr)
print('Sent')
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
dataFile.close()
receiverSocket.close```
first of all thank you for your time. I have need to transfer images from one PC (Windows) to an other (Linux) and the other way arround. I used sockets and byte streams. How ever it takes 4 seconds to send one image which is insane amount of time. Am I missing some point here? Is there any library that supports fast file transfer on windows as well as on linux?
Server or sender
import numpy
import socket
import threading
import os
from idlelib.IOBinding import encoding
import Communication
import multiprocessing
import time
import cv2
import WrapDatastructures
import sys
import ImageProcessorClient
Queue = multiprocessing.Queue()
def SendFileToClient(name, sock, image, image_number):
#ImageRequest
ImageRequest = sock.recv(1024)
#Decode the Bytestring into ascii characters
ImageRequestAsStr = ImageRequest.decode('ascii')
print("Incoming Request String:",ImageRequestAsStr)
if ImageRequestAsStr == "FILEFLAG":
#Cascade to convert grayscale image to byte array and send it to Image Processor Client
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#Send size of the image to processor client
memoryConsumption = sys.getsizeof(gray_image)
print("Memory Consumtion",memoryConsumption)
sendStr = "EXISTS" + str(memoryConsumption)
#Convert the string to byte because otherwise it will not be send
sock.send((sendStr.encode(encoding)))
userResponse = sock.recv(1024)
#the Responce will be received in byte and will be converted to a string to make it checkable
userResponceStr = userResponse.decode('ascii')
if userResponceStr[:2] == 'OK':
#Get byte array
print("Convert grayscale_image to bytedata")
data = WrapDatastructures.singleChannelImgToByte(gray_image)
#bytesToSend = data #send 1024 bytes
#sock.send(bytesToSend)
sendData = 0
for i in range(0,memoryConsumption,1024):
sock.send(data[i:i+1024])
else:
print("User response not known")
else:
sendStr = "ERR"
sock.send(sendStr.encode(encoding))
sock.close()
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
#init camera
print("server started.")
imageCounterPerContainer = 0
while(True):
#Take image and put it in Q
#Call the controller to turn motor
#look for client to get request
if Queue.empty() is True:
#create client
print("create Client")
while True:
c, addr = s.accept()
print("client connected ip:< " + str(addr) +">")
imageCounterPerContainer +=1
t = threading.Thread(target = SendFileToClient, args=("rtrThread",c,cv2.imread("image_33.jpg"),imageCounterPerContainer))
t.start()
s.close()
if __name__ == "__main__":
Main()
Processor
import socket
from idlelib.IOBinding import encoding
import WrapDatastructures
import cv2
import time
def Main():
host = "127.0.0.1"
port = 5000
start = time.time()
s = socket.socket()
s.connect((host,port))
getfileRequest = "FILEFLAG"
if getfileRequest != "q":
s.send(getfileRequest.encode())
data = s.recv(1024)
dataStr = data.decode('ascii')
if dataStr[:6] == "EXISTS":
filesize = int(dataStr[6:])
print("Data is available size", filesize)
sendStr = "OK"
s.send(sendStr.encode(encoding))
#create new file new_filename and
img = b""
while True:
data = s.recv(1024)
if len(data) == 0:
break
img = b"".join([img, data])
print("Download Complete")
transferedImg = WrapDatastructures.ByteToCV2(img, (2048,2448))
cv2.imshow("transfered",transferedImg)
end = time.time()
print("Duration",end -start)
cv2.waitKey(0)
s.close()
else:
print("File does not exists")#
s.close()
s.close()
if __name__ == "__main__":
Main()
I can not send my numpy array in socket. I use pickle but my client pickle crashes with this error: pickle data was truncated
My server :
I create a numpy array and I want to send in my client with pickle (it's work)
import socket, pickle
import numpy as np
from PIL import ImageGrab
import cv2
while(True):
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 4096)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print ('Connected by', addr)
arr = np.array([[0, 1], [2, 3]])
printscreen_pil=ImageGrab.grab(bbox=(10,10,500,500))
img = np.array(printscreen_pil) ## Transform to Array
data_string = pickle.dumps(img)
conn.send(data_string)
msg_recu = conn.recv(4096)
print(msg_recu.decode())
conn.close()
My client
He has my numpy array, but I can not load with pickle. I have this error.
import socket, pickle
import numpy as np
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
msg_a_envoyer = "hello".encode()
s.send(msg_a_envoyer)
while 1:
data = s.recv(4096)
if not data: break
data_arr = pickle.loads(data)
print (data_arr)
s.close()
the problem is that if the size of the pickled data is > 4096 you only get the first part of the pickled data (hence the pickle data was truncated message you're getting)
You have to append the data and pickle it only when the reception is complete, for example like this:
data = b""
while True:
packet = s.recv(4096)
if not packet: break
data += packet
data_arr = pickle.loads(data)
print (data_arr)
s.close()
increasing a bytes object is not very performant, would be better to store the parts in a list of objects, then join, though. Faster variant:
data = []
while True:
packet = s.recv(4096)
if not packet: break
data.append(packet)
data_arr = pickle.loads(b"".join(data))
print (data_arr)
s.close()
In simple words, the file you are trying to load is not complete. Either you have not downloaded it correctly or it's just that your pickle file is corrupt. You can create a new pickle to solve this issue
Recently I wrote some code (client and server) to send an image - the client simply uploads the image to the server, just using the socket module: Sending image over sockets (ONLY) in Python, image can not be open.
However, the image sending part is now what I am concerned with. This is the original image I'm using:
In my server code (which receives the images), I have these lines:
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
data = sock.recv(40960000)
if not data:
myfile.close()
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
But I don't think this is the best way of doing it. I think I should instead implement the server such that it receives the data in chunks:
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
from random import randint
imgcounter = 1
basename = "image%s.png"
HOST = '127.0.0.1'
PORT = 2905
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
txt = str(data)
if data:
if data.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print 'got size %s' % size
sock.sendall("GOT SIZE")
elif data.startswith('BYE'):
sock.shutdown()
else :
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
amount_received = 0
while amount_received < size:
data = sock.recv(4096)
amount_received += len(data)
print amount_received
if not data:
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()
But when I do this, the server prints:
got size 54674
4096
8192
12288
16384
20480
24576
28672
32768
36864
40960
45056
49152
50578
And then seems to hang, and the client hangs too. However, at the server's side I can see only a piece of the image the client wanted to send:
It seems like there are some bytes missing. What is the proper way of sending a huge amount of data (images, other type of file) using ONLY sockets?
I'm assuming that you have a particular reason for doing this with naked sockets, such as self-edification, which means that I won't answer by saying "You accidentally forgot to just use HTTP and Twisted", which perhaps you've heard before :-P. But really you should look at higher-level libraries at some point as they're a lot easier!
Define a protocol
If all you want is to send an image, then it can be simple:
Client -> server: 8 bytes: big endian, length of image.
Client -> server: length bytes: all image data.
(Client <- server: 1 byte, value 0: indicate transmission received - optional step you may not care if you're using TCP and just assume that it's reliable.)
Code it
server.py
import os
from socket import *
from struct import unpack
class ServerProtocol:
def __init__(self):
self.socket = None
self.output_dir = '.'
self.file_num = 1
def listen(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.bind((server_ip, server_port))
self.socket.listen(1)
def handle_images(self):
try:
while True:
(connection, addr) = self.socket.accept()
try:
bs = connection.recv(8)
(length,) = unpack('>Q', bs)
data = b''
while len(data) < length:
# doing it in batches is generally better than trying
# to do it all in one go, so I believe.
to_read = length - len(data)
data += connection.recv(
4096 if to_read > 4096 else to_read)
# send our 0 ack
assert len(b'\00') == 1
connection.sendall(b'\00')
finally:
connection.shutdown(SHUT_WR)
connection.close()
with open(os.path.join(
self.output_dir, '%06d.jpg' % self.file_num), 'w'
) as fp:
fp.write(data)
self.file_num += 1
finally:
self.close()
def close(self):
self.socket.close()
self.socket = None
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
sp = ServerProtocol()
sp.listen('127.0.0.1', 55555)
sp.handle_images()
client.py
from socket import *
from struct import pack
class ClientProtocol:
def __init__(self):
self.socket = None
def connect(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect((server_ip, server_port))
def close(self):
self.socket.shutdown(SHUT_WR)
self.socket.close()
self.socket = None
def send_image(self, image_data):
# use struct to make sure we have a consistent endianness on the length
length = pack('>Q', len(image_data))
# sendall to make sure it blocks if there's back-pressure on the socket
self.socket.sendall(length)
self.socket.sendall(image_data)
ack = self.socket.recv(1)
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
cp = ClientProtocol()
image_data = None
with open('IMG_0077.jpg', 'r') as fp:
image_data = fp.read()
assert(len(image_data))
cp.connect('127.0.0.1', 55555)
cp.send_image(image_data)
cp.close()
A simple way is to send data size as the first 4 bytes of your data and then read complete data in one shot. Use the below functions on both client and server-side to send and receive data.
def send_data(conn, data):
serialized_data = pickle.dumps(data)
conn.sendall(struct.pack('>I', len(serialized_data)))
conn.sendall(serialized_data)
def receive_data(conn):
data_size = struct.unpack('>I', conn.recv(4))[0]
received_payload = b""
reamining_payload_size = data_size
while reamining_payload_size != 0:
received_payload += conn.recv(reamining_payload_size)
reamining_payload_size = data_size - len(received_payload)
data = pickle.loads(received_payload)
return data
you could find sample program at https://github.com/vijendra1125/Python-Socket-Programming.git
The problem is you are not incrementing amount_received for the first chunk of the data received.
Fix below:
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
from random import randint
imgcounter = 1
basename = "image%s.png"
HOST = '127.0.0.1'
PORT = 2905
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
txt = str(data)
if data:
if data.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print 'got size %s' % size
sock.sendall("GOT SIZE")
elif data.startswith('BYE'):
sock.shutdown()
else :
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
amount_received = len(data) # The fix!
while amount_received < size:
data = sock.recv(4096)
amount_received += len(data)
print amount_received
if not data:
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()
The following is complete client , server and sendproc codes:
Client.py
from socket import *
import pickle
import sendproc
import struct
s = socket(AF_INET, SOCK_STREAM) # Create a socket object
host = "192.168.1.4" # Get local machine name
port = 1094 # Reserve a port for your service.
s.connect((host, port))
with open("file.txt",'rb') as f:
print ('file opened')
print('Sending file...')
for data in f:
print(data)
print("MSG sent")
sendproc.send_msg(s, data)
Server.py
from socket import *
import pickle
import sendproc
port = 1094 # Reserve port for service.
s = socket(AF_INET,SOCK_STREAM) # Create a socket object
host = "192.168.1.4" # Get local machine name
s.bind((host, port)) # Bind to the port
s.listen(5)
print('server is listening')
conn,addr = s.accept()
with open("file1.txt",'w') as fb:
print("File downloading\n",fb)
while True:
print("hi")
data = sendproc.recv_msg(conn)
print(data)
if not data:
print("No data")
break
fb.write(data)
fb.flush()
print("Download complete\n")
SendRecieveProcedure.py
import struct
def send_msg(s, msg):
msg2 = struct.pack('>I', len(msg)) + msg
s.send(msg2)
def recv_msg(s):
# Read message length and unpack it into an integer
raw_msglen = s.recv(4)
print(raw_msglen)
if not raw_msglen:
return None
n = struct.unpack('>I',raw_msglen)[0]
# Read the message data
data = ' '
while len(data) < n:
packet = s.recv(n - len(data)).decode("cp437")
if not packet:
return None
data += packet
#print("hwllo",data )
return data
output prints correctly to the console, but if I go open up the file it's only writing starting lines.so what is the problem in code