This question may be very hard to answer or perhaps somebody knows a common reason.
I have 1 server, 5 clients;
Socket client
Socket listener
Every 5000 MS the client checks for a file on the server (Which is Windows 7)via socket, if found the client received the file via socket.
I understand only Windows Server can process more than two asynch file transfers at a time.
My issue is that, randomly the client begins to receive the file. All clients generally work fine. Once in a while, a client will stop receiving the file partthrough and not complete the file transfer and my client program just hangs and never finishes.
I can NOT reproduce this on development environment. I have tested it with half-gig files, 100's of sends and I never get an error.
My question is , is it possible that there is some protocol on Windows 7 that is stopping my file send from the server.
My Receive call back for the client is quite lengthy, but here it is. I do not believe the problem to be within the code.
Any help would be greatly appreciated. My boss is about to have my neck :(
private static void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
state.totalBytesRead += bytesRead;
if (bytesRead > 0)
{
if (state.flag == 0)
{
if (state.totalBytesRead >= 8)
{
// we know we put the msgLen / prefixLen as the first 8 bytes on the stream
state.msgLen = BitConverter.ToInt32(state.buffer, 0);
state.prefixLen = BitConverter.ToInt32(state.buffer, 4);
state.flag = 1;
// good to process the first 2 integer values on the stream
//state.sb.Append(Encoding.ASCII.GetString(state.buffer, 8, bytesRead));
int prefixRequestBytes = state.prefixLen;
if (prefixRequestBytes > StateObject.BufferSize)
prefixRequestBytes = StateObject.BufferSize;
state.lastSendByteCount = prefixRequestBytes;
state.totalBytesRead = 0;
// start re-writing to the begining of the buffer since we saved
client.BeginReceive(state.buffer, 0, prefixRequestBytes, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
else
{
int bytesToSend = state.lastSendByteCount - bytesRead;
state.lastSendByteCount = bytesToSend;
// need to receive atleast first 8 bytes to continue
// Get the rest of the data.
client.BeginReceive(state.buffer, state.totalBytesRead, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
if (state.flag == 1)
{
// we are expexing to process the prefix
if (state.totalBytesRead >= state.prefixLen)
{
// we are good to process
// Lets always assume that our prefixMsg can fit into our prefixbuffer ( we wont send greater than prefixbuffer)
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.prefixLen));
string prefixMsg = state.sb.ToString();
if (!String.IsNullOrEmpty(prefixMsg))
{
state.cmd = parseXml("CMD", prefixMsg);
state.fName = parseXml("FNAME", prefixMsg);
// File requester should never get a del command
//if (state.cmd == "DEL")
//{
// Console.WriteLine("Processing 'DEL' command..");
// // delete the file
// string filePath = "C:\\" + locationFolder + "\\" + state.fName;
// if (System.IO.File.Exists(filePath))
// {
// System.IO.File.Delete(filePath);
// }
// Console.WriteLine("Deleted file");
// // receiveDone.Set();
// requestTimer.Start();
// return;
//}
//else
if (state.cmd == "SND")
{
Console.WriteLine("Processing 'SND' command..");
// let it rip
if (state.msgLen == 0) // no files
{
Console.WriteLine("No files on server");
requestTimer.Start();
return;
}
}
}
state.receivedPath = importTempFolder + state.fName;
// receive the rest of the file
if (System.IO.File.Exists(state.receivedPath))
{
Console.WriteLine("Deleting temp file: " + state.receivedPath + " for re-write");
System.IO.File.Delete(state.receivedPath);
}
state.flag++;
int msgRequestBytes = state.msgLen;
if (msgRequestBytes > StateObject.BufferSize)
msgRequestBytes = StateObject.BufferSize;
state.lastSendByteCount = msgRequestBytes;
state.totalBytesRead = 0;
// should be good to process the msg now
// start re-writing to the begining of the buffer since we saved
client.BeginReceive(state.buffer, 0, msgRequestBytes, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
else
{
int bytesToSend = state.lastSendByteCount - bytesRead;
state.lastSendByteCount = bytesToSend;
// request the rest of the prefix
// Get the rest of the data.
client.BeginReceive(state.buffer, state.totalBytesRead, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
// we are expecting to process the file
if (state.flag > 1)
{
if (state.totalBytesRead >= state.msgLen)
{
Console.WriteLine("Writing final {0} bytes to server", bytesRead);
using (FileStream fs = new FileStream(state.receivedPath, FileMode.Append, FileAccess.Write))
using (BinaryWriter writer = new BinaryWriter(fs))
{
//BinaryWriter writer = new BinaryWriter(File.Open(state.receivedPath, FileMode.Append, FileAccess.Write, FileShare.None));
writer.Write(state.buffer, 0, bytesRead);
fs.Flush();
// writer.Close();
}
// GC.Collect();
// if temp folder exists, import will exists because its inside it
string destFile = importFolder + state.fName;
if (System.IO.File.Exists(destFile))
{
Console.WriteLine("Deleting file for re-write in importin: \n" + destFile);
System.IO.File.Delete(destFile);
}
Console.WriteLine("Moving file: \n" + state.receivedPath);
System.IO.File.Copy(state.receivedPath, destFile);
Console.WriteLine("Deleting file from temp: \n" + state.receivedPath + importTempFolder + state.fName);
System.IO.File.Delete(state.receivedPath);
if (state.cmd == "SND")
{
Console.WriteLine("Sending 'DEL' command.");
SendDeleteResponse(client, state.fName);
Console.WriteLine("Finished reading to file: " + state.receivedPath);
// receiveDone.Set();
requestTimer.Start();
return;
}
Console.WriteLine("Finished reading file");
client.Shutdown(SocketShutdown.Both);
client.Close();
// receiveDone.Set();
requestTimer.Start();
}
else
{
//Console.WriteLine("Reading {0} bytes from server...", bytesRead);
// Padd these bytes
using (FileStream fs = new FileStream(state.receivedPath, FileMode.Append, FileAccess.Write))
using (BinaryWriter writer = new BinaryWriter(fs))
{
//BinaryWriter writer = new BinaryWriter(File.Open(state.receivedPath, FileMode.Append, FileAccess.Write, FileShare.None));
writer.Write(state.buffer, 0, bytesRead);
fs.Flush();
// writer.Close();
}
// GC.Collect();
// get how many more bytes are left to read
int bytesToSend = state.msgLen - bytesRead;
if (bytesToSend > StateObject.BufferSize)
bytesToSend = StateObject.BufferSize;
client.BeginReceive(state.buffer, 0, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
}
else
{
// All the data has arrived;
}
}
catch (Exception e)
{
Console.WriteLine("HERE5 " + e.Message);
client.Close();
// receiveDone.Set();
requestTimer.Start();
return;
}
}
Related
Simple I try to send a file to a server then send a file from server to client using networkstreams (only for files). The code shown is only server side, first one gets a file from client, second sends a file to client
try
{
using (var netStream = new NetworkStream(current, false))
{
netStream.ReadTimeout = 5000;
using (var fileStream = File.OpenWrite(cp.parameters[0] + "\\" + cp.parameters[0] + ".txt"))
{
fileStream.CopyFrom(netStream);
}
}
}
After this i try to execute this piece of code but it says on SocketException that I cannot use it because it's not connected. In debug for the socket "current" i see the .Connected variable is set to false but the IPEndpoints and ports for both sides are still the correct ones only the .Connected status is false.
try
{
Console.WriteLine("Text is a payloadx64file request");
using (var netStream = new NetworkStream(current, false))
{
using (var fileStream = File.OpenRead("Payload_x64.zip"))
{
fileStream.CopyTo(netStream);
Console.WriteLine(fileStream.Name);
}
}
}
How do i use the Socket with a network stream but prevent it to close down after garbage collector or block modification the variable .Connected, also as a side question
I mention that i set the ReadTimeout to 5 seconds because if there is no timeout in the Copy functions the Stream object get's stuck in a while loop because of a stream read that never ends. If someone knows how to end the loop or read please share with me too.
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) //here gets stuck in case someone knows
Here is the Copy code from a stream to another
public static void CopyTo(this Stream input, Stream output)
{
byte[] buffer = new byte[16 * 1024];
int bytesRead;
int total = 0;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
if (total <= totalFileSize)
{
byte[] clear_buffer = CryptosystemChiper.DecryptToByteArray(buffer);
int size = clear_buffer.Length;
output.Write(clear_buffer, 0, size);
total += size;
//Console.WriteLine("Bytes got:" + size); FROM DEBUG
//Console.WriteLine("Total: " + total + " bytesRead is: " + bytesRead); FROM DEBUG
}
else
{
//Console.WriteLine("Total: " + total + " bytesRead is: " + bytesRead); FROM DEBUG
//Console.WriteLine("About to break"); FROM DEBUG
break;
}
}
I am working on a unity project where user can send data from client to server using TCP/IP. I am able to send the data. But my unity stalls or freeze until the data got read from the networkstream.
Server Code:Read Data.
public void StartServer (){
// Start TcpServer background thread
tcpListenerThread = new Thread (new ThreadStart(ListenForIncomingRequests));
tcpListenerThread.IsBackground = true;
tcpListenerThread.Start();
startServerButton.interactable = false;
path = UnityEditor.EditorUtility.SaveFolderPanel ("Any type of File.", "", ""); // Path.Combine(path,"D:\\Siva\\TCPDownloadfiles");
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)) {
SendMessage();
}
}
/// <summary>
/// Runs in background TcpServerThread; Handles incoming TcpClient requests
/// </summary>
private void ListenForIncomingRequests () {
Thread threadForDownloading = new Thread (new ThreadStart(DownloadingStreamData));
threadForDownloading.IsBackground = true;
threadForDownloading.Start();
//DownloadingStreamData ();
}
private void DownloadingStreamData()
{
try {
fileCount++;
int fileNameLen;
byte[] incomingData = new byte[1024];
string ext = "";
// Create listener on localhost port 8052.
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8052);
tcpListener.Start();
Debug.Log("Server is listening");
bytes = new Byte[Int32.MaxValue]; // 2221024
while (true) {
using (connectedTcpClient = tcpListener.AcceptTcpClient()) {
// Get a stream object for reading
using (stream = connectedTcpClient.GetStream()) {
Debug.Log("Befor Stream Read..........");
IAsyncResult result = stream.BeginRead(bytes, 0, bytes.Length, MessageReceived, stream);
result.AsyncWaitHandle.WaitOne();
// Read incoming stream into byte arrary.
do{
//length = stream.Read(bytes, 0, bytes.Length);
//length = s_bytesReceived;
Debug.Log("After Stream Read.........."+length);
incomingData = new byte[length];
Array.Copy(bytes, 0, incomingData, 0, length - 4);
// Convert byte array to string message.
fileNameLen = BitConverter.ToInt32(incomingData, 0);
string clientMessage = Encoding.ASCII.GetString(incomingData,4, fileNameLen);
ext = Path.GetExtension(clientMessage);
//Debug.Log("client message received as: " + clientMessage);
//File.WriteAllBytes(path + "\\temp"+fileCount.ToString()+ext, incomingData);
BinaryWriter bWrite = new BinaryWriter(File.Open(path + "\\temp"+fileCount.ToString()+ext, FileMode.Create)); ;
bWrite.Write(incomingData, 4 + fileNameLen, length - 4 - fileNameLen);
bWrite.Flush();
bWrite.Close();
} while(stream.DataAvailable);
//Debug.Log("Bytes length2 :>>>"+" "+fileNameLen +" Incoming data length" +incomingData.Length);
//connectedTcpClient.Close();
//stream.Flush();
//stream.Close();
//Debug.Log("GETTING FILE NAME THROUGH BUFFER ::"+stream);
}
}
}
}
catch (SocketException socketException) {
Debug.Log("SocketException " + socketException.ToString());
}
}
I tried using stream.BeginRead method but that is throwing exception like Stream/socket was disposed already and trying to access it on client code.
But stream.Read method works as like i expect but it stalls/freeze the unity until it get the data.Please give me some better solution for this issue. Thanks in advance.
Client Code: Sends Data
if (stream.CanWrite) {
string path = UnityEditor.EditorUtility.OpenFilePanel ("Any type of File.", "", "");
WWW www = new WWW ("file:///" + path);
byte[] fileNameBytes = Encoding.ASCII.GetBytes(path);
byte[] fileDataBytes = www.bytes;
byte[] fileNameLength = BitConverter.GetBytes(fileNameBytes.Length);
clientData = new byte[4 + fileNameBytes.Length + fileDataBytes.Length];
fileNameLength.CopyTo(clientData, 0);
fileNameBytes.CopyTo(clientData, 4);
fileDataBytes.CopyTo(clientData, 4 + fileNameBytes.Length);
Debug.Log ("FIle sends to server path : "+path);
//stream.BeginRead(clientData, 0, clientData.Length, MessageReceived, stream);
try {
stream.Write(clientData, 0, clientData.Length);
//stream.BeginWrite(clientData, 0, clientData.Length, MessageReceived, stream);
}catch (Exception e) {
Debug.Log("SocketException " + e.ToString());
}
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);
}
}
}
}
Alright so for my game, Ive set up a server / client peer to peer connection, to send positions and etc back and forth.
Although my messages arent actually sending that fast, and not reliably either. As in parts of the strings are missing, and sometimes the sending just halts and the thread doesnt continue ( not sure why ).t
Anyways my Recieving code is here :
public void RecieveAsync()
{
if (netStream == null) netStream = Server.GetStream();
if (netStream.DataAvailable == false) return;
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, new AsyncCallback(recieveCallBack), netStream);
}
public void recieveCallBack(IAsyncResult ar)
{
//try
//{
String content = String.Empty;
Console.WriteLine("Stuck trying to get data");
int rec = netStream.EndRead(ar);
if (rec > 0)
{
Console.WriteLine(Encoding.ASCII.GetString(
ReadBuffer, 0, rec));
string packet = Encoding.ASCII.GetString(
ReadBuffer, 0, rec);
bool completedPacket = false;
int appendTo = rec;
if (packet.Contains("<eof>"))
{
appendTo = packet.IndexOf("<eof>");
packet.Replace("<eof>", "");
completedPacket = true;
}
SB.Append(packet, 0, appendTo);
// Check for end-of-file tag. If it is not there, read
// more data.
content = SB.ToString();
if (completedPacket)
{
// All the data has been read from the
// client. Display it on the console.
if (DataRecieved != null)
{
string RecievedData = SB.ToString();
DataRecieved(RecievedData);
netStream.Flush();
Array.Clear(ReadBuffer, 0, ReadBuffer.Length);
ReadBuffer = new byte[1024];
}
SB.Clear();
// Echo the data back to the client.
}
else
{
// Not all data received. Get more.
Array.Clear(ReadBuffer, 0, ReadBuffer.Length);
ReadBuffer = new byte[1024];
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
}
}
}
And my sending code here :
public void Send(byte[] data, int index, int length)
{
//add data as state
//socket.NoDelay = true;
if (netStream == null) netStream = TcpClient.GetStream();
netStream.BeginWrite(data, 0, length, sendCallback, netStream);
}
private void sendCallback(IAsyncResult ar)
{
//try
//{
netStream.EndWrite(ar);
//if (ar.AsyncState != null)
//{
// byte[] buffer = (byte[])ar.AsyncState;
// socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
// return;
//}
if (OnSend != null)
{
OnSend(this);
}
netStream.Flush();
//catch (Exception ex)
//{
// System.Windows.Forms.MessageBox.Show(ex.ToString());
// return;
//}
}
The packets are under the Encoding.ASCII.Getbytes.
And both the server and client are updating in while (true) threads with a Thread.Sleep(1).
Because you're trying to reconstitute a string bit by bit (this approach will break if you use more common multibyte encoding such as UTF8), your approach to this is fragile.
As stated in my comment, you might well miss your <eof> because it is split over two reads.
IMO, a preferable approach is to tag your message with a preceding length field (4 byte int) so that you don't have to tiptoe around at the end of the message trying to figure out if it's finished yet.
Just pour all your reads into a MemoryStream until you reach the indicated message length, then decode the contents of the MemoryStream with whatever encoding you see fit.