Reputation: 567
I'm trying to send files using sockets..it's working with few bytes files no more...how to solve this problem? It's a client / server program I'm trying to send at least 50 MB.
The client side-Sending:
System.Net.Sockets.TcpClient tcpClient = new
System.Net.Sockets.TcpClient();
tcpClient.Connect(recipientIP, FTPPORTNO);
int BufferSize = tcpClient.ReceiveBufferSize;
NetworkStream nws = tcpClient.GetStream();
FileStream fs;
fs = new FileStream(filename, FileMode.Open,
FileAccess.Read);
byte[] bytesToSend = new byte[fs.Length];
int numBytesRead = fs.Read(bytesToSend, 0,
bytesToSend.Length);
int totalBytes = 0;
for (int i = 0; i <= fs.Length/BufferSize; i++)
{
//---send the file---
if (fs.Length - (i*BufferSize) > BufferSize)
{
nws.Write(bytesToSend, i*BufferSize,
BufferSize);
totalBytes += BufferSize;
}
else
{
nws.Write(bytesToSend, i*BufferSize,
(int) fs.Length - (i*BufferSize));
totalBytes += (int) fs.Length - (i*BufferSize);
}
fs.Close();
}
The Recieving code:
try
{
//---get the local IP address---
System.Net.IPAddress localAdd =
System.Net.IPAddress.Parse(
ips.AddressList[0].ToString());
//---start listening for incoming connection---
System.Net.Sockets.TcpListener listener = new
System.Net.Sockets.TcpListener(localAdd,
FTPPORTNO);
listener.Start();
//---read incoming stream---
TcpClient tcpClient = listener.AcceptTcpClient();
NetworkStream nws = tcpClient.GetStream();
//---delete the file if it exists---
if (File.Exists("c:\\temp\\" + filename))
{
File.Delete("c:\\temp\\" + filename);
}
//---create the file---
fs = new System.IO.FileStream("c:\\temp\\" + filename,
FileMode.Append, FileAccess.Write);
int counter = 0;
int totalBytes = 0;
do
{
//---read the incoming data---
int bytesRead = nws.Read(data, 0,
tcpClient.ReceiveBufferSize);
totalBytes += bytesRead;
fs.Write(data, 0, bytesRead);
//---update the status label---
ToolStripStatusLabel1.Text = "Receiving " +
totalBytes + " bytes....";
Application.DoEvents();
counter += 1;
} while (nws.DataAvailable);
ToolStripStatusLabel1.Text = "Receiving " + totalBytes
+ " bytes....Done.";
fs.Close();
tcpClient.Close();
listener.Stop();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
The Server Code:
public void SendMessage (string message)
{
//---adds a linefeed char---
message += "\n";
try
{
//---send the text---
System.Net.Sockets.NetworkStream ns;
lock (client.GetStream())
{
ns = client.GetStream();
byte[] bytesToSend =
System.Text.Encoding.ASCII.GetBytes(message);
//---sends the text---
ns.Write(bytesToSend, 0, bytesToSend.Length);
ns.Flush();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Any Ideas?
Upvotes: 0
Views: 8382
Reputation: 133975
Your primary problem is that you're expecting DataAvailable == false
to mean that no more data is forthcoming. That's not the case. DataAvailable
says whether data is available right now. It doesn't mean that there won't be any more available at some point in the future.
If you're sending and receiving data of any kind, there must be some way for the sender to tell the receiver where the end of the message is. In general there are two ways to do that:
With text protocols, the second option is typically used: a message is sent, and terminated with a newline. That marks the end of the message.
When sending binary data, the first method is typically used. That header can be something as simple as four bytes that say how long the file is. So in your case you'd write something like:
// tell receiver how many bytes are coming
byte[] lengthData = BitConverter.GetBytes[fs.Length];
nws.Write(lengthData, 0, lengthData.Length);
// then send the file
The receiver, then, needs to read the first four bytes, convert to an integer, and then read that many bytes. Only when it's read that many bytes can it know that it's reached the end of the file.
// read length
byte[] lengthData = new byte[4];
bytesRead = nws.Read(lengthData, 0, 4);
// I assume here that it got all four bytes. In your code, you'll want to
// make sure that you got four bytes before moving on.
int bytesToRead = BitConverter.ToInt32(lengthData, 0);
// Now start your reading loop, and read until the total number of bytes read
// is equal to the bytesToRead value above.
Upvotes: 1
Reputation: 101140
Why don't you just do this on the sender end:
fileStream.CopyTo(networkStream);
A lot simpler :)
On the receiver side you cannot assume that DataAvailable = false
means that there are no more data. It's better that the sender closes the connection when done socket.Shutdown(SocketShutdown.Send)
and that the receiver continues to read until 0
is returned.
Sender side:
socket.Shutdown(SocketShutdown.Send);
socket.Receive(xxx)
to wait for graceful disconnectSocket.Close();
Receiver side:
socket.Shutdown(SocketShutdown.Both)
Socket.Close();
However, you still got a flaw: The socket might have been disconnected due to network failure. Only way to know that is to send the file size first (before sending file)
Upvotes: 0