C# Weird issue with BinaryFormatter serialize/deserialize - c#

I'm currently having a VERY weird issue with BinaryFormatter serialize / deserialize i hope i can get some help with.
Right now, i'm currently working on learning Game Development with Unity 5.5 for the last 2 months. I decided to challenge myself and create a multiplayer game in which i've created the network part all by myself.
Around a week ago, i tested it over the internet with a friend and all was working as expected, but yesterday i found a problem which is making it unplayable.
[Serializable]
public class Packet
{
//Remeber to change Packet function if changing something here
public List<string> Gdata;
public int PacketInt;
public bool PacketBool;
public string senderID;
public PacketType packetType;
public Packet(PacketType type, string senderID)
{
Gdata = new List<string>();
this.senderID = senderID;
this.packetType = type;
}
public Packet(byte[] packetBytes)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream(packetBytes);
Console.WriteLine(packetBytes);
Packet p = (Packet)bf.Deserialize(ms);
ms.Close();
this.Gdata = p.Gdata;
this.PacketInt = p.PacketInt;
this.PacketBool = p.PacketBool;
this.senderID = p.senderID;
this.packetType = p.packetType;
}
public byte[] ToBytes()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this);
byte[] bytes = ms.ToArray();
ms.Close();
return bytes;
}
public static string GetIP4Address()
{
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress i in ips)
{
if (i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
return i.ToString();
}
return "127.0.0.1";
}
}
public enum PacketType
{
/* Connection */
Connecting,
Handshake,
ConnectionComfirmed,
DataRequest,
NewClient, // Sent from the server to all players online when a new player has connected, containing revelant data to sync the new player.
Disconnecting,
/* Errors */
ServerError,
/* Updates */
Movement,
PositionUpdate,
/* Chat */
Chat
}
The problem i'm describing below happends on the line Packet p = (Packet)bf.Deserialize(ms);
This is what i'm using to handle the packets. It's inside a DLL which i have attached to both the server software and the game i'm creating. An example on how it works is this:
void DataManager(Packet p)
{
switch (p.packetType)
{
case PacketType.Connecting:
if (p.Gdata[1] == ServerHandshake)
{
_clientID = p.senderID;
Packet sp = new Packet(PacketType.Handshake, _clientID);
sp.Gdata.Add(ClientHandshake);
_socket.Send(sp.ToBytes());
}
break;
}
}
When testing it locally, it's working without a problem and has been working fine for the last 2 months. Also, as i wrote above, i tested it a little over a week ago without a problem what so ever.
However, the problem now is that for some reason, at the exact same moment, i get the error 'The input stream is not a valid binary format' whenever someone connected over the internet is moving. The code for this part is below:
if (movement_vector != Vector2.zero)
{
anim.SetBool("iswalking", true);
anim.SetFloat("input_x", movement_vector.x);
anim.SetFloat("input_y", movement_vector.y);
Packet p = new Packet(PacketType.Movement, GetComponent<Script_PlayerData>().Player_GUID);
p.Gdata.Add(movement_vector.x.ToString());
p.Gdata.Add(movement_vector.y.ToString());
p.Gdata.Add(player.position.x.ToString());
p.Gdata.Add(player.position.y.ToString());
GameObject.Find("GameScripts").GetComponent<Script_Network>()._socket.Send(p.ToBytes());
if (HasMoved == 0) HasMoved = 1;
}
Before this part is even executed, the server and game client is sending several packets back and forth, and that is working completly fine. Even the chat i've added to the game is working as intended but as soon as a player connected over the internet is moving to any direction, i get the 'The input stream is not a valid binary format' exception thrown, even though it's working fine locally with atleast up to 10 clients connected.
I've been looking around on the internet for hours trying to find a solution to this issue but nothing i've tested or read so far has been working for me.
I haven't modified this code at all since the first time i tested it with remote players connected. I also update the DLL in the Unity project every time after i have compiled the DLL.
So as a last resort, i'm asking here. Anyone knows what possibly could make it behave like this, and does anyone knows a solution to it?
EDIT: Apparently forgot to specify it's TCP. Code Snippets below that might help you understand better how it works:
Server Program:
void SetupSocket()
{
ConsoleMessage("Initializing socket...");
_listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(s_config.ServerIP), s_config.ServerPort);
ConsoleMessage("Binding server to " + s_config.ServerIP + ":" + s_config.ServerPort);
_listenerSocket.Bind(ip);
_listenerThread = new Thread(ListenThread);
_listenerThread.Start();
}
void NetworkListener(Socket _socket, string GUID) // Threaded for each client connected
{
OnlinePlayers++;
byte[] Buffer;
int readBytes;
try
{
for (;;)
{
int l = GetPlayerIndexSlot(GUID);
if (l == -1) break;
Buffer = new byte[_socket.SendBufferSize];
readBytes = _socket.Receive(Buffer);
if (readBytes > 0)
{
Packet packet = new Packet(Buffer);
DataManager(_socket, packet);
}
}
}
catch (SocketException ex)
{
ConsoleMessage("Socket error: " + ex.ErrorCode + ", Client id: " + GUID);
if (ex.ErrorCode == 10054) // WSAECONNRESET - Connection reset by peer
{
OnPlayerDisconnecting(_socket, 5);
}
}
}
void DataManager(Socket _socket, Packet p)
{
switch (p.packetType)
{
case PacketType.Connecting: ConnectingPacket(_socket, p.Gdata[0]); break;
case PacketType.Handshake: HandshakeProcess(p.senderID, _socket, p.Gdata[0]); break;
case PacketType.Disconnecting: OnPlayerDisconnecting(_socket, 0); break;
case PacketType.DataRequest: DataRequest(p.Gdata[0], _socket, p.senderID); break;
case PacketType.Movement: PlayerMovement(p.senderID, _socket, p.Gdata[0], p.Gdata[1], p.Gdata[2], p.Gdata[3]); break;
case PacketType.PositionUpdate: PlayerPositionUpdate(p.senderID, _socket, p.Gdata[0], p.Gdata[1]); break;
case PacketType.Chat: ChatMessage(p.senderID, _socket, p.Gdata[0]); break;
}
}

Related

A device attached to the system is not functioning

I'm working on an UWP application (Universal Windows) and I got this problem, I'm hoping that your talent will help me a lot. The problem is I plugged an headset HidDevice to read Firmware Version from that headset.
Here is my code:
public async void ReadFirmwareVersion()
{
if (DeviceManagerEventHandler.Current.HidDevice != null)
{
HidOutputReport outReport = DeviceManagerEventHandler.Current.HidDevice.CreateOutputReport();
byte[] buffer = queryVersion();
DataWriter dataWriter = new DataWriter();
dataWriter.WriteBytes(buffer);
outReport.Data = dataWriter.DetachBuffer();
await DeviceManagerEventHandler.Current.HidDevice.SendOutputReportAsync(outReport);
HidInputReport inReport = await DeviceManagerEventHandler.Current.HidDevice.GetInputReportAsync();
if (inReport != null)
{
UInt16 id = inReport.Id;
var bytes = new byte[64];
DataReader dataReader = DataReader.FromBuffer(inReport.Data);
dataReader.ReadBytes(bytes);
}
else
{
rootPage.NotifyUser("Invalid input report received", NotifyType.ErrorMessage);
}
}
}
public static Byte[] queryVersion()
{
Byte[] cmd = new Byte[64];
cmd[0] = 0x0B;
cmd[1] = 0x11;
return cmd;
}
I got an error at
outReport.Data = dataWriter.DetachBuffer();
they said
Value does not fall within the expected range
and 1 more error at HidInputReport inReport = await DeviceManagerEventHandler.Current.HidDevice.GetInputReportAsync(); is
A device attached to the system is not functioning
I tried to get the headset firmware version but it didn't work out due to these errors. Please help, I spent 2 days almost. Did I do something wrong?

C# Deadlock in Named Pipe

Im stuck. I have joined the project that uses Named Pipes, and have lets say "not ideal architecture". And seems like I accidentally received a deadlock:(
The logic is following. There is Named Pipe. Client and Server model. On server part there is a loop, that always pings named pipe and process what client sends, sometimes sending back responses.
On Client side of my pipe, I have following method, from other developer, that is being used to send request to server and receive and return the response.
private object locker = new Object();
private string ListenOnce(string msg)
{
Debug.WriteLine("Will listen for message " + msg);
string msgFrom = "";
if (run) {
string toReturn = "";
lock (locker) {
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain(); //Waiting for another process to read the command
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
if (toReturn.Contains('¥'))
{
string[] split = toReturn.Split('¥');
if (split.Length > 1)
{
var roomNames = this.connection.application.GameCache.GetRoomNames();
for (int i = 1; i < split.Length; i++)
{
string[] split2 = split[i].Split('¶');
if (split2.Length > 1)
{
string accountName = split2[0];
int offenderActorID = int.Parse(split2[1]);
string offenderRoomName = split2[2];
foreach (var roomName in roomNames)
{
Room room;
if (this.connection.application.GameCache.TryGetRoomWithoutReference(roomName, out room))
{
Game game = room as Game;
if (game != null && game.Name == offenderRoomName)
{
GameClientPeer peer = (GameClientPeer)game.ActorsManager.ActorsGetActorByNumber(offenderActorID).Peer;
if (peer != null)
{
peer.KickPlayer();
}
}
}
}
}
}
}
}
}
if (toReturn.Contains('¥'))
{
return toReturn.Split('¥')[0];
}
else
{
return toReturn;
}
}
return "";
}
The problem is - in some cases I cant receive response from pipe right when requested, and need to start what I called here "poller". This is a task, that loops 5 times, and during those 5 times "polls" the pipe through this ListenOnce method.
private void PollTargets()
{
timer.Dispose();
Debug.WriteLine("Going to start polling");
Task.Factory.StartNew(() => {
int runCount = 0;
while (true)
{
runCount++;
PipeOperation request = new PipeOperation(Consts.Pipes.RequestTargets, uniqueID);
string responseStr = unityConnection.client.SendMessage(JsonConvert.SerializeObject(request));
Debug.WriteLine("Task is running, response is " + responseStr);
if (!string.IsNullOrEmpty(responseStr))
{
try
{
PipeOperation pipeResponse = JsonConvert.DeserializeObject<PipeOperation>(responseStr);
if (!string.IsNullOrEmpty(pipeResponse.Payload))
{
GrenadeExplosionData explosionData = JsonConvert.DeserializeObject<GrenadeExplosionData>(pipeResponse.Payload);
if (explosionData != null)
{
//probably need to invoke that in main thread
DealDamage(explosionData);
//isRunning = false;
Debug.WriteLine("Received nice response, will damage targets");
break;
}
}
}
catch (Exception exc)
{
Debug.WriteLine("Something went wrong while polling...");
Debug.WriteLine(exc.Message);
break;
}
}
if (runCount > 5)
{
Debug.WriteLine("run count exceed " + runCount.ToString());
break;
}
}
RemoveGrenadeFromUnityConnection();
});
}
I am starting poller when the Grenade explodes, from timer like that:
timer = new System.Threading.Timer((obj) =>
{
PollTargets();
},
null, 4000, System.Threading.Timeout.Infinite);
And thats it. After people play 2-3 hrs. Seems like I receive a deadlock. It should be taken into account that there might be many grenades on server who starts that poller, so probably it just goes mad at some point over there.
Pls help, Im stuck with that. Who has ideas?
We should keep in mind, that
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain();
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
should be used only by one thread at a time, as stream might be read only from one source.
There are several calls to ListenOnce from the code, but not a lot. One is being fired every 4 minutes.The rest ones are not constant, but conditional.
Hope somebody would see where is a mistake here...
Found what locks everything...However, it does not help a lot:)
Its
stream.WaitForPipeDrain();
it tries to read another end of pipe, but because of there is no timeouts in message mode, it just hangs for ever..

Socket not reading all the packets that arrive

I am working on a C# TCP client and monitoring my packets using Microsoft Network Monitor. There is a server that's basically a black box sends an N amount of packets (right now it's in the order of 10-20) with a delay of 0,1 ms to 1 ms between each of them and the next one.
The packets that are read by my client are in order and of course most arrive in larger chunks than appear on Network Monitor since TCP receives the stream. My problem is some packets fail to arrive (I did check the previous chunk of information to make sure it's not there. They aren't stored in the wrong order either.).
So is it possible that my client is missing some of the information somehow? Are the packets being sent too frequently? Sadly I cannot tamper with their frequency. I add here some of my code, if you could enlighten me as to why packets that arrive are not read and how to solve this I would be most grateful.
This is where I first call BeginReceive:
private static void AcceptCallback(IAsyncResult result)
{
ConnectionInfo connection = new ConnectionInfo();
MensajeRecibido msj = new MensajeRecibido();
try
{
// Finish Accept
Socket s = (Socket)result.AsyncState;
connection.Socket = s.EndAccept(result);
msj.workSocket = connection.Socket;
connection.Socket.Blocking = false;
connection.Buffer = new byte[255];
lock (connections) connections.Add(connection);
// Start Receive
connection.Socket.BeginReceive(msj.buffer, 0,
msj.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), msj);
// Start new Accept
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), result.AsyncState);
}
catch (SocketException exc)
{
//Log here
}
catch (Exception exc)
{
//Log here
}
}
This is the callback:
private async static void ReceiveCallback(IAsyncResult result)
{
MensajeRecibido mensaje = new MensajeRecibido();
mensaje = (MensajeRecibido)result.AsyncState;
try
{
mensaje.workSocket.EndReceive(result);
mensaje.EstaCompleto();
mensaje.workSocket.BeginReceive(mensaje.buffer, 0,
mensaje.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), mensaje);
}
catch (SocketException)
{
//Log
}
catch (Exception)
{
//Log
}
}
And this is the method EstaCompleto() which basically converts the message and adds it to a list. (It returns true or false because it's actually meant to go in an if clause but until I get rid of this problem that really serves no purpose)
public bool EstaCompleto()
{
MensajeActual = Destuffing(ByteToFrame_Decoder(buffer)); //This translates the message to an understandable string
Mensajes.Enqueue(MensajeActual);
if(MensajeActual.Contains("<ETX>"))
{
return true;
}
else return false;
}
Edit 25/3/15:
Here's the rest of the class MensajeRecibido.
public class MensajeRecibido
{
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 25500;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
public string UltimoMensajeLeido = "0";
public string MensajeActual = "0";
public Queue<string> Mensajes = new Queue<string>();
public IPAddress IPRack;
//*******************************************************************
public bool EstaCompleto()
///See code in the previous sample
//*******************************************************************
public string ByteToFrame_Decoder(byte[] frame)
{
string answer = null;
UTF8Encoding ObjDecoder = new System.Text.UTF8Encoding();
char[] array_chares = new char[frame.Length];
string msj_neg = null;
string titlemsg = "Atención";
try
{
int cant = ObjDecoder.GetChars(frame, 0, frame.Length, array_chares, 0);
}
catch (EncoderFallbackException EncFbackEx)
{
msj_neg = "No hay comunicación";
// System.Windows.Forms.MessageBox.Show(msj_neg, titlemsg, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
answer = decode_string(array_chares);
return answer;
} // fin método ByteToFrame_Decoder()
//*******************************************************************
public string Destuffing(string msjstuff)
{
string destuffed = null;
string matched = null;
string original = null;
int largo = msjstuff.Length;
for (int i = 0; i < (largo - 1); i++)
{
matched = msjstuff.Substring(i, 2);
original = msjstuff.Substring(i, 1);
if (original != " ")
{
switch (matched)
{
case "EX":
{ original = "D"; i++; } break;
case "ex":
{ original = "d"; i++; } break;
case "EE":
{ original = "E"; i++; } break;
case "ee":
{ original = "e"; i++; } break;
case " ":
{ original = ""; i += 2; } break;
}
destuffed = destuffed + original;
}
else
{
i++;
}
}
destuffed = destuffed + ">";
return destuffed;
} //fin método Destuffing()
//*******************************************************************
public static string decode_string(char[] ArrChar)
{
string text = null;
string reply = null;
foreach (char letter in ArrChar)
{
int value = Convert.ToInt32(letter);
string hexOutput = String.Format("{0:X}", value); // Convert the decimal value to a hexadecimal value in string form.
switch (hexOutput)
{
case "20":
text = " ";
break;
case "1":
text = "<SOH>";
break;
case "2":
text = "<STX>";
break;
case "3":
text = "<ETX>";
break;
case "4":
text = "<EOT>";
reply = reply + text;
goto Finish;
case "5":
text = "<ENQ>";
break;
case "6":
text = "<ACK>";
break;
case "15":
text = "<NAK>";
break;
case "17":
text = "<ETB>";
break;
case "1E":
text = "<RS>";
break;
/*case "23":
text = "#";
break;
case "24":
text = "$";
break;
case "26":
text = "&";
break;*/
default:
text = letter.ToString();
break;
}
reply = reply + text;
}
Finish: ; //salimos del foreach
return reply;
} //fin método decode_string()
//*******************************************************************
}
Without a good, minimal, complete code example that reliably demonstrates the problem, it's impossible to provide an exact fix for the bug.
However, from this statement in your ReceiveCallback() method, it's clear what the problem is:
mensaje.workSocket.EndReceive(result);
The EndReceive() method returns a byte count for a reason: there is no guarantee of the number of bytes that will be received.
Network programming novices generally complain about two different behaviors:
Their code only receives part of a "packet" (or "message", or similar terminology).
Their code fails to receive some of the "packets" which were sent.
Both problems stem from a single source: the failure to understand that in the TCP protocol, there is no such thing as a "packet".
It's up to the application to define a message boundary. All that TCP gives you is a guarantee that if the bytes sent are in fact received, they will be received in the same order in which they were sent, and if any given byte is received, all of the previously sent bytes were also received (i.e. no gaps in the data).
Problem #1 above happens when TCP delivers only part of what the novice programmer sent as a "packet". This is perfectly legal behavior on TCP's part, and it's up to the application to keep track of the data received so far and to figure out when it's received a whole "packet".
Problem #2 (which is what you're experiencing) happens when TCP delivers two or more "packets" in a single receive operation. Again, this is perfectly legal on TCP's part, and it's up to the application to process the received data and identify where one "packet" ends and the next begins.
The first step to doing all of this correctly is to actually copy the return value of the EndReceive() method to a variable, and then to use that value as part of processing the received data. Since your code example doesn't save the value anywhere, or even look at it at all, I can guarantee that you aren't correctly handling the "packet" boundaries in your data.
How should you handle those boundaries? I have no idea. It depends on how you are sending the data, and how you want to process the results. Without a complete code example (as described in the link I provided above), it's not possible to address that. Do note however that there are a large number of examples out there for how to do it correctly. Hopefully now that you know what to look for, you will be able to come up with a fix yourself. If not, feel free to create a good code example and post a new question asking for help with that.

How to convert byte into Boolean

I want to convert a byte into Boolean. This is the code:
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true)
{
MessageBox.Show("Name: ");
string name = "Connected";
if (name == "") break;
byte[] sdata = Encoding.ASCII.GetBytes(name);
udpc.Send(sdata, sdata.Length);
if (udpc.Receive(ref ep)=null)
{
// MessageBox.Show("Host not found");
}
else
{
byte[] rdata = udpc.Receive(ref ep);
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job);
}
}
I want to convert this line of code into a Boolean:
udpc.Receive(ref ep);
You don't want to just compare the result with null at all... that way you would lose the actual data, and then call Receive again, effectively skipping the packet.
You should use:
byte[] data = udpc.Receive(ref ep);
if (data == null)
{
// Whatever
}
else
{
MessageBox.Show(Encoding.ASCII.GetBytes(data));
}
Also note that this code is broken:
string name = "Connected";
if (name == "") break;
How can name possibly be an empty string when you've just set it to "Connected"?
The UdpClient is naturally blocking until bytes are received.
This means that you shouldn't get data at all, assuming that you're looking for a way to indicate if you have received data, then once you move past the udpc.Recieve, you should return true.
I would also consider changing the code a bit as you will have some compilation issues with the = null statement as this does not translate into a compilable code expression.
There is also a problem with your if else statement as you're attempting to read from the UDP client which would consume the sent data.
Personally I would opt for a UDP socket, but in order to get you rolling I would change the code to something like this:
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true)
{
MessageBox.Show("Name: ");
string name = "Connected";
if (name == "") break; //This will never happen because you have already set the value
byte[] sdata = Encoding.ASCII.GetBytes(name);
int dataSent = 0;
try
{
dataSent = udpc.Send(sdata, sdata.Length);
}
catch(Exception e)
{
dataSent = 0;
//There is an exception. Probably the host is wrong
}
if (dataSent > 0)
{
try
{
byte[] rdata = udpc.Receive(ref ep);
if(rdata!=null && rdata.Length > 0)
{
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job)
//True here as we managed to recieve without going to the catch statement
//and we actually have data in the byte[]
}
else
{
MessageBox.Show("We did not recieve any data");
//False here, because the array was empty.
}
}
catch(Exception udpe)
{
//False here as we had a socket exception or timed out
MessageBox.Show(udpe.ToString());
}
}
}

Udp packets to machine behind nat

First of all sry about my english. My problem is i have electronic circuit on press machine. This circuit sending data to my server without a problem. After i recieve data i need to send command to circuit. In LAN its working like a charm. But out of lan circuit dont recieving my command somehow. Any idea how i can send to udp pocked to machine behind NAT ? my code is bellow , ty for any help.
private void ReceiveMessage()
{
while (true)
{
try
{
var remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
var content = _udpClient.Receive(ref remoteIpEndPoint);
if (content.Length > 0)
{
var message = Encoding.ASCII.GetString(content);
var smsg = message.Split('|');
var pin1 = int.Parse(smsg[13]);
var pin2 = int.Parse(smsg[14]);
var isChanged = CheckChanges(smsg[1]);
if (isChanged == 1)
{
**var recvpt = new IPEndPoint(remoteIpEndPoint.Address, remoteIpEndPoint.Port);
var client = new UdpClient();
var cmd1 = "CP1S" + _pin1Time + "F";
var cmd2 = "CP2S" + _pin2Time + "F";
var senddata1 = Encoding.UTF8.GetBytes(cmd1);
var senddata2 = Encoding.UTF8.GetBytes(cmd2);
client.Send(senddata1, senddata1.Length, recvpt);
client.Send(senddata2, senddata2.Length, recvpt);
client.Close();**
// UpdateChanges(smsg[1]);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToStrin<wbr ></wbr>g());
}
}
}
}
Computers that are behind a NAT router are not directly accessible from a remote network. There would need to be rules put in place on your firewall/router to route this traffic to the remote machine. For explicit directions see your WAN/LAN admin. If you don't have one you could try asking over on Server Fault with more information about your network.

Categories