List<byte> -> string -> List<byte>

Does anyone know if there is a way to conver a List<byte> into a string, and then convert that string back into a List<byte> later?

It doesn't look like List<byte> supports GetBytes. I was thinking about putting all the elements into a string that is comma delimited and then reading them back again. But I'm not sure of a fast way to read a comma delimited string. It seems like that operation would take too long.

I need to transmit a small list with a socket. I want to use a string to I don't have to deal with a lot of the advance socket programming of sending objects. The comma delimited solution will work but I'm just wondering if there is a better/faster way.

The list will not be very big at the maximum it will have 74 elements inside of it. None of the elements will be larger then 2 bytes so I figured if I converted 1-9 with a leading 0 then everything in that list would be 2 bytes and it would be a lot faster to read.

If I did it that way I may not even need a comma delimited string. I would just read a string in 2 bytes at a time, each read will be an element for the new List<byte> on the other machine. Maybe by using string.Substring().

But I always though that string operations like that were very slow. I need something that is going to be fast enough to keep up with my game.

Thanks. :D
[1418 byte] By [Kensino] at [2007-11-20 11:32:19]
# 1 Re: List<byte> -> string -> List<byte>
List<byte> lstBytes;
...
...

lstBytes.ToArray(); // will give you a byte array

The class below should help.. You can call the ToArray method of your list or you can modify the class below to accept a List<byte>.

public class BinUtil
{
private static readonly string[] HexDigits =
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
};

/// <summary>
/// Determines if specified string is a hexadecimal string.
/// </summary>
/// <param name="hexString">string to check</param>
/// <returns>Boolean indicating whether or not the specified string is a hexadecimal string</returns>
/// <remarks>"00FF0A12" is an example of a hexadecimal string</remarks>
public static bool IsHexString(string hexString)
{
if (hexString == null || ((hexString.Length % 2) != 0))
{
return false;
}

foreach (char c in hexString)
{
if (!Uri.IsHexDigit(c))
{
return false;
}
}

return true;
}

/// <summary>
/// Converts a byte array to a hexadecimal string representation.
/// </summary>
/// <param name="bytes">Array to be converted</param>
/// <returns>Hexadecimal string</returns>
public static string ToHexString(byte[] bytes)
{
StringBuilder retVal = new StringBuilder(bytes.Length * 2);
for (int i = 0; i < bytes.Length; i++)
{
retVal.Append(HexDigits[bytes[i]]);
}

return retVal.ToString();
}

/// <summary>
/// Converts a byte array to a hexadecimal string representation with specified separator after every byte.
/// </summary>
/// <param name="bytes">Array to be converted</param>
/// <param name="separator">Separator to add after each byte</param>
/// <returns>Hexadecimal string</returns>
public static string ToHexString(byte[] bytes, string separator)
{
StringBuilder retVal = new StringBuilder((bytes.Length * 2) + (separator.Length * bytes.Length));
for (int i = 0; i < bytes.Length; i++)
{
retVal.Append(HexDigits[bytes[i]]);
retVal.Append(separator);
}

return retVal.ToString();
}

/// <summary>
/// Converts a section of a byte array to a hexadecimal string representation.
/// </summary>
/// <param name="bytes">Array to be converted</param>
/// <param name="offset">The location in bytes array from which to start converting data</param>
/// <param name="length">The number of bytes to convert</param>
/// <returns>Hexadecimal string</returns>
public static string ToHexString(byte[] bytes, int offset, int length)
{
StringBuilder retVal = new StringBuilder(length * 2);

for (int i = 0; i < length; i++)
{
retVal.Append(HexDigits[bytes[offset + i]]);
}

return retVal.ToString();
}

/// <summary>
/// Converts a section of a byte array to a hexadecimal string representation with specified separator after every byte.
/// </summary>
/// <param name="bytes">Array to be converted</param>
/// <param name="offset">The location in bytes array from which to start converting data</param>
/// <param name="length">The number of bytes to convert</param>
/// <param name="separator"></param>
/// <returns>Hexadecimal string</returns>
public static string ToHexString(byte[] bytes, int offset, int length, string separator)
{
StringBuilder retVal = new StringBuilder((bytes.Length * 2) + (separator.Length * bytes.Length));

for (int i = 0; i < length; i++)
{
retVal.Append(HexDigits[bytes[offset + i]]);
retVal.Append(separator);
}

return retVal.ToString();
}

/// <summary>
/// Convert a hexadecimal string to a byte array.
/// </summary>
/// <param name="hexString">Hexadecimal string to convert</param>
/// <returns>byte array</returns>
public static byte[] ToByteArray(string hexString)
{
byte[] retVal = new byte[0];

if (!IsHexString(hexString))
{
throw new ArgumentException("Error: Illegal hex string. " + hexString);
}

retVal = new byte[hexString.Length / 2];

for (int i = 0; i < retVal.Length; i++)
{
retVal[i] = Convert.ToByte(hexString.Substring(i*2, 2), 16);
}

return retVal;
}
}
tpcampb at 2007-11-9 11:36:49 >
# 2 Re: List<byte> -> string -> List<byte>
Or you can use Convert.ToBase64String (Byte[]) and the FromBase64String methods.

If it is binary data, Id just say leave it that way if you can handle it. You can just make the first 2 bytes sent the length of the send. Then whomever is receiving the data just reads the first two bytes to see how much is left to read and then reads the rest of the data. No padding or conversions needed.
DeepT at 2007-11-9 11:37:49 >
# 3 Re: List<byte> -> string -> List<byte>
BitConverter is *definately* the way to go as opposed to using the code above. However, sockets prefer byte[] when sending data, so why not just send the array itself?
Mutant_Fruit at 2007-11-9 11:38:49 >
# 4 Re: List<byte> -> string -> List<byte>
BitConverter is *definately* the way to go as opposed to using the code above. However, sockets prefer byte[] when sending data, so why not just send the array itself?
I don't know how to send the List<byte> array itself. I tried sending objects before and I posted a thread on this forum asking for help and no one seems to know how to do it correctly, so I gave up on seding arrays or other objects over the network.

No one on this forum knows how to do it. So I have to use strings instead.

http://www.dev-archive.com/forum/showthread.php?t=436127
Kensino at 2007-11-9 11:39:55 >
# 5 Re: List<byte> -> string -> List<byte>
Is the receiving app on the other side of the socket a .net or Java app?
Arjay at 2007-11-9 11:40:54 >
# 6 Re: List<byte> -> string -> List<byte>
Is the receiving app on the other side of the socket a .net or Java app?
It's a .Net windows service.

I have tried to modify my code again to send the size data along with the socket because it seems some Send methods are stepping on other Send methods and they are getting commands that are concat when they should be two seperate commands. I made some changes but now I just get error messages.

Server:

// TRANSMIT A MESSAGE TO ALL CONNECTED CLIENTS
public void TransmitToAllClients(string msgToTransmit, NetCommandType commandType) {

byte[] bteNetworkStringBytes = Encoding.ASCII.GetBytes(NetHelper.WriteNetworkString(commandType, msgToTransmit));

Socket workerSocket = null;
try {
for(int i = 0; i < m_workerSockets.Count; i++) {
workerSocket = (Socket)m_workerSockets[i];
if((workerSocket != null) && (workerSocket.Connected)) {

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent(string.Format("TRANSMIT TO ALL CLIENTS: {0}", NetHelper.WriteNetworkString(commandType, msgToTransmit)));
#endif

//// ==========================================================================
workerSocket.Send(bteNetworkStringBytes);
//// ==========================================================================
}
}
} catch(SocketException) {
// TODO: IMPLEMENTATION, IF WE ENCOUNTER AN EXCEPTION WE STILL NEED TO KEEP
// SENDING THE DATA TO ALL THE REMAINING SOCKETS.
}
}


Client

public void OnDataReceived(IAsyncResult asyn) {

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ENTERED ON_DATA_RECEIVED METHOD");
#endif

DataPacket dataPack = (DataPacket)asyn.AsyncState;

try {

// END THE SOCKET READ AND STORE THE NUMBER OF CHARACTERS READ

int charsRead = dataPack.Sock.EndReceive(asyn);

// CREATE AN ARRAY LARGE ENOUGH TO HOLD ALL THE DATA READ FROM THE SOCKET
char[] chars = new char[charsRead + 1];

// DECODE THE DATA, WRITE RESULTS INTO chars
Decoder deco = Encoding.ASCII.GetDecoder();
deco.GetChars(dataPack.DataBuffer, 0, charsRead, chars, 0);

// GET THE NETWORK STRING THAT WAS SENT OVER THE WIRE
string recString = new string(chars);

// DISINTEGRATE THE NETWORK STRING
NetCommandType cmdType;
string cmdData; // TODO :: I THINK THE OUT PARAMS ARE STEPPING ON THE TOES OF OTHER THREADS/BEING OVER WRITEN BY OTHER THREADS

#if PRNT_DBG_MSGS

BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ATTEMPTING TO READ NETWORK STRING");
BetaLogger.Logger.LogEvent(string.Format("COPY OF DATA RECEIVED: {0}", recString));
#endif

// IF WE HAVE RECEIVED A VALID NETWORK STRING, FIRE IT.
if(NetHelper.ReadNetworkString(recString, out cmdType, out cmdData)) {

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: NETWORK STRING HAS BEEN READ - ATTEMPTING EXECUTION");
#endif

ExecuteNetworkCommand(cmdType, cmdData);

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ATTEMPTED EXECUTION OF NETWORK STRING HAS BEEN PASSED");
#endif
}

// WAIT FOR MORE DATA ON THE SOCKET
WaitForData();

} catch(ObjectDisposedException) {
// TODO: SERVER CLOSED CONNECTED ??
} catch(SocketException) {
// TODO: IMPLEMENTATION
}
}


I changed the red lines with the following but I just get errors. According to MSDN this is what that param is for.

Server

workerSocket.Send(bteNetworkStringBytes, bteNetworkStringBytes.Length, SocketFlags.None);


Client

dataPack.Sock.EndReceive(asyn);
int charsRead = dataPack.Sock.Receive(dataPack.DataBuffer, dataPack.Sock.Available, SocketFlags.None);


Guess I don't have something right again.
Kensino at 2007-11-9 11:41:54 >
# 7 Re: List<byte> -> string -> List<byte>
This is actually two different commands to my client, but for some reason they randomly get concat, it doesn't happen very often, but it shouldn't happen at all.

000401000507 (this should really be two commands)

command 1: 000401 (which means they are connected to the server, and their client id = 1)

command 2: 000507 (which means load message 07 from the resource file and display it)

The first 4 bytes are always the command, and the rest is the command data. They are both converted to enums. Its a lot better then sending the actual data or a very long string.

They are not concat when the leave the server, only when they arrive at the client, my BetaLogger will prove that. Do you think this is caused from the OUT params I am using in the OnDataReceived method? Are these not thread safe?

--
edited
--

I have confirm that this appears to be because the messages are being sent to the client too fast. This has to be what is happening. I have been testing for hours, and I cannot see any other reason for this to happen.

So I thought about making a queue system to only send 1 message per second to each client but that will not work. I would need to do the same on the server side because the server will have an extrem amount of client connections. I can't really to this queue in reverse.

It looks like my best option is to stick with the size option. I need to send the size with the string, I can send it as the first four bytes, this is not a problem for me. But I cannot figure out how to get it on the other side. I need to get the size from the first 4 bytes of the string, read that command and then all remaining bytes are pushed the next command.

Its possible I know, but I cannot figure out how to do it, because on my OnReceived method it reads the data in, and doesn't really allow me a place to grab size data before reading anything. I can't get the size data until I've read the string.

My string could be like this

001200010009

first 4: 12 bytes to read, 2nd 4: command, 3rd 4: command data

My string may not always be that simple however, command data may not always be 4 bytes, the rest will always be four bytes. I will never need to send a string larger then 9999 bytes. I will never even get close to that. All my strings are actually stored in the client, I just send the ID of the string that the client needs to load.

I will look into it in the mean time. If I can get every single message to be the exact same size coming over the network kind of like a HASH, then I will always know how many bytes to read. Problem is I cannot reverse a hash so I have no way to know what the original message was. I think I can try to get something working,

problem is sending that array byte bytes, I still have no idea how to do that, and I cannot gurantee how many bytes will be in that array. That will toss my fixed command length right out the door.

--

Well this is all I can come up with, bitConverter does not with with a List<byte> for some stupid reason. This works but it is very slow. I cannot use it.


byte[] bteList = new byte[100];

for(byte i = 0; i < 100; i++) {

bteList[i] = i;

}

for(byte i = 0; i < bteList.Length; i++) {

listBox1.Items.Add(bteList[i]);

}

string bytes = Convert.ToBase64String(bteList);

textBox1.Text = bytes;

byte[] bteList2 = Convert.FromBase64String(bytes);

for(byte i = 0; i < bteList2.Length; i++) {

listBox2.Items.Add(bteList2[i]);

}
Kensino at 2007-11-9 11:42:59 >
# 8 Re: List<byte> -> string -> List<byte>
Since it's a web service, why not connect to it using the class generated when adding a web service reference? It'll handle the serialization/deserialization for you.
Arjay at 2007-11-9 11:43:53 >
# 9 Re: List<byte> -> string -> List<byte>
i dont know what your talking about. what is a web service? i am building a windows game.

regardless it seems impossible. even when i send a fixed string of 8 bytes its impossible to work correctly because they are async methods and it seems one thread always steps on another thread and this causing the issue. There is nothing I can do to prevent a thread from walking on another thread.

I thought there was a LOCK command or something...?? I don't know but I'm tired and I'm going to bed. Do you know of a lock command? Does that prevent a thread from using a method until its unlocked, and then that thread can use it? kind of like queuing the threads?

thanks
Kensino at 2007-11-9 11:45:02 >
# 10 Re: List<byte> -> string -> List<byte>
BitConverter works on byte[]. This is typically what a socket will give you as it's received data. If not, just call myList.ToArray(), which will give you a byte[] and then use bitconverter on that.

As for the messages appearing on each other, what you need to do is have a way of knowing the length of the data you are supposed to receive. The typical way to do this is to first send an int which represents the amount of data you're about to send, then send the data.

On the receiving side you read out 4 bytes, convert it to an int (bitconverter can do this for you), then you read that many bytes from your socket/network stream. Then read 4 bytes again etc etc.

Finally, you need to be careful that you send your messages sequentially. Its up to you to make sure that one of your threads in your client doesn't send a message while a second thread is in the middle of sending one. Either a) read previous posts in the forum or b) google thread safety and the 'lock' statement or 3) Read tutorials on the web which show you how to do this kind of basic problem
Mutant_Fruit at 2007-11-9 11:45:53 >
# 11 Re: List<byte> -> string -> List<byte>
Thanks Mutant_Fruit. I am not going to give up even as I've been stuck on this for a week. I know it has to be possible. I think you are right. I think I know what happening now because I have a few methods in my server one that sends to all clients and one that sends to a single client. It appears that these are stepping on each other. If I can move them into one single method, then control it with the lock statement I think it will be less likely for them to do that, then I will try to send the size before my transmission.

I am going to get this working no matter how long it takes. I'll be working on it today. I'll post back when I find a solution, or if I run into any more problems. I think I kinda understand what is going on now.

Thanks.
Kensino at 2007-11-9 11:47:02 >
# 12 Re: List<byte> -> string -> List<byte>
Its not working. I modified my code to receive a string with the first 4 bytes are size data.

public void WaitForData() {
try {

DataPacket dataPack = new DataPacket();
dataPack.Sock = m_ClientSocket;

int charsRead = m_ClientSocket.Receive(dataPack.DataBuffer, 4, SocketFlags.None);
char[] chars = new char[charsRead + 1];
Decoder deco = Encoding.ASCII.GetDecoder();
deco.GetChars(dataPack.DataBuffer, 0, charsRead, chars, 0);
string sizeBytes = new string(chars);
int sizeOfNetworkString;

if(int.TryParse(sizeBytes, out sizeOfNetworkString)) {
if(m_SocketCallback == null)
m_SocketCallback = new AsyncCallback(OnDataReceived);

m_asyncResult = m_ClientSocket.BeginReceive(dataPack.DataBuffer, (charsRead + 1) , sizeOfNetworkString, SocketFlags.None, m_SocketCallback, dataPack);
}

} catch(SocketException) {
// TODO: IMPLEMENTATION
}
}

Now I get an error as soon as I enter the OnDataReceived method

The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult

Cannot someone just please show me how to do it, so I understand and I can move on. I have been trying for a long time. I posted my original thread almost a week ago. I don't see why its so hard to do.

I'm begnining to think .Net's network support is not very good.
Kensino at 2007-11-9 11:48:01 >
# 13 Re: List<byte> -> string -> List<byte>
i dont know what your talking about. what is a web service? i am building a windows game.

regardless it seems impossible. even when i send a fixed string of 8 bytes its impossible to work correctly because they are async methods and it seems one thread always steps on another thread and this causing the issue. There is nothing I can do to prevent a thread from walking on another thread.

I thought there was a LOCK command or something...?? I don't know but I'm tired and I'm going to bed. Do you know of a lock command? Does that prevent a thread from using a method until its unlocked, and then that thread can use it? kind of like queuing the threads?

thanksSorry, I misread '.net windows service' as '.net web service'.
There are lock commands in .net. If you need multiple readers, check out the ReaderWriterLock class. If you would like a RAII approach to locking, check out the IDisposable and Using block (http://www.dev-archive.com/forum/showthread.php?t=436753) thread.
Arjay at 2007-11-9 11:48:57 >
# 14 Re: List<byte> -> string -> List<byte>
Well I'll try it again. Seems like this is taking forever and I'm not getting anywhere. I cannot understand why there are no good articles/tutorials on this. I tell you once I get this working I will be doing a in depth article on the subject for my website. All the help I have found on the Internet on this topic has been pretty much useless. I found a lot of articles but not many show a complete example, and none of them show you how to send objects or show you how to send size bytes. It sounds simple but its not.
Kensino at 2007-11-9 11:50:04 >
# 15 Re: List<byte> -> string -> List<byte>
You can't send 'objects' via a socket. You can only send 'bytes'. If you want to send information via a socket, it has to be convertible to an array of bytes (through whatever means you want to use) and then convertible from an array of bytes back into the original object,

There are dozens of tutorial documents on how to build a simple webserver that sends text to and from client's connected to the server. Some of them should be helpful. Google for 'c# socket tutorial'.
Mutant_Fruit at 2007-11-9 11:51:08 >
# 16 Re: List<byte> -> string -> List<byte>
Mutant, I don't have much experience using sockets, but I assume you could send 'serializable' objects (i.e., serialize/deserialize the objects using the XmlSerializer class), couldn't you?
Arjay at 2007-11-9 11:52:02 >
# 17 Re: List<byte> -> string -> List<byte>
I've been using google for a week there are not any good examples. I have tried hundreds of code changes and nothing works. Not one of them show you how to send the size of an object, and then read it on the other side. I don't think that's the correct solution. I tried that several times and it still combines many commands into one.

I don't really think its possible. I have tried to serialize objects, that doesn't do any good because the objects still run on top of each other and they are corrupt on the other side. It is impossible to tell where one object stops and another one stops, sending the size before it does not help.
Kensino at 2007-11-9 11:53:10 >
# 18 Re: List<byte> -> string -> List<byte>
Search: 'c# socket tutorial'

First result is absolute garbage http://www.developerfusion.co.uk/show/3918/2/, it doesn't even work in its provided state.

Other result: http://www.dev-archive.com/csharp/csharp/cs_misc/sampleprograms/article.php/c7695/, I stated in my previous thread I am already using that article. Its the one causing me so many problems, and the author refuses to provide assistance (most likely because he knows it doesn't work correctly)

The other results are for Java and WinSock, and not one of them show me how to send size before I send an object. You won't find an article that does what I need because there are none. I've been searching for a week. I would have found it by now. Not even MSDN shows you how to do it.

I don't need a beginner socket example. I have all the sockets working. Everything works fine except the commands overlap from time to time, so I need something that shows me how to know when one command stops and one starts. I have also tried using the Socket.NoDelay() which is SUPPOSED to help but it doesnt have any effect. I thought sockets in .Net were suppsoed to be very powerfull... :rolleyes:
Kensino at 2007-11-9 11:54:04 >
# 19 Re: List<byte> -> string -> List<byte>
OK, here's a really simple example.

Client and server are sending/receiving strings.

Client has a string 'ClientString'.
Client wants to send this to the server through a socket.
Client first sends the length of the string: socket.Send(ClientString.Length);
Client then sends the string: socket.Send(System.Text.Encoding.UTF8.GetBytes(ClientString));

Client then sends a second string, ClientString2 in the same manner.

Server reads one int from the socket: int length = socket.ReadInt();
server now knows how much data it needs to read to retrieve.
Server reads 'length' bytes from the socket: byte[] data = socket.Read(length);
Server converts back to string from: string ClientString = System.Text.Encoding.UTF8.GetString(data);

Server now reads one int again: int length = Socket.ReadInt();
Server now knows the length of the second string.
Server reads the second string: byte[] data = socket.Read(length);
Server converts back to string form: string ClientString2 = System.Text.Encoding.UTF8.GetString(data);

You have now successfully received two string which were sent at the same time without screwing it up.

Note: You can't just send an 'int' through a socket. Sockets need a byte[], so you can use BitConverter.GetBytes(myInt) to convert the int to a byte[]. Alternatively, you could wrap your socket in a NetworkStream, which makes it much easier to use.

The patten works, it is the solution. Just because you can't make the solution work doesn't mean it's not the right solution.
Mutant_Fruit at 2007-11-9 11:55:03 >
# 20 Re: List<byte> -> string -> List<byte>
There is no ReadInt() method for the socket. I've tried this, I've already done it with the size but it doesn't work.

Sending to client with size

public void TransmitToSingleClient(NetCommandType commandType, string msgToTransmit, int clientNo) {

try {
Socket workerSocket = null;

// TODO: I NEED TO TRACK IF ALL THE BYTES WERE SENT TO THE CLIENT. I WILL DO THIS LATER ONCE EVERYTHING IS WORKING.
int bytesSent = 0;

byte[] bteNetworkStringBytes = Encoding.ASCII.GetBytes(NetHelper.WriteNetworkString(commandType, msgToTransmit));
byte[] bteNetworkStringSize = Encoding.ASCII.GetBytes(bteNetworkStringBytes.Length.ToString());

if(clientNo == NetHelper.TransmitToAllClients) {
for(int i = 0; i < m_workerSockets.Count; i++) {
workerSocket = (Socket)m_workerSockets[i];
workerSocket.NoDelay = true;
if((workerSocket != null) && (workerSocket.Connected)) {
bytesSent = workerSocket.Send(bteNetworkStringSize, bteNetworkStringSize.Length, SocketFlags.None);
bytesSent = workerSocket.Send(bteNetworkStringBytes, bteNetworkStringBytes.Length, SocketFlags.None);
}
}
} else {
workerSocket = (Socket)m_workerSockets[clientNo - 1];

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent(string.Format("TRANSMIT TO **SINGLE** CLIENT: {0}", NetHelper.WriteNetworkString(commandType,msgToTransmit)));
#endif

//// ==========================================================================
workerSocket.Send(bteNetworkStringSize);
workerSocket.Send(bteNetworkStringBytes);
//// ==========================================================================
}

} catch(SocketException) {

// TODO: IMPLEMENTATION
}
}

Receive on client

public void WaitForData() {

if(m_SocketCallback == null)
m_SocketCallback = new AsyncCallback(OnDataReceived);

try {

DataPacket dataPack = new DataPacket();
dataPack.Sock = m_ClientSocket;

if(nextTransmissionSize.HasValue) {
// READ IN ONLY THE NEXT TRANSMISSION, DO NOT ALLOW TRANSMISSIONS TO OVERLAP
m_asyncResult = m_ClientSocket.BeginReceive(dataPack.DataBuffer, 0, (int)nextTransmissionSize, SocketFlags.None, m_SocketCallback, dataPack);
} else {
// THIS TRANSMISSION SHOULD CONTAIN SIZE DATA FOR THE TRANSMISSION TO FOLLOW, WE ARE GOING TO READ THE ENTIRE TRANSMISSION
m_asyncResult = m_ClientSocket.BeginReceive(dataPack.DataBuffer, 0, dataPack.DataBuffer.Length, SocketFlags.None, m_SocketCallback, dataPack);
}

} catch(SocketException) {
// TODO: IMPLEMENTATION
}
}

private int? nextTransmissionSize = null; // STORES THE SIZE OF THE NEXT TRANSMISSION COMMING OVER THE WIRE.
public void OnDataReceived(IAsyncResult asyn) {

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ENTERED ON_DATA_RECEIVED METHOD");
#endif

DataPacket dataPack = (DataPacket)asyn.AsyncState;

try {

// END THE SOCKET READ AND STORE THE NUMBER OF CHARACTERS READ
int charsRead = dataPack.Sock.EndReceive(asyn);

// CREATE AN ARRAY LARGE ENOUGH TO HOLD ALL THE DATA READ FROM THE SOCKET
char[] chars = new char[charsRead + 1];

// DECODE THE DATA, WRITE RESULTS INTO chars
Decoder deco = Encoding.ASCII.GetDecoder();
deco.GetChars(dataPack.DataBuffer, 0, charsRead, chars, 0);

// GET THE NETWORK STRING THAT WAS SENT OVER THE WIRE
string recString = new string(chars);

// IS THIS A NETWORK COMMAND TRANSMISSION OR A SIZE TRANSMISSION?
if(!nextTransmissionSize.HasValue) {

#if PRNT_DBG_MSGS

BetaLogger.Logger.LogEvent("ENTERED !nextTransmissionSize NO VALUE");
BetaLogger.Logger.LogEvent(string.Format("COPY OF DATA RECEIVED: {0}", recString));
#endif

int iSize; // TEMPORARY STORAGE
if(!int.TryParse(recString, out iSize))
nextTransmissionSize = null; // IM NOT SURE WHAT THIS IS, THROUGH IT OUT...
else
nextTransmissionSize = (int?)iSize;
} else {

#if PRNT_DBG_MSGS

BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ATTEMPTING TO READ NETWORK STRING");
BetaLogger.Logger.LogEvent(string.Format("COPY OF DATA RECEIVED: {0}", recString));
#endif
// DISINTEGRATE THE NETWORK STRING
NetCommandType cmdType;
string cmdData;

// IF WE HAVE RECEIVED A VALID NETWORK STRING, FIRE IT.
if(NetHelper.ReadNetworkString(recString, out cmdType, out cmdData)) {

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: NETWORK STRING HAS BEEN READ - ATTEMPTING EXECUTION");
#endif

ExecuteNetworkCommand(cmdType, cmdData);

// TRANSMISSION EXECUTED, INVALIDATE SIZE DATA SO WE MAY RECEIVE ANOTHER TRANSMISSION
nextTransmissionSize = null;

#if PRNT_DBG_MSGS
BetaLogger.Logger.LogEvent("CLIENT PORT MANAGER: ATTEMPTED EXECUTION OF NETWORK STRING HAS BEEN PASSED");
#endif
}
}

// WAIT FOR MORE DATA ON THE SOCKET
WaitForData();

} catch(ObjectDisposedException) {
// TODO: SERVER CLOSED CONNECTED ??
} catch(SocketException) {
// TODO: IMPLEMENTATION
}
}

The messages still overlap, what did I do wrong??
Kensino at 2007-11-9 11:56:05 >
# 21 Re: List<byte> -> string -> List<byte>
The messages still overlap, what did I do wrong??Try moving to a console app and work with a single client based on Mutant's code until you get that working. Then move to multi-client.
Arjay at 2007-11-9 11:57:13 >
# 22 Re: List<byte> -> string -> List<byte>
I'm just going to rip out my hair.

I will try but the solution is not so simple because everyone is missing the fact I am working with Asynchronous Sockets. So when I send two seperate commands like that, one with size data and one with the real command they get mixed up between threads from time to time. If one thread send a size data and another thread sends a message, it uses the wrong size data to read the wrong message.

I cannot use Synchronous sockets because I need to have many clients connected at the same time and it would never work. That example makes it sound so simple, and it would be if I was using Synchronous Sockets.

I know what you are saying but there has to be some way to control it.
Kensino at 2007-11-9 11:58:12 >
# 23 Re: List<byte> -> string -> List<byte>
I'm just going to rip out my hair.

I will try but the solution is not so simple because everyone is missing the fact I am working with Asynchronous Sockets. So when I send two seperate commands like that, one with size data and one with the real command they get mixed up between threads from time to time. If one thread send a size data and another thread sends a message, it uses the wrong size data to read the wrong message.

I cannot use Synchronous sockets because I need to have many clients connected at the same time and it would never work. That example makes it sound so simple, and it would be if I was using Synchronous Sockets.

I know what you are saying but there has to be some way to control it.Can you send the size and the data as part of a single message? In other words prepend the size in the byte array you are sending (kind of like the way a BSTR does it). On the receiving end you would look at the first 4 bytes to determining the overall length.

[Edit] After rereading previous posts, looks like you may have already tried this.
Arjay at 2007-11-9 11:59:13 >
# 24 Re: List<byte> -> string -> List<byte>
See my code in post # 13.

I already tried that but I didn't know how to read the data in on the other side so I had to give up.
Kensino at 2007-11-9 12:00:13 >
# 25 Re: List<byte> -> string -> List<byte>
See my code in post # 13.

I already tried that but I didn't know how to read the data in on the other side so I had to give up.Since you are storing it in a string couldn't you just do a SubString on the first few characters and then convert to an int? Then read the rest of the data?
Arjay at 2007-11-9 12:01:18 >
# 26 Re: List<byte> -> string -> List<byte>
I've written a bittorrent engine in C# using async sockets. i've already done what you're doing on a far larger and more complex scale than what you're doing. My description of how things should work is correct. That's exactly how i work things in my bittorrent library.

Yes, there is no ReadInt(), but what you do is read 4 bytes and use BitConverter to turn those bytes into an int. BitConveter.ToInt32(btye[]) is the method, i believe. Alternatively, i believe NetworkStream has a .ReadInt() method, you could check that out.

What i'd highly advise is that you should get it working for 1 Server + 1 Client first. Be able to send multiple messages using synchronous sockets first. When that works, making it asynchronous is about 15-30 minutes extra work (tops). When that works, making multiple clients work shouldn't be too much harder, a few hours tops.]

EDIT:
If one thread send a size data and another thread sends a message, it uses the wrong size data to read the wrong message.
Cardinal sin number 1. Never allow multiple threads access to the same object at the same time if doing so is not explicitly said to be threadsafe. Of course, the question is why would one thread by sending the 4byte length and another be sending the message? You should only have one thread allowed send data for each connection. Note; That doesn't mean you need 1 thread per connection, it just means you dont have two threads servicing the one connection.
Mutant_Fruit at 2007-11-9 12:02:19 >
# 27 Re: List<byte> -> string -> List<byte>
AHHHHHHH :wave:

OK! Seems to be working finially. I figured out what I was doing wrong. I am not losing any messages now, even when I send a lot, and they are all complete. My server sends all messages from one method that is not threaded. The client still recieves Async messages but it doesn't matter because the server only sends them sync. But this still allows the client to send a message at the same time its receiving a message.

I do have a few questions though. Maybe why I was getting confused.

#1. How come when I get the bytes of an int32 no matter what the number is, the bytes length is always 4? I was trying to add this myself with ToString("0000") so that the int would be 4 bytes. I didn't know I didn't have to do that until I created a test program


private void button1_Click(object sender, EventArgs e) {
byte[] size = BitConverter.GetBytes(Convert.ToInt32(textBox1.Text));
listBox1.Items.Clear();
for(int i = 0; i < size.Length; i++) {
listBox1.Items.Add(size[i]);
}


#2. I'm still having a few problems sending the List<byte>. My program crashes when I try to send it, and I cannot debug a windows service for some reason, I only have express edition I think that's why.

I need to append the 4 byte network command to the front of the list, so I am trying to do that with Array.Copy. I'm not sure if I'm on the right track or not, but I can't figure out how to concat two byte[]'s. This is how I am writting the network bytes


// CONCATENATES A SPECIAL COMMAND FOR A CLIENT, THIS IS NOT REALLY A STRING.
public static byte[] WriteNetworkString(NetCommandType cmdType, byte[] cmdData) {
byte[] cmdTypeBytes = Encoding.ASCII.GetBytes(((int)cmdType).ToString("0000"));
byte[] networkBytes = new byte[cmdTypeBytes.Length + cmdData.Length];
Array.Copy(cmdTypeBytes, 0, networkBytes, 0, cmdTypeBytes.Length);
Array.Copy(cmdData, 0, networkBytes, (cmdTypeBytes.Length + 1), cmdData.Length);
return networkBytes;
}


Then I have a reader that will take it apart again. I try to keep all this stuff seperate from the network code so its in a helper class for my games network methods.

#3. I have solved this in one direction, now in the other direction I will have a problem because I cannot control when clients will send data, and a lot of clients may send data at one time. So to prevent this issue on commands stepping on each other. I plan to use the exact same method, only I was thinking I could store the data in a Hashtable. With the client ID as the key and the int size as the data.

This way I will make sure that one client's size data does not get used to read another clients transmission. I use a single private int on the client side, but that's not going to be good enough for a server, because I'm sure other clients will overwrite that size data before the client has a chance to send its data, and the server will read in a lot of threads. I noticed that I can make a hashtable thread syncronized by setting its property, so it should work out good.

Am I on the right track now for the server?

Clients are working, and updating automatically by the windows service which controls the game :) http://kensino.com/images/Untitled.jpg. These are just test boxes, the real UI isn't 100% complete yet. These help me test the code without bringing in exisiting errors from the UI's code. If these fail I know its a problem with the network code.

Also I have been trying to follow all the rules for OOP. I have been making all my variables camel case, my private fields prefexed with a m_, all consts are in upper case and I never use numbers in my code. I always assign a name to the number by making it a const, so it makes my code more readable. I'm think I am getting the hang of this. I hate bingo but this program is an excellent learning expierence. It uses a lot of different types of programming, and once its working I'll need to use MS SQL to store user stats, and accounts.
http://kensino.com/images/Untitled2.jpg

I even found a cool way to have an enum push my game along by a threading timer.


using System;
namespace BingoEngine {
// THE SPEED AT WHICH THE GAME WILL BE PUSHED, IN SECONDS.
public enum GameSpeed {
// THIS SETS THE AMOUNT OF TIME BETWEEN NUMBER CALLS
Fast = 4000, // FOUR SECONDS
Normal = 8000, // EIGHT SECONDS
Slow = 10000, // TEN SECONDS
VerySlow = 15000, // FIFTEEN SECONDS
BetaMode = 1500 // DO NOT USE THIS MODE
}
}


So does it seem like I'm getting a hang of using C#? There is a lot I don't know but my code is getting better and better, and more concise. I do a lot of things now with one statement that I use to do in several. My code seems to be getting a lot more advanced as well.
Kensino at 2007-11-9 12:03:15 >