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.
Related
I have a "messenger" application that works like this:
Client Sends Message to Server -> Server forwards Message to rest of the clients -> Clients read the message.
The server always receives the messages, but the clients do not.
Code that forwards the message to all clients (Server/TcpListener):
public static void SendToAll(TcpClient sender, string message)
{
// Log the recieved message in the console
Console.WriteLine(message);
// Save the recieved message for new clients
messageLog += message + "\n";
byte[] msg = Encoding.ASCII.GetBytes(message);
foreach (TcpClient client in clients.Keys)
{
if (client == sender || clients[client] == "") continue;
if (!client.Connected)
{
clients.Remove(client);
continue;
}
NetworkStream stream = client.GetStream();
stream.Write(msg, 0, msg.Length);
}
}
Code that reads messages from the server (TcpClient):
byte[] buffer = new byte[1024];
while (true)
{
using (MemoryStream memoryStream = new MemoryStream())
{
Int32 bytes = 0;
do
{
bytes = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, bytes);
}
while (stream.DataAvailable);
Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));
}
Server (image attached)
Client1 (image attached)
Client2 (image attached)
Found the answer.
The problem was probably caused because TCP is slow; not entirely finished with reading all the stream and already tasked with reading new data.
So I Switched
byte[] buffer = new byte[1024];
while (true)
{
using (MemoryStream memoryStream = new MemoryStream())
{
Int32 bytes = 0;
do
{
bytes = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, bytes);
}
while (stream.DataAvailable);
Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));
}
to
// ... Main() {
while (true) StartRead();
// ... }
public static async void StartRead(NetworkStream stream)
{
byte[] buffer = new byte[1024];
Int32 bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length));
string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine(message);
}
I have a small problem with this. I have another program / software which converts image to bytes and sends them on. So what I need to do now is catch those bytes in Unity and convert them back to image and set that as a texture.
I've already established the connection to the other software via TCP/IP system, connection is working, other software is sending data, but I've got no idea how to convert those bytes to img.
Debug.Log("client message received as: " + clientMessage);
is just a test so I can see that data is coming through.
Here is my code
img.LoadRawTextureData(Loader);
img.Apply();
GameObject.Find("Plane").GetComponent<Renderer>().material.mainTexture = img;
//
private void ListenForIncommingRequests()
{
try
{
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 35800);
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] bytes = new Byte[1024];
while (true)
{
using (connectedTcpClient = tcpListener.AcceptTcpClient())
{
using (NetworkStream stream = connectedTcpClient.GetStream())
{
int length;
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
Loader = incommingData;
string clientMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("client message received as: " + clientMessage);
}
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("SocketException " + socketException.ToString());
}
}
Have you tried passing the bytes into LoadRawTextureData?
private byte[] ListenForIncommingRequests()
{
try
{
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 35800);
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] bytes = new Byte[1024];
while (true)
{
using (connectedTcpClient = tcpListener.AcceptTcpClient())
{
using (NetworkStream stream = connectedTcpClient.GetStream())
{
int length;
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
Loader = incommingData;
string clientMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("client message received as: " + clientMessage);
}
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("SocketException " + socketException.ToString());
}
return bytes;
}
And call it like this.
var result = ListenForIncommingRequests();
img.LoadRawTextureData(result);
img.Apply();
GameObject.Find("Plane").GetComponent<Renderer>().material.mainTexture = img;
I currently have an application that uses the .NET C# .SendFile() method.
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(endPoint);
client.SendFile(filePath);
And I have a very simple receive file solution that goes something like this. Takes the the bits read and append it to a file basically:
ReadCallback(IAsyncResult ar) {
StateObject tempState = (StateObject)ar.AsyncState;
Socket handler = tempState.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead <= 0)
{
return;
}
BinaryWriter writer = null;
try
{
writer = new BinaryWriter(File.Open(receivePath, FileMode.Append));
writer.Write(tempState.buffer, 0, bytesRead);
}
catch (Exception error)
{
Console.WriteLine(error.Message);
Thread.Sleep(30);
}
finally
{
if (writer != null)
{
writer.Close();
}
// this method starts a new AsyncCallback(ReadCallback)
// and this method is ReadCallback so it works as a recursive method
handler.BeginReceive(tempState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), tempState);
}
Now I want to add additonal info like: filename, file size, md5 hash etc to the transfer.
So I wonder how if I send this for example:
byte[] preBuffer = { 1, 2, 3, 4 };
byte[] postBuffer ={ 5, 6, 7, 8 };
.SendFile(filePath, preBuffer, postBuffer, TransmitFileOptions.None)
How can I receive this information and separate it from the binary file that I write? How should I change my receive
Unless you want to append data to the file received on the other end, don't use postBuffer. i.e. if you want to send meta information about the file, only use preBuffer. In this case I recommend serializing the data to an in memory buffer then sending that buffer as the preBuffer and deserializing it on the other end. For example:
byte[] preBuffer;
using (var memoryStream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(memoryStream))
{
writer.Write(filePath);
writer.Write(fileLength);
writer.Write(md5Hash);
}
preBuffer = memoryStream.ToArray();
}
mySocket.SendFile(filePath, preBuffer, null,
TransmitFileOptions.UseDefaultWorkerThread);
Then, when you want to read the meta information and file, read the pre-data first, and the remaining will be the file. For example:
private void ReadCallback(IAsyncResult ar)
{
StateObject tempState = (StateObject) ar.AsyncState;
Socket handler = tempState.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead <= 0)
{
return;
}
using (var memoryStream = new MemoryStream(tempState.buffer))
{
using (BinaryReader reader = new BinaryReader(memoryStream))
{
var filename = reader.ReadString();
var length = reader.ReadInt32();
var md5Hash = reader.ReadString();
var fileData = new byte[memoryStream.Length - memoryStream.Position];
reader.Read(fileData, 0, fileData.Length);
try
{
using (var writer = new BinaryWriter(
File.Open(receivePath, FileMode.Append)))
{
writer.Write(tempState.buffer, 0, bytesRead);
}
}
catch (Exception error)
{
Console.WriteLine(error.Message);
Thread.Sleep(30);
}
finally
{
// this method starts a new AsyncCallback(ReadCallback)
// and this method is ReadCallback so it works as a recursive method
handler.BeginReceive(tempState.buffer,
0,
StateObject.BufferSize,
0,
new AsyncCallback(ReadCallback),
tempState);
}
}
}
}
I'm trying to securely transfer files between 2 devices, so I'm using an SslStream attached to a TcpClient. Documents and text files come across just fine, but image files don't show up correctly. The following is the server code:
listener = new TcpListener(IPAddress.Any, 1337);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
var certificate = Connection.GetClientCertificate(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
try
{
sslStream.AuthenticateAsServer(certificate, true, SslProtocols.Default, true);
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
var messageData = ReadMessage(sslStream);
var mode = messageData[0];
var tokenBytes = messageData.Splice(1, 16);
var fileNameBytes = messageData.Splice(17, 128);
var fileBytes = messageData.Splice(146);
var fileName = Encoding.ASCII.GetString(fileNameBytes).TrimEnd('\0');
using (var tempFile = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write))
{
tempFile.Write(fileBytes, 0, fileBytes.Length);
tempFile.Flush();
}
if (mode == 0)
tempFiles.Add(fileName);
Process.Start(fileName);
}
catch (AuthenticationException e)
{
MessageBox.Show("The other side failed to authenticate.");
}
finally
{
sslStream.Close();
client.Close();
}
}
And ReadMessage is defined as follows:
private static byte[] ReadMessage(SslStream sslStream)
{
byte[] buffer = new byte[2048];
MemoryStream stream = new MemoryStream();
int bytes = -1;
while (bytes != 0)
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
stream.Write(buffer, 0, bytes);
}
return stream.ToArray();
}
And then the client code is this:
TcpClient client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse(ip), 1337));
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
var certificate = Connection.GetClientCertificate(ip);
try
{
sslStream.AuthenticateAsClient(ip, new X509CertificateCollection() { certificate }, SslProtocols.Default, false);
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
sslStream.Write(data);
}
catch (AuthenticationException e)
{
MessageBox.Show("The other side failed to authenticate.");
}
finally
{
sslStream.Close();
client.Close();
}
And the code that calls into it just does:
var fileBytes = File.ReadAllBytes(file);
var tokenBytes = Encoding.UTF8.GetBytes(token);
var fileNameBytes = Encoding.UTF8.GetBytes(Path.GetFileName(file));
var buffer = new byte[145 + fileBytes.Length];
buffer[0] = 1;
for (int i = 0; i < 16; i++)
{
buffer[i + 1] = tokenBytes[i];
}
for (int i = 0; i < fileNameBytes.Length; i++)
{
buffer[i + 17] = fileNameBytes[i];
}
for (int i = 0; i < fileBytes.Length; i++)
{
buffer[i + 145] = fileBytes[i];
}
SocketConnection.Send(ip, buffer);
Is there anything inherently wrong with what I'm doing, or do I need to do something different for images?
EDIT: I have changed it to reflect the current code, and also, after doing a dump of the raw bytes on both ends, it looks like for some reason the bytes are getting rearranged when they come over the wire. Is there any way to ensure that the bytes come across in the original order?
In ReadMessage you're writing bytes.Length bytes to the stream, regardless of the number of bytes that were actually read. Try:
private static byte[] ReadMessage(SslStream sslStream)
{
byte[] buffer = new byte[2048];
MemoryStream stream = new MemoryStream();
int bytes = -1;
while (bytes != 0)
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
// Use "bytes" instead of "buffer.Length" here
stream.Write(buffer, 0, bytes);
}
return stream.ToArray();
}
Based on your follow-up, you're also taking the file data from the wrong point in the buffer, and so you're losing the first byte of the file.
Your code should be:
var fileBytes = messageData.Splice(145); // File data starts at 145, not 146
Is this possibly a conflict between endianness? If the bytes from the server are ABCDEF and the client is seeing the image bytes as BADCFE then that's the issue.
I haven't worked with image files, but when I read a short or an int instead of a String from the bytes coming in over the wire, I do something like this:
int intFromStream = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(byteArrayWithLength4, 0));
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.