I am trying to rewrite some of my code from a C++ program I wrote a while ago, but I am not sure if/how I can write to a byte array properly, or if I should be using something else. The code I am trying to change to C# .NET is below.
unsigned char pData[1400];
bf_write g_ReplyInfo("SVC_ReplyInfo", &pData, 1400);
void PlayerManager::BuildReplyInfo()
{
// Delete the old packet
g_ReplyInfo.Reset();
g_ReplyInfo.WriteLong(-1);
g_ReplyInfo.WriteByte(73);
g_ReplyInfo.WriteByte(g_ProtocolVersion.GetInt());
g_ReplyInfo.WriteString(iserver->GetName());
g_ReplyInfo.WriteString(iserver->GetMapName());
}
BinaryWriter might work, although strings are written with a preceding 7-bit encoded length, which I suspect the client won't be able to handle. You'll probably have to convert strings to bytes and then either add a length word or 0-terminate it.
No need to manually convert numbers to bytes. If you have a long that you want to write as a byte, just cast it. That is, if your BinaryWriter is bw, then you can write bw.Write((byte)longval);. To write -1 as a long: bw.Write((long)(-1)).
Related
Alright, so I basically want to read any file with a specific extension. Going through all the bytes and reading the file is basically easy, but what about getting the type of the next byte? For example:
while ((int)reader.BaseStream.Position != RecordSize * RecordsCount)
{
// How do I check what type is the next byte gonna be?
// Example:
// In every file, the first byte is always a uint:
uint id = reader.GetUInt32();
// However, now I need to check for the next byte's type:
// How do I check the next byte's type?
}
Bytes don't have a type. When data in some language type, such as a char or string or Long is converted to bytes and written to a file, there is no strict way to tell what the type was : all bytes look alike, a number from 0-255.
In order to know, and to convert back from bytes to structured language types, you need to know the format that the file was written in.
For example, you might know that the file was written as an ascii text file, and hence every byte represents one ascii character.
Or you might know that your file was written with the format {uint}{50 byte string}{linefeed}, where the first 2 bytes represent a uint, the next 50 a string, followed by a linefeed.
Because all bytes look the same, if you don't know the file format you can't read the file in a semantically correct way. For example, I might send you a file I created by writing out some ascii text, but I might tell you that the file is full of 2-byte uints. You would write a program to read those bytes as 2-byte uints and it would work : any 2 bytes can be interpreted as a uint. I could tell someone else that the same file was composed of 4-byte longs, and they could read it as 4-byte longs : any 4 bytes can be interpreted as a long. I could tell someone else the file was a 2 byte uint followed by 6 ascii characters. And so on.
Many types of files will have a defined format : for example, a Windows executable, or a Linux ELF binary.
You might be able to guess the types of the bytes in the file if you know something about the reason the file exists. But somehow you have to know, and then you interpret those bytes according to the file format description.
You might think "I'll write the bytes with a token describing them, so the reading program can know what each byte means". For example, a byte with a '1' might mean the next 2 bytes represent a uint, a byte with a '2' might mean the following byte tells the length of a string, and the bytes after that are the string, and so on. Sure, you can do that. But (a) the reading program still needs to understand that convention, so everything I said above is true (it's turtles all the way down), (b) that approach uses a lot of space to describe the file, and (c) The reading program needs to know how to interpret a dynamically described file, which is only useful in certain circumstances and probably means there is a meta-meta format describing what the embedded meta-format means.
Long story short, all bytes look the same, and a reading program has to be told what those bytes represent before it can use them meaningfully.
I want to use serialport.readline() because it's a blocking call and the data I'm getting has 0x0D 0x0A (CR LF) at the end. However, what I want is an Hex String instead of an Ascii representation.
For example, the device I am communication with is sending byte arrays like {0xff,0xff,0x45,0x0D,0x0A}. I want to simply print out in my program just like this: 0xff, 0xff,0x45. Readline() kindly trims out LF and CR.
I though about using serialport.read(buff[]...) by specifying how many bytes I want to read. But it didn't work very well because if I am reading too fast half of the array will be 0x00 and if I am reading too slow, there will be an overflow for the com port. I don't want to lose any bytes.
I tried to convert what I got from serialport.readline() to a byte array but the hex string I got usually turns into 0x3f. Code is like this:
var line = string.Join(",", mySerialPort.ReadLine().Select(c => ((Byte)c).ToString("X")).ToArray());
I changed the encoding a few times (ASCII, UTF8,UNICODE) but still no go.
Is there any way to convert the non-Ascii String I got from readline() into a byte array?
It sounds like you shouldn't be reading it as text data at all.
You're fundamentally dealing with binary data, so use the overload of Read which takes a byte array rather than a char array. (Or call ReadByte repeatedly.)
Any time you try to treat arbitrary binary data as if it's text, you're going to have a bad experience.
It sounds like you've already tried this, but done it badly:
But it didn't work very well because if I am reading too fast half of the array will be 0x00
That suggests you're ignoring the return value of Read, which says how many bytes have actually been read. You should have something like:
int bytesRead = port.Read(buffer, 0, buffer.Length);
// Now use the portion of buffer which is from 0 (inclusive) to
// bytesRead (exclusive).
I have recently started learning C# Networking and I was wondering how would you tell if the received Byte array is a file or a string?
A byte array is just a byte array. It's just got data in.
How you interpret that data is up to you. What's the difference between a text file and a string, for example?
Fundamentally, if your application needs to know how to interpret the data, you've got to put that into the protocol.
A byte array is just a byte array. However, you could make the original byte array include a byte that describes what type it is (assuming you are the originator of it). Then you find this descriptor byte and use it to make decisions.
Strings are encoded byte arrays; files can contain strings and/or binary data.
ASCII strings use byte values between 0-127 to represent characters and control codes. For UTF8 people have written validation routines (https://stackoverflow.com/a/892443/884862).
You'd have to check the array for all of the string encoding characteristics before you could assume it's a binary file.
edit Here's an SO question about classifying a file type Using .NET, how can you find the mime type of a file based on the file signature not the extension using a signature (first X bytes) of the file to determine it's mimetype.
No you can't. Data is data, you must layer on top of your network communication form of protocol, it will need to say something like: "If the first byte I see is a 1 the next four bytes represent a int, if I see a 2 read the next byte and that is the length of the text string that follows that..."
A much easier solution than inventing your own protocol is use a prebuilt one that gives you a higher level abstraction like WCF so you don't need to deal with byte arrays.
Not quite a "file", an array contains data. You should loop through that array and write the data,
Try this:
foreach(string data in array)
{
Console.WriteLine(data);
}
Now, if it doesn't contain strings, but data, you can simply use a
foreach(var data in array)
{
Console.WriteLine(data.ToString());
}
I have the following code in C#:
Console.WriteLine("Connecting to server...");
TcpClient client = new TcpClient("127.0.0.1", 25565);
client.Client.Send(BitConverter.GetBytes(0x02));
client.Client.Send(BitConverter.GetBytes(0x0005));
client.Client.Send(Encoding.UTF8.GetBytes("wedtm"));
Console.Write("{0:x2}", client.GetStream().ReadByte());
For the life of me, I can't figure out how to transpose this to ruby. Any help here?
This is what I have so far, but it's not working as expected:
require 'socket'
s = TCPSocket.open("127.0.0.1", 25565)
s.write(0x02)
s.write(0x0005)
s.write("wedtm".bytes)
response = s.recvfrom(2)
puts "Response Size #{response.size}: #{response.to_s}"
The response should be 0x02
EDIT:
I'm assuming I have to use String#unpack on this, however, I can't figure out how to get "wedtm" to output to the appropriate \x000\x000\x000\x000 format.
There are at least two things to consider here:
Network byte order is big-endian. This means that you should always think in single bytes or arrays of bytes, as bytes are not subject to being shuffled around while larger types are.
C#'s BitConverter.GetBytes(int16) returns 2 bytes in little-endian format and GetBytes(int32) returns 4 bytes in little-endian format
Without knowing any Ruby or its string format, I'd guess you need to do something like this for the first part:
s.write("\x02\x00".bytes)
s.write("\x05\x00\x00\x00".bytes)
The second part should be okay.
WireShark is an invaluable tool when debugging network code and/or reverse engineering networking protocols, record the traffic of the C# app and compare the difference with yours.
I'm doing a number of bitwise operations on an array of bytes in C#. I'm obtaining the array by calling FileStream.Read. I just realized that I'm not sure what would happen if a file had a bad byte or corrupt byte in it somewhere. For example, maybe a nibble is chopped off of the end or something like that. What would the FileStream do with it? Would the messed up byte by 'rounded' off by the Read method? Would an exception be thrown? Or is this something that will virtually never happen?
Thanks,
brian
If your FileStream.Read call succeeds, there's no such thing as a file having a bad byte or corrupt byte. Each byte that is successfully read, and part of the file, is a value from 0 to 255. How it is interpreted by a program is what matters.
If FileStream.Read returns for example 5 bytes, then you can rely that those 5 bytes are read successfully from the file and all bits of the bytes were put into your buffer successfully.
There is such thing though for example as a bad cluster on your hard disk, in which case your Read would fail with some kind of exception.
For completeness I should also mention that every file type has a file format. I.e. how you should interpret the binary data. It is possible that a byte or several bytes don't follow the file format. And in that way you can view a byte as being corrupt or invalid, but it's not really corrupt or invalid just wrong in terms of what the file format specifies.