I have an image in my server which I want to send to my Java client through sockets. In c# I converted to byte array and then tried to send over the socket. But, a byte array in C# is unsigned so I tried to send signed byte array sbyte[] but it cannot be send by clientSocket.Send() method. On the java client side, I need to convert the byte array received to an Image object. Here is the exception trace that I get, at Image image = reader.read(0, param). Please help me with this.
Exception in thread "main" javax.imageio.IIOException: Bogus marker length
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImageHeader(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readNativeHeader(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.checkTablesOnly(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.gotoImage(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readHeader(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(Unknown Source)
at ServerByteStreamWithoutOIS.main(ServerByteStreamWithoutOIS.java:54)
Here is my C# server code:
class Program
{
static void Main(String[] args)
{
Socket sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 2. Fill IP
IPAddress IP = IPAddress.Parse("147.174.117.187");
IPEndPoint IPE = new IPEndPoint(IP, 20229);
// 3. binding
sListen.Bind(IPE);
// 4. Monitor
Console.WriteLine("Service is listening ...");
sListen.Listen(2);
// 5. loop to accept client connection requests
while (true)
{
Socket clientSocket;
try
{
clientSocket = sListen.Accept();
}
catch
{
throw;
}
// send the file
byte[] buffer = ReadImageFile("1.jpg");
clientSocket.Send(buffer, buffer.Length, SocketFlags.None);
clientSocket.Close();
Console.WriteLine("Send success!");
}
}
private static byte[] ReadImageFile(String img)
{
FileInfo fileInfo = new FileInfo(img);
byte[] buf = new byte[fileInfo.Length];
FileStream fs = new FileStream(img, FileMode.Open, FileAccess.Read);
fs.Read(buf, 0, buf.Length);
fs.Close();
//fileInfo.Delete ();
GC.ReRegisterForFinalize(fileInfo);
GC.ReRegisterForFinalize(fs);
return buf;
}
}
}
Here is my Java client:
public class ServerByteStreamWithoutOIS {
public static void main(String[] args) throws IOException, ClassNotFoundException{
int port = 20229;
Socket sock = null;
InetAddress addr = null;
addr = InetAddress.getByName("147.174.117.187");
sock = new Socket(addr, port);
System.out.println("created socket!");
int count = 0;
while(true){
String line = "";
String realLine = "";
BufferedReader bReader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
byte[] buffer = null;
while((line=bReader.readLine() )!=null){
realLine = realLine + line;
System.out.println(line.getBytes());
}
buffer = realLine.getBytes();
//buffer = (byte[])ois.readObject();
ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = (ImageReader) readers.next();
Object source = bis; // File or InputStream, it seems file is OK
ImageInputStream iis = ImageIO.createImageInputStream(source);
//Returns an ImageInputStream that will take its input from the given Object
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
Image image = reader.read(0, param);
//got an image file
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
//bufferedImage is the RenderedImage to be written
Graphics2D g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
File imageFile = new File("image.bmp");
ImageIO.write(bufferedImage, "bmp", imageFile);
System.out.println(imageFile.getPath());
//Thread.sleep(100);
System.out.println("Done saving");
}
}
}
I believe the error is because you are converting the bytes received in the Java server to a string representation. This can result in an error because a jpg is binary data, and when some binary data can not be converted to a character in a string, some conversion occurs which will result in an error when you use the getBytes() function.
If you instead read the bytes from the inputstream using the read(byte[],int,int]) function, I think you should be alright.
http://download.oracle.com/javase/1.5.0/docs/api/java/io/InputStream.html#read(byte[], int, int)
Edit, added a working code example
The "problem" of Java having signed bytes is a non issue. In binary they are the same bits, so when written to a file, the same bits are written since they are still the same order.
I wrote an example of a C# client and a Java server that I got working. I'm sure you can find it of use.
Server – Java
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ImageServer {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(8000);
Socket accept = server.accept();
InputStream inputStream = accept.getInputStream();
BufferedInputStream stream = new BufferedInputStream(inputStream);
int length = readInt(inputStream);
byte[] buf = new byte[length];
for (int read = 0; read < length; ) {
read += stream.read(buf, read, buf.length - read);
}
stream.close();
FileOutputStream fos = new FileOutputStream("image.png");
fos.write(buf, 0, buf.length);
fos.flush();
fos.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private static int readInt(InputStream inputStream) throws IOException {
byte[] buf = new byte[4];
for (int read = 0; read < 4; ) {
read += inputStream.read(buf, 0, 4);
}
return toInt(buf);
}
public static int toInt(byte[] b) {
return (b[0] << 24)
+ ((b[1] & 0xFF) << 16)
+ ((b[2] & 0xFF) << 8)
+ (b[3] & 0xFF);
}
}
Client – C#
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace Test.SendImageClient {
public class Program {
public static void Main(string[] args) {
if (args.Length == 0) {
Console.WriteLine("usage: client imagefile");
return;
}
FileStream stream = File.OpenRead(args[0]);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("localhost", 8000);
int length = IPAddress.HostToNetworkOrder((int)stream.Length);
socket.Send(BitConverter.GetBytes(length), SocketFlags.None);
byte[] buffer = new byte[1024];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) {
socket.Send(buffer, 0, read, SocketFlags.None);
}
socket.Close();
}
}
}
it seems like the bytes being received are not lining up w/the jpeg specification (can't be deserialized properly). are you sure the file on the server exists and that the c# byte[] is getting filled properly? maybe try to write the file on the server before sending it through the socket to ensure that you are actually reading a valid jpeg on the server.
Related
Now I know that this question has been asked a lot but I really just don't get how to do it. I tried this but the file don't get complete I just receive just a bit of the file and the rest is just NULL here is my code in client part I first send a message to the server that contain the file size like this :
// here I send the a upload request with the size of the file that I want to send
byte[] data = Encoding.Unicode.GetBytes("uploadreq~"+new FileInfo(ofg.FileName).Length);
// here is the socket client
target.Send(data);
Then on the server side :
if (cmd.Contains(update.update_request))
{
// here I set an int var to the file size
update.update_size = int.Parse(cmd.Split('~')[1]);
// here I setup the a new byte array with the given file size
update.update_received = new byte[update.update_size];
// then I send a upload confirm command
Connection.sendCommand(Commands.update_confirme);
update.isupdate = true;
}
Again on the client side when the confirmation has been received :
if (cmd.StartsWith("updateConfirm"))
{
// reading all the bytes of the file and sending them
byte[] datatosend = File.ReadAllBytes("the file path");
Connection.send_bytes(datatosend);
}
Finally on the client side :
private void receiveInfo()
{
byte[] buffer = new byte[999999];
int received = 0;
try
{
received = Connection.clientSocket.Receive(buffer);
}
catch (SocketException)
{
Connection.clientSocket.Close();
Connection.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Connection.makeConnection();
}
if (received == 0)
return;
byte[] data = new byte[received];
Array.Copy(buffer, data, received);
if (update.isupdate == true)
{
// this calls a method that process the data received
update.process_update(data);
}
}
public static void process_update(byte[] data)
{
int writeSize = 0;
Buffer.BlockCopy(data, 0, update_received, writeSize, data.Length);
writeSize += data.Length;
if (update_received.Length == update_size)
{
using (FileStream fs = File.Create("the path to where the file shloud go"))
{
byte[] info = update_received;
fs.Write(info, 0, info.Length);
}
Array.Clear(update_received, 0, update_received.Length);
isupdate = false;
}
}
As I was writing this question I changed the buffer size in the receive info method and that seems to change stuff a bit but still, the file won't arrive fully..
Try this for the client:
private void SendFile(String FileName,String IPAddress,int Port )
{
System.Net.Sockets.TcpClient TcpClient = new System.Net.Sockets.TcpClient(IPAddress, Port);
System.Net.Sockets.NetworkStream NetworkStream = TcpClient.GetStream();
System.IO.Stream FileStream = System.IO.File.OpenRead(FileName);
byte[] FileBuffer = new byte[FileStream.Length];
FileStream.Read(FileBuffer, 0, (int)FileStream.Length);
NetworkStream.Write(FileBuffer, 0, FileBuffer.GetLength(0));
NetworkStream.Close();
}
and this is the code for the server:
private void ReceiveFile(String FilePath, int Port)
{
System.Threading.Thread WorkerThread = new System.Threading.Thread(() =>
{
System.Net.Sockets.TcpListener TcpListener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 60000);
TcpListener.Start();
System.Net.Sockets.Socket HandlerSocket = TcpListener.AcceptSocket();
System.Net.Sockets.NetworkStream NetworkStream = new System.Net.Sockets.NetworkStream(HandlerSocket);
int BlockSize = 1024;
int DataRead = 0;
Byte[] DataByte = new Byte[BlockSize];
lock (this)
{
System.IO.Stream FileStream = System.IO.File.OpenWrite(FilePath);
while (true)
{
DataRead = NetworkStream.Read(DataByte, 0, BlockSize);
FileStream.Write(DataByte, 0, DataRead);
if (DataRead == 0)
{
break;
}
}
FileStream.Close();
}
});
WorkerThread.Start();
}
This will only transfer one file.
This question already has an answer here:
Why does my client socket not receive what my server socket sends?
(1 answer)
Closed 7 years ago.
I want to send big files with socket in c#. File can be transferred but when I want to open it, I see it is damaged. What's the problem?
I broke the file to 2KB in array in client code and send it. Then, in server code, I received it and put it in byte array and convert to file.
server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace MyServer
{
class Program
{
static void Main(string[] args)
{
bool full = false;
byte[] data = new byte[2049];
byte[] bsize = new byte[2048];
List<byte> bytes = new List<byte>();
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(ipep);
newsock.Listen(100);
Console.WriteLine("Wating For Client ...");
Socket client = newsock.Accept();
IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",clientep.Address,clientep.Port);
Console.Write("Enter the name of file: ");
string Address = Console.ReadLine();
client.Receive(bsize);
int size = BitConverter.ToInt32(bsize, 0);
byte[] bytes2 = new byte[size];
int k = 0;
while (true)
{
client.Receive(data);
for(int i = k,j=0; i < k + 2048 && j<2048; i++,j++)
{
if (i == size)
{
full = true;
break;
}
bytes2[i] = data[j];
//bytes.Insert(i,data[j]);
}
k += 2048;
if (full == true)
break;
/*if (bytes.Count >= size)
break;*/
}
File.WriteAllBytes(#"G:\"+Address,bytes2 /*bytes.ToArray()*/);
Console.WriteLine("Disconnected from Client {0}",clientep.Address);
client.Close();
newsock.Close();
Console.ReadKey();
}
}
}
client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
int reza = 0;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("192.168.0.2"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
server.Connect(ipep);
}
catch (SocketException e)
{
Console.WriteLine("Unable to connect to Server");
Console.WriteLine(e.ToString());
Console.ReadKey();
return;
}
Console.Write("Enter Address Of File:");
string Address = Console.ReadLine();
FileStream File = new FileStream(Address, FileMode.Open, FileAccess.Read);
byte[] bytes = System.IO.File.ReadAllBytes(#Address);
File.Close();
byte[] data = new byte[2048];
byte[] Size = BitConverter.GetBytes(bytes.Length);
server.Send(Size, Size.Length, SocketFlags.None);
for (int i = 0; i <= bytes.Length; i +=2048)
{
int k = i + 2048;
for(int j=i,d=0 ;j< k && j<bytes.Length; j++,d++)
{
data[d] = bytes[j];
reza++;
}
if (reza == 2048)
{
server.Send(data, data.Length, SocketFlags.None);
Console.Write("*");
reza = 0;
}
else
{
server.Send(data, reza, SocketFlags.None);
Console.WriteLine("*");
}
}
Console.WriteLine("Disconnecting from server ...");
server.Shutdown(SocketShutdown.Both);
server.Close();
Console.ReadKey();
}
}
}
The problem is that you ignore the return value from Receive(). There is no guarantee what-so-ever that your buffer will be completely filled.
The return value tells you how much data that the socket actually read from the network. Adjust your receiving code so it's taken into account. Same goes for the send. If the internal socket buffer gets full it will report less bytes sent than you have requested to send.
Other than that, I suggest you start to give your variables meaningful names. Your code is not very readable as is.
Here is a better receive routine:
var fileBuffer = new byte[size];
var receiveBuffer = new byte[2048];
var bytesLeftToReceive = size;
var fileOffset = 0;
while (bytesLeftToReceive > 0)
{
//receive
var bytesRead = client.Receive(receiveBuffer);
if (bytesRead == 0)
throw new InvalidOperationException("Remote endpoint disconnected");
//if the socket is used for other things after the file transfer
//we need to make sure that we do not copy that data
//to the file
int bytesToCopy = Math.Min(bytesRead, bytesLeftToReceive);
// copy data from our socket buffer to the file buffer.
Buffer.BlockCopy(receiveBuffer, 0, bytesLeftToReceive, fileBuffer, fileOffset);
//move forward in the file buffer
fileOffset += bytesToCopy;
//update our tracker.
bytesLeftToReceive -= bytesToCopy;
}
However, since you are transferring large files, isn't it better to write it directly to a file stream?
var stream = File.Create(#"C:\path\to\file.dat");
var receiveBuffer = new byte[2048];
var bytesLeftToReceive = size;
while (bytesLeftToReceive > 0)
{
//receive
var bytesRead = client.Receive(receiveBuffer);
if (bytesRead == 0)
throw new InvalidOperationException("Remote endpoint disconnected");
//if the socket is used for other things after the file transfer
//we need to make sure that we do not copy that data
//to the file
int bytesToCopy = Math.Min(bytesRead, bytesLeftToReceive);
// write to file
stream.Write(receiveBuffer, 0, bytesToCopy);
//update our tracker.
bytesLeftToReceive -= bytesToCopy;
}
On the send side I would do something like this:
// read directly from the file to reduce memory usage.
var fileName = #"....";
using (var file = File.OpenRead(fileName))
{
var sendBuffer = new byte[2048];
var fileSize = BitConverter.GetBytes((int)file.Length);
server.Send(fileSize, fileSize.Length, SocketFlags.None);
var bytesLeftToTransmit = fileSize;
while (bytesLeftToTransmit > 0)
{
var dataToSend = file.Read(sendBuffer, 0, sendBuffer.Length);
bytesLeftToTransmit -= dataToSend;
//loop until the socket have sent everything in the buffer.
var offset=0;
while (dataToSend > 0)
{
var bytesSent = socket.Send(sendBuffer, offset, dataToSend);
dataToSend -= bytesSent;
offset += bytesSent;
}
}
}
Finally you have a Socket.SendFile which have been optimized to send files. You can invoke it at any time for an open socket.
I have a Client and Server code for files sending. For some reason I need to receive at client and send from Server...
Everything work perfectly, in some cases all files sent and received perfectly. In another cases after sending a few files programm crashes. Don't understand where the problem...
Errors:
client colsole
server console
client
// client code
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Client003
{
const string destFilePath = #"..\..\..\";
const int BufferSize = 1024;
public static void StartReceiving()
{
// Data buffer for sending data.
byte[] buffer;
// FileStream to read data
FileStream fileStream;
int fileNameLen = 0;
string fileName = "";
long fileLen = 0;
int NoOfPackets = 0;
int receivedBytes = 0;
int i, j;
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket receiver = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
receiver.Connect(remoteEP);
buffer = new byte[4];
receiver.Receive(buffer, 4, 0);
int filesNumber = BitConverter.ToInt32(buffer, 0);
for (i = 0; i < filesNumber; i++)
{
buffer = new byte[4];
receiver.Receive(buffer, 4, 0);
fileNameLen = BitConverter.ToInt32(buffer, 0);
// --
buffer = new byte[fileNameLen];
receiver.Receive(buffer, fileNameLen, 0);
fileName = Encoding.UTF8.GetString(buffer);
// --
buffer = new byte[8];
receiver.Receive(buffer, 8, 0);
fileLen = BitConverter.ToInt64(buffer, 0);
// --
NoOfPackets = Convert.ToInt32(Math.Ceiling(
Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize) ));
fileStream = new FileStream(destFilePath + fileName, FileMode.OpenOrCreate, FileAccess.Write);
receivedBytes = 0;
// --
for (j = 0; j < NoOfPackets; j++)
{
if (fileLen > BufferSize)
{
buffer = new byte[BufferSize];
receivedBytes = receiver.Receive(buffer, BufferSize, 0);
fileStream.Write(buffer, 0, receivedBytes);
fileLen -= BufferSize;
}
else
{
buffer = new byte[fileLen];
receivedBytes = receiver.Receive(buffer, (int)fileLen, 0);
fileStream.Write(buffer, 0, receivedBytes);
}
}
fileStream.Close();
}
// Release the socket.
receiver.Shutdown(SocketShutdown.Both);
receiver.Close();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartReceiving();
return 0;
}
}
server
//server code
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
class Server003
{
public static void StartListening()
{
// Data buffer for incoming data.
byte[] buffer;
byte[] fileNameByte;
byte[] fileNameLenByte;
byte[] fileLenByte;
// FileStream to write data
FileStream fileStream;
Int64 fileLen = 0;
int NoOfPackets = 0;
int readBytes = 0;
int i;
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
Int32 filesNumber = binFilesNames.Count;
byte[] filesNumberByte = BitConverter.GetBytes(filesNumber);
handler.Send(filesNumberByte);
// --
foreach (string binName in binFilesNames)
{
fileNameByte = Encoding.UTF8.GetBytes(binName);
fileNameLenByte = BitConverter.GetBytes(fileNameByte.Length);
handler.Send(fileNameLenByte);
handler.Send(fileNameByte);
// --
fileStream = new FileStream(sourceFilePath + binName, FileMode.Open, FileAccess.Read);
fileLen = fileStream.Length;
fileLenByte = BitConverter.GetBytes(fileLen);
handler.Send(fileLenByte);
// --
NoOfPackets = Convert.ToInt32(Math.Ceiling(
Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize)));
for (i = 0; i < NoOfPackets; i++)
{
if (fileLen > BufferSize)
{
buffer = new byte[BufferSize];
// reeding data from file and writing it to the bytes "buffer"
readBytes = fileStream.Read(buffer, 0, BufferSize);
// send bytes from "buffer"
handler.Send(buffer, readBytes, SocketFlags.None);
fileLen -= BufferSize;
}
else
{
buffer = new byte[fileLen];
// reeding data from file and writing it to the bytes "buffer"
readBytes = fileStream.Read(buffer, 0, (int)fileLen);
// send bytes from "buffer"
handler.Send(buffer, readBytes, SocketFlags.None);
}
}
fileStream.Close();
}
// Release the socket.
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static List<string> GetFiles()
{
var dir = new DirectoryInfo(sourceFilePath); // folder with files
var files = new List<string>(); // List with file names
foreach (FileInfo file in dir.GetFiles("T*260000.bin"))
{
files.Add(Path.GetFileName(file.FullName));
}
return files;
}
public static int Main(String[] args)
{
binFilesNames = GetFiles();
StartListening();
return 0;
}
const string sourceFilePath = #"..\..\..\Binaries\";
static List<string> binFilesNames;
const int BufferSize = 1024;
}
UPD:
I took into account the moments that pointed LB2. Here is the receive part and it works as it need:
while ((receivedBytes = receiver.Receive(buffer)) > 0) // receive bytes to "buffer"
{
var tmpBuff = buffer.Take(receivedBytes); // takes first receivedBytes elements
bufferList.AddRange(tmpBuff);
}
But I don't understand how sending work. When I send whole data at once - all ok, but when i trying to send partially it crashes:
This works and whole data sent:
handler.Send(buffer);
This one crashes:
int sentBytes = 0;
int sumSentBytes = 0;
do
{
// send bytes from "buffer"
sentBytes = handler.Send(buffer, sumSentBytes, BufferSize, SocketFlags.None);
sumSentBytes += sentBytes;
}
while (sentBytes > 0);
So what is the best way to construct sending of large amounts of data (in my case about 20Mb, but it depends)?
There are multiple bugs in the code to be able to pinpoint specifically where this particular came from. Here are a few things you should be aware and where code needs clean up:
Socket class is IDisposable and thus should be wrapped in using. (I don't know if this is full program, or just a snippet with a driver main(), but if you call StartReceiving enough times, it'll leak memory).
FileStream (that you have a in a for loop) is IDisposable and thus should be wrapped in using. (Call to .Close() may actually clean up enough, but still better to use using.)
Use of Socket.Receive() is incorrect. You cannot assume that you receive as many bytes as you requested. Receive() returns either 0 if connection is lost, or number of bytes (upto requested count) that are currently available in the receive buffer. So as you go through:
buffer = new byte[fileNameLen];
receiver.Receive(buffer, fileNameLen, 0);
fileName = Encoding.UTF8.GetString(buffer);
// --
buffer = new byte[8];
receiver.Receive(buffer, 8, 0);
fileLen = BitConverter.ToInt64(buffer, 0);
... it is quite possible that you only read part of fileName bytes, get partial fileName, and then remainder bytes for filename are actually (incorrectly) interpreted as fileLen.
You correctly use receivedBytes to copy received bytes to file stream, but then you incorrectly decrement fileLen by BufferSize rather than receivedBytes, thus corrupting your file by possibly writing only part of the stream, in this part of the code:
receivedBytes = receiver.Receive(buffer, BufferSize, 0);
fileStream.Write(buffer, 0, receivedBytes);
fileLen -= BufferSize;
You keep reallocating new byte[] in a loop for each call to .Receive which is unnecessary. You can keep reusing the same buffer.
For the server code, exception screenshot that you posted has ? for the message (likly encoding issues). Please trap and post the actual message.
These are just a few things that I spotted by casual review. Whether some of these are the culprits, or there is some other issue is hard to ascertain with these issues present.
I guess you get an exception:
ArgumentOutOfRangeException: size is greater than the length of buffer minus the value of the offset parameter.
You'll have to subtract the bytes already sent from the size parameter:
int bytesToSend = BufferSize - sumSentBytes;
sentBytes = handler.Send(buffer, sumSentBytes, bytesToSend, SocketFlags.None);
Java (client side)
relevant code
// Create the encoder and decoder for targetEncoding
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharsetEncoder encoder = charset.newEncoder();
byte[] underlyingBuffer = new byte[100000];
ByteBuffer buffer = ByteBuffer.wrap(underlyingBuffer);
System.out.println("first buffer remaining" + buffer.remaining() + " "
+ buffer.limit());
buffer.order(ByteOrder.LITTLE_ENDIAN);
try {
Socket client = new Socket("localhost", 8080);
OutputStream oStream = client.getOutputStream();
InputStream iStream = client.getInputStream();
//String secondFilePath = "C:\\Users\\pedge\\Desktop\\readData.csv";//this is csv file
//long secondFileLength = ReadFileToCharArray(buffer,secondFilePath , encoder);
String inputImage = "C:\\Users\\pedge\\Desktop\\Desert.jpeg";// image to transfer
ReadFileToCharArray(buffer,inputImage , encoder);
//imageWrite(oStream, inputImage);
buffer.flip();
int dataToSend = buffer.remaining();
int remaining = dataToSend;
while (remaining > 0) {
oStream.write(buffer.get());
--remaining;
}
public static long ReadFileToCharArray(ByteBuffer buffer, String filePath,
CharsetEncoder encoder) throws IOException {
fileCount++;
System.out.println("second buffer remaining" + buffer.remaining() + " "
+ buffer.limit());
StringBuilder fileData = new StringBuilder(100);
File file = new File(filePath);
System.out.println("Size of file ["+fileCount+"] sent is ["+file.length()+"]");
BufferedReader reader = new BufferedReader(new FileReader(filePath));
char[] buf = new char[10000000];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
System.out.println(numRead);
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1000000];
}
reader.close();
CharBuffer charBuffer = CharBuffer.wrap(fileData.toString()
.toCharArray());
System.out.println("char buffer " + charBuffer.remaining());
ByteBuffer nbBuffer = null;
try {
nbBuffer = encoder.encode(charBuffer);
} catch (CharacterCodingException e) {
throw new ArithmeticException();
}
buffer.putInt(nbBuffer.limit());
System.out.println("buffer information" + buffer.position() + " "
+ buffer.limit() + " nbBuffer information" + nbBuffer.position()
+ " " + nbBuffer.limit());
buffer.put(nbBuffer);
return file.length();
}
C# (Server Side)
static void Main(string[] args)
{
try
{
Run(args);
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}
}
static void Run(string[] args)
{
TcpListener listener = new TcpListener(8080);
listener.Start();
while (true)
{
using (TcpClient client = listener.AcceptTcpClient())
{
try
{
Read(client);
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}
}
}
}
static void Read(TcpClient client)
{
String csvFile4Parsing = "C:\\Users\\pedge\\Desktop\\newReadData.csv";// csv file created from byte stream
Console.WriteLine("Got connection: {0}", DateTime.Now);
NetworkStream ns = client.GetStream();
BinaryReader reader = new BinaryReader(ns);
int length = reader.ReadInt32();
Console.WriteLine("Length of csv is [" + length + "]");
byte[] fileArray = reader.ReadBytes(length);
File.WriteAllBytes(csvFile4Parsing, fileArray);//bytes from stream, written to csv`
Now i am able to transfer the image from java to C# and a file is then created by c#(works perfect)
But when i try to send the image(same as like CSV), it doesn't work at all and even the bytes received at the server end are different from that of client end. I have spent hours now on this with no success. :/
and help will be much appreciated. thanks.
CSV data is text and might require the CharsetEncoder you are using to process the stream before sending it to the C#, but image data is binary and you only want to send a bit-for-bit copy of the data. The problem is likely to be that the stream encoder mistakenly interprets some binary sequences in the image data as text characters that need to be encoded and mangles them.
Just use plain binary stream read and write on both sides (you are already doing it in C#) and confirm that the data is exactly the same. If it isn't, post a hex sample of how it is different.
Finally the solved this issue.
Java(Client)
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class ImageServer {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8000);
//code to send image
File file = new File("C:\\Users\\ashish\\Desktop\\image.jpg");
FileInputStream fileInputStream = new FileInputStream(file);
int count=0;
byte[] fileBytes = new byte[(int)file.length()];
int content;
OutputStream outputStream = socket.getOutputStream();
while((content = fileInputStream.read(fileBytes)) != -1){
outputStream.write(fileBytes, 0, (int)file.length());
}
System.out.println("file size is "+ fileBytes.length);
for(byte a : fileBytes){System.out.println(a);}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
C#(Server)
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace Test.SendImageClient
{
public class Program
{
static void Main(string[] args)
{
TcpListener tcpListener = null;
try
{
IPAddress ipadress = IPAddress.Parse("127.0.0.1");
tcpListener = new TcpListener(ipadress, 8000);
/* Start Listeneting at the specified port */
tcpListener.Start();
byte[] bytes = new byte[6790];
byte[] finalBytes;
while(true){
TcpClient client = tcpListener.AcceptTcpClient();
Console.WriteLine("Connected!");
NetworkStream stream = client.GetStream();
int i;
do
{
i = stream.Read(bytes, 0, bytes.Length);
finalBytes = new byte[i];
Console.WriteLine("Size dynamically is "+i);
for (int n = 0; n < i; n++ )
{
finalBytes[n] = bytes[n];
}
}while(stream.DataAvailable);
File.WriteAllBytes("C:\\Users\\ashish\\Desktop\\newImage.jpg", finalBytes);
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
tcpListener.Stop();
}
}
}
}
To put my toe in the water of Network programming, I wrote a little Console App to send a png file to a server (another console app). The file being written by the server is slightly bigger than the source png file. And it will not open.
The code for the client app is:
private static void SendFile()
{
using (TcpClient tcpClient = new TcpClient("localhost", 6576))
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
//FileStream fileStream = File.Open(#"E:\carry on baggage.PNG", FileMode.Open);
byte[] dataToSend = File.ReadAllBytes(#"E:\carry on baggage.PNG");
networkStream.Write(dataToSend, 0, dataToSend.Length);
networkStream.Flush();
}
}
}
The code for the Server app is :
private static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(Listen));
thread.Start();
Console.WriteLine("Listening...");
Console.ReadLine();
}
private static void Listen()
{
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
int port = 6576;
TcpListener tcpListener = new TcpListener(localAddress, port);
tcpListener.Start();
using (TcpClient tcpClient = tcpListener.AcceptTcpClient())
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
using (Stream stream = new FileStream(#"D:\carry on baggage.PNG", FileMode.Create, FileAccess.ReadWrite))
{
// Buffer for reading data
Byte[] bytes = new Byte[1024];
var data = new List<byte>();
int length;
while ((length = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
var copy = new byte[length];
Array.Copy(bytes, 0, copy, 0, length);
data.AddRange(copy);
}
BinaryFormatter binaryFormatter = new BinaryFormatter();
stream.Position = 0;
binaryFormatter.Serialize(stream, data.ToArray());
}
}
}
tcpListener.Stop();
The size of the written file is 24,103Kb, whereas the source file is only 24,079Kb.
Is it apparent to anyone why this operation is failing?
Cheers
You are writing your output using a BinaryFormatter. I'm pretty sure that this will add some bytes at the start of the output to indicate the type that you're outputting (in this case System.Byte[]).
Just write the bytes out directly to the file without using the formatter:
using (Stream stream = new FileStream(#"D:\carry on baggage.PNG", FileMode.Create, FileAccess.ReadWrite))
{
// Buffer for reading data
Byte[] bytes = new Byte[1024];
int length;
while ((length = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, length);
}
}