I have a Java android code that sends data (image or text) to a C# application, to receive these data I'm using Async socket. But exists a problem that is relative to BeginReceive() function is not receiving the complete data when is sent an image.. Then how I can make a kind of "loop" to receive full data and after show the image on Picturebox (for example)?
Form
private Listener listener;
private Thread startListen;
private Bitmap _buffer;
public frmMain()
{
InitializeComponent();
}
private void serverReceivedImage(Client client, byte[] image)
{
try
{
byte[] newImage = new byte[image.Length - 6];
Array.Copy(image, 6, newImage, 0, newImage.Length);
using (var stream = new MemoryStream(newImage))
{
using (var msInner = new MemoryStream())
{
stream.Seek(2, SeekOrigin.Begin);
using (DeflateStream z = new DeflateStream(stream, CompressionMode.Decompress))
{
z.CopyTo(msInner);
}
msInner.Seek(0, SeekOrigin.Begin);
var bitmap = new Bitmap(msInner);
Invoke(new frmMain.ImageCompleteDelegate(ImageComplete), new object[] { bitmap });
}
}
}
catch (Exception)
{
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
}
private delegate void ImageCompleteDelegate(Bitmap bitmap);
private void ImageComplete(Bitmap bitmap)
{
if (_buffer != null)
_buffer.Dispose();
_buffer = new Bitmap(bitmap);
pictureBox1.Size = _buffer.Size;
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_buffer == null) return;
e.Graphics.DrawImage(_buffer, 0, 0);
}
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
startListen = new Thread(listen);
startListen.Start();
}
private void listen()
{
listener = new Listener();
listener.BeginListen(101);
listener.receivedImage += new Listener.ReceivedImageEventHandler(serverReceivedImage);
startToolStripMenuItem.Enabled = false;
}
Listener
class Listener
{
private Socket s;
public List<Client> clients;
public delegate void ReceivedImageEventHandler(Client client, byte[] image);
public event ReceivedImageEventHandler receivedImage;
private bool listening = false;
public Listener()
{
clients = new List<Client>();
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public bool Running
{
get { return listening; }
}
public void BeginListen(int port)
{
s.Bind(new IPEndPoint(IPAddress.Any, port));
s.Listen(100);
s.BeginAccept(new AsyncCallback(AcceptCallback), s);
listening = true;
}
public void StopListen()
{
if (listening == true)
{
s.Close();
listening = false;
}
}
void AcceptCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
Socket sock = handler.EndAccept(ar);
Client client = new Client(sock);
clients.Add(client);
sock.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), client);
client.Send("REQUEST_PRINT" + Environment.NewLine);
handler.BeginAccept(new AsyncCallback(AcceptCallback), handler);
}
void ReadCallback(IAsyncResult ar)
{
Client client = (Client)ar.AsyncState;
try
{
int rec = client.sock.EndReceive(ar);
if (rec != 0)
{
string data = Encoding.UTF8.GetString(client.buffer, 0, rec);
if (data.Contains("SCREEN"))
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
receivedImage(client, bytes);
}
else // not is a image, is a text
{
// prepare text to show in TextBox
}
}
else
{
Disconnected(client);
return;
}
client.sock.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), client);
}
catch
{
Disconnected(client);
client.sock.Close();
clients.Remove(client);
}
}
}
Client
class Client
{
public Socket sock;
public byte[] buffer = new byte[8192];
public Client(Socket sock)
{
this.sock = sock;
}
public void Send(string data)
{
byte[] buffer = Encoding.ASCII.GetBytes(data);
sock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback((ar) =>
{
sock.EndSend(ar);
}), buffer);
}
}
Android code
private byte[] compress(byte[] data) {
Deflater deflater = new Deflater();
deflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
return output;
}
public static DataOutputStream dos;
public static byte[] array;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
array = compress(bos.toByteArray());
//...
dos = new DataOutputStream(SocketBackgroundService.clientSocket.getOutputStream());
byte[] header = ("SCREEN").getBytes(StandardCharsets.UTF_8);
byte[] dataToSend = new byte[header.length + array.length];
System.arraycopy(header, 0, dataToSend, 0, header.length);
System.arraycopy(array, 0, dataToSend, header.length, array.length);
dos.writeInt(dataToSend.length);
dos.write(dataToSend, 0, dataToSend.length);
dos.flush();
EDITION
i'm always getting the error Invalid Parameter in this line
var bitmap = new Bitmap(msInner);
and using compression also happens the same here
z.CopyTo(msInner);
IvalidDataException
on ServerReceivedImage() method respectively.
using this
File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "image.png"), newImage);
i noted that is receiving only 15KB (size of file without use compression).
I was writing a comment but it does not give me enough space to express my frustration with your code.
My main points are
You try to recompress and perfectly compressed image. PNG is portable network graphics. It was designed for network transfers. If it is acceptable you should use something like jpeg.
You just decode received buffer using UTF8.GetString and search for a text, then re-encode that string and try to decompress and read an image from it, by starting from index 6 which is pretty meaningless considering you added a two byte size field to the start of stream and you really do not know position of "SCREEN".
You do not check if you have received ALL of the stream data.
All of the code looks like you have scoured the SO questions and answers and created a copy pasta.
Now my recommendations.
When transferring data from network, do not try to invent wheels. Try something like gRPC which has both android java and c# packages.
If you will use raw data, please, please know your bytes.
I assume you will extend your code by adding new command pairs. Since you have no magic markers of some kind of signal system, it will be very hard for you to distinguish data from header. For a simple implementation add some kind of magic data to your header and search for that data, then read header and then read data. You may need to read from socket again and again until you receive all of the data.
424A72 0600 53435245454E 008E0005 ..... 724A42
B J r 6 S C R E E N 36352 ..... rJB
this sample data shows that we have a valid stream by looking at "BJr". Then read a 2 byte unsigned integer to read command size which is 6 for SCREEN. Read command and then read four bytes unsigned length for command data. For our sample it is 36352. Just to be safe I've added an end of command marker "rJB".
For a bonus point try reducing memory allocations / copies, you can look at System.Span<T>
Related
As the title says, I have been given a simple flight simulator and I have been tasked to create a GUI which connects to the flight sim (Through Socket Programming). Then I can send Control Updates to the flight sim through a button by using TCPClient and writing to the stream (already done that).
However, the flight Sim I have been given sends telemetry information and my GUI is supposed to receive that information and display it on a datagridView. I have tried running a thread in the background to invoke the ReceiveMessage method and then the DisplayMessage method is supposed to activate but nothing works. The Flight Simulator sends a JSON string and from what I understood, my GUI needs to deserialize it and present it on to the Data Grid View.
Sorry if my explanation is not great. Here is the code:
The process of listening when the programs are connected should work in the following sequence:
public void ConnectProgram(string IPaddress, int port)
{
tcpClient = new TcpClient();
tcpClient.Connect(IPaddress, port);
}
private void start()
{
messageInThread = new Thread(new ThreadStart(ReceiveMessage))
{
IsBackground = true
};
//thank you LarsTech for pointing out to write .Start() but it still doesn't work
messageInThread.Start();
btnListen.Enabled = false;
}
private void ReceiveMessage()
{
//netStream = tcpClient.GetStream();
string JSONmsg = " ";
int i;
using (netStream = tcpClient.GetStream())
{
byte[] buffer = new byte[1024];
using (MemoryStream ms = new MemoryStream())
{
int numBytesRead;
while ((numBytesRead = netStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Read(buffer, 0, numBytesRead);
}
JSONmsg = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
DisplayMessage(JSONmsg);
}
}
}
private void DisplayMessage(string JSONmsg)
{
if (dataTelemetryInfo.InvokeRequired)
{
object[] args = new object[] { JSONmsg };
this.Invoke(new StringArg(DisplayMessage), args); //StringArg is a delegate with a string as a parameter
}
else
{
lblTest.Text += JSONmsg;
telemetryInfo = serializer.Deserialize<TelemetryUpdate>(JSONmsg);
dataTelemetryInfo.Rows.Add(telemetryInfo.Altitude.ToString(), telemetryInfo.ElevatorPitch.ToString(), telemetryInfo.Pitch.ToString(),
telemetryInfo.Speed.ToString(), telemetryInfo.Throttle.ToString(), telemetryInfo.VerticalSpeed.ToString(),
telemetryInfo.WarningCode.ToString());
}
}
Once I connect the programs, and I click on the Listen button of my GUI (which starts the "start()" method), nothing changes and my datagridview isn't updated. Thank you in advance.
Change ReceiveMessage to:
private void ReceiveMessage()
{
//netStream = tcpClient.GetStream();
string JSONmsg = " ";
int i;
using (netStream = tcpClient.GetStream())
{
byte[] buffer = new byte[1024];
using (MemoryStream ms = new MemoryStream())
{
int numBytesRead;
while ((numBytesRead = netStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, numBytesRead);
}
JSONmsg = Encoding.ASCII.GetString(ms.ToArray());
DisplayMessage(JSONmsg);
}
}
}
You must .Write to your MemoryStream.
my program should be able to send and receive files but for some reason whenever i click on the send (button1) and receive (button2) buttons, it keeps hanging. Not sure if its something wrong my my codes? Also, I feel like my codes are pretty long as compared to other examples i found online but I'm not sure how to rectify.
Client codes
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9000);
private void Form1_Load(object sender, EventArgs e)
{
try
{
socket.Connect(remoteEP);
textBox2.Text = "Connected to Server";
}
catch (Exception ex)
{
textBox2.Text = "Unable to connect to Server";
textBox2.Text = ex.Message;
}
}
public const string SEND = "[SEND]";
public const string RECEIVE = "[RECEIVE]";
public const string QUIT = "[QUIT]";
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
NetworkStream stream = new NetworkStream(socket);
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
try
{
writer.WriteLine(RECEIVE);
writer.Flush();
writer.WriteLine(textBox1.Text);
writer.Flush();
Bitmap bmp = new Bitmap(#"C:\Users\Y400\Desktop\Lectures\Year 3\WAD\Week 11" + textBox1.Text);
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] bmpBytes = ms.GetBuffer();
bmp.Dispose();
ms.Close();
int sent;
sent = sendData(socket, bmpBytes);
textBox1.Text = "Transferring file complete\r\n";
textBox1.Text += bmpBytes.Length + " bytes sent to Server.";
}
catch (Exception ex)
{
textBox2.Text = ex.Message;
}
}
public static int sendData (Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int left = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(size);
sent = s.Send(datasize);
while(total<size)
{
sent = s.Send(data, total, left, SocketFlags.None);
total += sent;
left -= sent;
}
return total;
}
private void button2_Click(object sender, EventArgs e)
{
textBox2.Clear();
textBox1.Clear();
byte[] data = new byte[1024];
string fileN = textBox2.Text.Trim();
NetworkStream ns = new NetworkStream(socket);
StreamReader reader = new StreamReader(ns);
StreamWriter writer = new StreamWriter(ns);
writer.WriteLine(SEND);
writer.Flush();
writer.WriteLine(fileN);
writer.Flush();
try
{
while (true)
{
data = receiveData(socket);
MemoryStream ms = new MemoryStream(data);
break;
}
textBox2.Text = ("Receiving file from server ...\r\n" + data.Length + " bytes copied");
}
catch (Exception ex)
{
textBox2.Text = ex.Message;
}
}
public static byte[] receiveData (Socket s)
{
int total = 0;
int recv;
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, 0);
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
{
recv = s.Receive(data, total, dataleft, 0);
if (recv == 0)
{
break;
}
total += recv;
dataleft -= recv;
}
return data;
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
textBox2.Text = "Connection closed";
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
Server codes
class Program
{
public const string SEND = "[SEND]";
public const string RECV = "[RECV]";
public const string QUIT = "[QUIT]";
static void Main(string[] args)
{
runServer();
}
static void runServer()
{
try
{
byte[] data = new byte[1024];
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 9000);
server.Bind(localEP);
server.Listen(10);
Console.WriteLine("Waiting for Client ...");
Socket client = server.Accept();
Console.WriteLine("Client connected");
NetworkStream stream = new NetworkStream(client);
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
try
{
while(true)
{
string request = reader.ReadLine();
string filename = reader.ReadLine();
if (request == QUIT)
{
Console.WriteLine("Client disconnected");
break;
}
else if (request == SEND)
{
getFileFromClient(filename, client);
}
else if (request == RECV)
{
receiveFileFromClient(filename, client);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void getFileFromClient(string filename, Socket client)
{
try
{
FileStream output = File.OpenWrite(filename);
Console.WriteLine(filename + " created");
int count = 0;
while(true)
{
byte[] data = new byte[1024];
int size = client.Receive(data);
output.Write(data, 0, size);
count += size;
if(size<1024)
{
break;
}
}
output.Close();
Console.WriteLine(count + " bytes read from client");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void receiveFileFromClient(string filename, Socket client)
{
int count = 0;
FileStream input = File.OpenRead(filename);
Console.WriteLine("Reading " + filename);
while(true)
{
byte[] data = new byte[1024];
int bytesRead = input.Read(data, 0, 1024);
client.Send(data, bytesRead, SocketFlags.None);
count += bytesRead;
if(bytesRead < 1024)
{
break;
}
}
Console.WriteLine("Transferring file completed\r\n" + count + " bytes sent to Client");
input.Close();
}
}
Generally speaking
...try to approach the problem differently.
You can't just copy paste stuff from the Internet and hope for the best. You need to understand what you're doing thoroughly.
Regarding your exact problem
Take a look at the button2_Click method.
It contains a while loop which apparently never finishes.
while (true)
{
data = receiveData(socket);
MemoryStream ms = new MemoryStream(data);
break;
}
It does finish because of the break command. But this is all very hard to read.
When you copy paste code around and then apply quick fixes you end up with a pile of code which is very hard to debug.
It took me about 10 minutes to notice the fact that the client defines it's "message verbs" like so:
public const string SEND = "[SEND]";
public const string RECEIVE = "[RECEIVE]";
public const string QUIT = "[QUIT]";
while the server defines them like so:
public const string SEND = "[SEND]";
public const string RECV = "[RECV]";
public const string QUIT = "[QUIT]";
This is maybe not the only problem, but it is sufficient to create a deadlock,
because the server never executes the positive branch of this if statement:
else if (request == RECV)
{
receiveFileFromClient(filename, client);
}
so the client believes it is about to receive something, which proves to be false.
Also make sure you send the "SEND" and "RECEIVE" message verbs when you should and not mix them up.
Good luck!
PS: I would suggest you take a look at more simpler to use techniques for sending and receiving data, such as:
WCF
ASP.NET Web Services
Web API
Ignoring any logic errors that may occur in your programs, the way you are handling things in your client whenever it is doing an action it is doing it on the GUI thread. This will make your application seem like it is locking but instead it is executing your logic on the GUI thread.
The same problem is occurring on the server. It accepts a connection, and then goes on to receive the file. It will not be able to receive any other connection until it finished receiving the file.
The server is not without problems either because it is never checking if it receives 0 bytes from the socket. Which means that the client closed its end of the connection. You are simply assuming that if you receive less than 1024 you are receiving your last part of the file. This is simply not true for TCP. You only know you received the last part if you receive 0 bytes. TCP is a byte streaming protocol you cannot assume you will be receiving blocks of 1024 bytes. It is likely that this will be in fact the case, but you should not code it like that. Check for reception of 0 bytes. On the client you did check for 0 bytes, I am puzzled why you did not do the same on the server. The problematic part is this :
byte[] data = new byte[1024];
int size = client.Receive(data);
output.Write(data, 0, size);
count += size;
if(size<1024) //you can only break if the size is 0
{
break;
}
There are probably more bugs. As the other answer also indicated some other issues.
So I'm trying to make a chatroom. I use TCP Sockets to send all information. But when I send a byte array the receiving socket's buffer has the last byte missing. it's 0 cause the byte array is 255 big, so the left over bytes are 0. I've checked through debug mode, at the point when the packet was sent, the array is correct. But at the break point when the sockets finished receiving it's missing that last byte. Any reason why this would be happening? I saw another thread which said you had to stop the thread till the sockets finished receiving, but I'm using AsyncCallBack which to my knowledge is called when the socket has finished receiving.
Also the first byte in each packet is supposed to be the string size (To account for the extra empty bytes).
PacketClass:
public class Packet
{
public byte[] Buffer;
public Packet(string message)
{
Buffer = new byte[255];
byte[] messageArray = Encoding.ASCII.GetBytes(message);
Buffer[0] = (byte)messageArray.GetLength(0);
for (int i = 0; i < messageArray.GetLength(0); i++)
{
Buffer[i+1] = messageArray[i];
}
}
public Packet(byte[] buffer)
{
Buffer = buffer;
}
public string GetMessage()
{
List<byte> messageBuffer = new List<byte>();
for (int i = 1; i <= Buffer[0]; i++)
{
messageBuffer.Add(Buffer[i]);
}
return Encoding.ASCII.GetString(messageBuffer.ToArray());
}
}
SocketClass:
class Client
{
public static List<Client> connectedClients = new List<Client>();
public Socket Sock;
public byte[] Buffer = new byte[255];
public Client(Socket pSock)
{
Sock = pSock;
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
public void Send(byte[] pBuffer)
{
Sock.BeginSend(pBuffer, 0, pBuffer.GetLength(0), SocketFlags.None, new AsyncCallback(SendCallBack), null);
}
public void SendCallBack(IAsyncResult AR)
{
Console.WriteLine("Sent");
Sock.EndSend(AR);
}
public void RecieveCallBack(IAsyncResult AR)
{
Sock.EndReceive(AR);
Packet recPacket = new Packet(Buffer);
Console.WriteLine(recPacket.GetMessage());
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
}
Main Server Program
`class Client
{
public static List connectedClients = new List();
public Socket Sock;
public byte[] Buffer = new byte[255];
public Client(Socket pSock)
{
Sock = pSock;
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
public void Send(byte[] pBuffer)
{
Sock.BeginSend(pBuffer, 0, pBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), null);
}
public void SendCallBack(IAsyncResult AR)
{
Console.WriteLine("Sent");
Sock.EndSend(AR);
}
public void RecieveCallBack(IAsyncResult AR)
{
Sock.EndReceive(AR);
Packet recPacket = new Packet(Buffer);
Console.WriteLine(recPacket.GetMessage());
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
}`
Solved
The error was in the send method which I didn't include.
sock.BeginSend(sentBuffer[0].Buffer, 0, sentBuffer[0].Buffer[0], SocketFlags.None, new AsyncCallback(SendCallBack), null);
sentBuffer is a list, to be a queue. I changed it to 255 and it workd
I have this Server method called when client connected:
class Server {
protected override void clientIn(TcpClient client)//Called when a Client comes in
{
NetworkStream stream = client.GetStream();
byte[] y = new byte[client.ReceiveBufferSize];
objectState state = new objectState();
state.buffer = y;
state.user = client;
stream.BeginRead(y, 0, y.Length, read, state);
}
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
byte[] buffer = state.buffer;
TcpClient client = state.user;
int byte=client.GetStream().EndRead(ar);
client.GetStream().BeginRead(buffer, 0, client.ReceiveBufferSize, read, state);
String text = Encoding.ASCII.GetString(buffer);
Console.WriteLine(text);
}
}
class objectState
{
public TcpClient user;
public byte[] buffer;
}
I send two data from two different client and my problem is this:
If I don't execute the instruction "Console.WriteLine(text);", in Console I get 2 times the message "GetData"(it means that I get the data from 2 clients),
but If I execute the instruction "Console.WriteLine(text);", in Console I get 1 time the message "GetData" and below the data just got. It's the first client's data and the second client's data was lost but I don't understand why.
Can you help me?
Thank you for your time
UPDATE:
I edited the code in this way and it works fine , but I don't understand why:
protected override void clientIn(TcpClient client)
{
objectState state = new objectState();
state.user = client;
state.buffer= new byte[client.ReceiveBufferSize];
client.Client.BeginReceive(state.buffer, 0, client.ReceiveBufferSize, 0, new AsyncCallback(read), state);
}
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
TcpClient client = stato.user;
int dataSize = client.Client.EndReceive(ar);
String data = "";
data = Encoding.ASCII.GetString(state.buffer, 0,dataSize);
Console.WriteLine("\n "+data);
client.Client.BeginReceive(stato.buffer, 0, client.ReceiveBufferSize, 0, new AsyncCallback(read), state);
}
I don't understand where was wrong before.
UPDATE 2:
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
byte[] buffer = state.buffer;
TcpClient client = state.user;
int dataSize=client.GetStream().EndRead(ar);
String text = Encoding.ASCII.GetString(buffer);
state.buffer = new byte[client.ReceiveBufferSize];//new buffer
client.GetStream().BeginRead(state.buffer, 0, client.ReceiveBufferSize, read, state);
Console.WriteLine(text);
}
i have two Application to listen network Stream : Server.cs on the other hand; send file Client.cs. But i want to send more files on a stream from any folder. For example. i have C:/folder whish has got 3 jpg files. My client must run. Also My server.cs get files on stream:
Client.cs:
private void btn_send2_Click(object sender, EventArgs e)
{
string[] paths= null;
paths= System.IO.Directory.GetFiles(#"C:\folder" + #"\", "*.jpg", System.IO.SearchOption.AllDirectories);
byte[] Dizi;
TcpClient Gonder = new TcpClient("127.0.0.1", 51124);
FileStream Dosya;
FileInfo Dos;
NetworkStream Akis;
foreach (string path in paths)
{
Dosya = new FileStream(path , FileMode.OpenOrCreate);
Dos = new FileInfo(path );
Dizi = new byte[(int)Dos.Length];
Dosya.Read(Dizi, 0, (int)Dos.Length);
Akis = Gonder.GetStream();
Akis.Write(Dizi, 0, (int)Dosya.Length);
Gonder.Close();
Akis.Flush();
Dosya.Close();
}
}
Also i have Server.cs
void Dinle()
{
TcpListener server = null;
try
{
Int32 port = 51124;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[1024 * 250000];
// string ReceivedPath = "C:/recieved";
while (true)
{
MessageBox.Show("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
MessageBox.Show("Connected!");
NetworkStream stream = client.GetStream();
if (stream.CanRead)
{
saveFileDialog1.ShowDialog();
// burası degişecek
string pathfolder = saveFileDialog1.FileName;
StreamWriter yaz = new StreamWriter(pathfolder);
string satir;
StreamReader oku = new StreamReader(stream);
while ((satir = oku.ReadLine()) != null)
{
satir = satir + (char)13 + (char)10;
yaz.WriteLine(satir);
}
oku.Close();
yaz.Close();
client.Close();
}
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
Please look Client.cs: icollected all files from "c:\folder"
paths= System.IO.Directory.GetFiles(#"C:\folder" + #"\", "*.jpg", System.IO.SearchOption.AllDirectories);
My Server.cs how to get all files from stream?
It's not a typical way of doing things.
Usually you would write a single file in a single stream and repeat the process for multiple files. You risk data corruption this way as you'll have to place some kind of marker in the stream to know where to split it.
The easiest way is to use multiple sockets, one for commands and one (or more) for sending files.
The below code have NOT been tested, just wrote it up to show what I mean. It's multithreaded and can receive multiple files from the same client, just call sendfiles multiple times in the client.
You might want to add error/exception handling if you decide to finish the code.
Server.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Test2
{
public class Server
{
private readonly TcpListener _listener = new TcpListener(1234);
public void Start()
{
_listener.BeginAcceptTcpClient(OnClient, null);
}
private void OnClient(IAsyncResult ar)
{
// End async accept and start wait for a new connection again
TcpClient client = _listener.EndAcceptTcpClient(ar);
_listener.BeginAcceptTcpClient(OnClient, null);
// Let's start receiving files from the accepted client.
var context = new Context {Client = client, Buffer = new byte[8196]};
client.GetStream().BeginRead(context.Buffer, 0, context.Buffer.Length, OnReceive, context);
}
/// <summary>
/// Got some stuff from a client
/// </summary>
/// <param name="ar"></param>
private void OnReceive(IAsyncResult ar)
{
// got a file command
var context = (Context) ar.AsyncState;
int bytesRead = context.Client.GetStream().EndRead(ar);
string cmd = Encoding.UTF8.GetString(context.Buffer, 0, bytesRead);
string[] parts = cmd.Split(';');
string command = parts[0];
// want to send another file
if (command == "sendfile")
{
// context info for receiving files
var client = new FileClient();
client.FileName = parts[1];
client.Size = long.Parse(parts[2]);
client.FileStream = new FileStream("C:\\" + client.FileName, FileMode.CreateNew, FileAccess.Write);
// startup listener where we are going to receive the file.
var listener = new TcpListener(IPAddress.Any, 0); // get a kernelassigned number
client.Listener = listener;
listener.Start();
listener.BeginAcceptTcpClient(OnFileSocket, client);
// send reply
var ep = (IPEndPoint) listener.LocalEndpoint;
byte[] reply = Encoding.UTF8.GetBytes(ep.Port.ToString());
context.Client.GetStream().Write(reply, 0, reply.Length);
}
}
// Receiving the actual files.
private void OnFileSocket(IAsyncResult ar)
{
var client = (FileClient) ar.AsyncState;
client.Socket = client.Listener.EndAcceptTcpClient(ar);
var buffer = new byte[8192];
client.Buffer = buffer;
client.Socket.GetStream().BeginRead(buffer, 0, buffer.Length, OnReceiveFile, client);
}
private void OnReceiveFile(IAsyncResult ar)
{
var client = (FileClient) ar.AsyncState;
int bytesRead = client.Socket.GetStream().EndRead(ar);
client.Received += bytesRead;
client.FileStream.Write(client.Buffer, 0, bytesRead);
// recieved complete file, disconnect and exit.
if (client.Received == client.Size)
{
client.FileStream.Close();
client.Socket.Close();
return;
}
client.Socket.GetStream().BeginRead(client.Buffer, 0, client.Buffer.Length, OnReceiveFile, client);
}
#region Nested type: Context
private class Context
{
public byte[] Buffer;
public TcpClient Client;
}
#endregion
#region Nested type: FileClient
private class FileClient
{
public byte[] Buffer;
public string FileName;
public FileStream FileStream;
public TcpListener Listener;
public long Received;
public long Size;
public TcpClient Socket;
}
#endregion
}
}
Client.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Test2
{
internal class Client
{
private readonly IPAddress _server;
private readonly TcpClient _tcpClient = new TcpClient();
public Client(IPAddress server)
{
_server = server;
_tcpClient = new TcpClient();
}
public void Connect()
{
_tcpClient.Connect(new IPEndPoint(_server, 1234));
}
// asks server on which port the file should be sent.
private int RequestPort(string fileName, long length)
{
// lock tpcClient for each request, so we dont mix up the responses.
lock (_tcpClient)
{
// send request
byte[] bytes = Encoding.UTF8.GetBytes("sendfile;" + fileName + ";" + length);
_tcpClient.GetStream().Write(bytes, 0, bytes.Length);
// get reply
var buffer = new byte[1024];
int bytesRead = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
string reply = Encoding.UTF8.GetString(buffer, 0, bytesRead);
// error message or port?
int port;
if (!int.TryParse(reply, out port))
throw new InvalidOperationException("Server sent an error:" + reply);
return port;
}
}
public void SendFiles(string[] fileNames)
{
// Use a buffer to not preserve memory (instead of reading whole file into memory)
var buffer = new byte[8192];
foreach (string fileName in fileNames)
{
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Send on commandchannel that we want to send a file.
int filePort = RequestPort(Path.GetFileName(fileName), fileStream.Length);
var client = new TcpClient(new IPEndPoint(_server, filePort));
NetworkStream stream = client.GetStream();
// repeat until there are no more bytes to read.
int bytesRead = fileStream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
stream.Write(buffer, 0, bytesRead);
bytesRead = fileStream.Read(buffer, 0, buffer.Length);
}
stream.Close();
client.Close();
}
}
}
}
}