UDP client's packet categorization - c#

I've created my own UDP server/client to see how client->server comunication works and i was wondering if i can make the server to read a specific value... For example, i have a login form that sends ID & password to the UDP server. How can i make the UDP server to recognize the packet that contains the id/password ? A friend told me that you can set a "packet header" in C/C++ but not in C#.
Some code examples or ideas would be greate!
My UDP server's code:
Configuration _conf = Configuration.Load("realmConfig.lua");
int realmPort = _conf["AUTH"]["authPort"].GetValue<int>();
string data = "";
UdpClient __AUTH__ = new UdpClient(realmPort);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
Console.WriteLine(" S E R V E R IS S T A R T E D ");
Console.WriteLine("* Waiting for Client...");
while (data != "q")
{
byte[] receivedBytes = __AUTH__.Receive(ref remoteIPEndPoint);
data = Encoding.ASCII.GetString(receivedBytes);
Console.WriteLine("Handling client at " + remoteIPEndPoint + " - ");
Console.WriteLine("Message Received " + data.TrimEnd());
__AUTH__.Send(receivedBytes, receivedBytes.Length,remoteIPEndPoint);
Console.WriteLine("Message Echoed to" + remoteIPEndPoint + data);
}
Client:
string data = "";
byte[] sendBytes = new Byte[1024];
byte[] rcvPacket = new Byte[1024];
UdpClient client = new UdpClient();
IPAddress address = IPAddress.Parse(IPAddress.Broadcast.ToString());
client.Connect(address, 15000);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
Console.WriteLine("Client is Started");
Console.WriteLine("Type your message");
while (data != "q")
{
data = Console.ReadLine();
sendBytes = Encoding.ASCII.GetBytes(DateTime.Now.ToString() + " " + data);
client.Send(sendBytes, sendBytes.GetLength(0));
rcvPacket = client.Receive(ref remoteIPEndPoint);
string rcvData = Encoding.ASCII.GetString(rcvPacket);
Console.WriteLine("Handling client at " + remoteIPEndPoint + " - ");
Console.WriteLine("Message Received: " + rcvPacket.ToString());
}
Console.WriteLine("Close Port Command Sent"); //user feedback
Console.ReadLine();
client.Close(); //close connection

The UDP/IP packet headers are used for network and transport purposes. All of your application information should be in the UDP payload. You can put any bytes you want there, using any structure you want. Think of the payload as a very small file which you are passing from one application to another and structure it the same way you would a file. For example, the first byte might be a number indicating the type of data in the rest of the payload. In this way, you create your own application-level header.
Just as with a file, you need to remember that word alignment, byte packing, and endian may not be same on different machines. You are sending a sequence of raw bytes, and need to pay attention to how higher level structures will be converted and interpreted.
In addition, individual UDP datagrams are very limited in size. On most networks you will have problems with payloads much bigger than about 1400 bytes, and it is safest to keep payloads below about 512 bytes.
As always with UDP, remember that you are responsible for all flow control and error recovery. If a packet is lost for any reason, you will receive no notification: it simply fails to arrive. If you send packets too quickly, they will be lost. If you do not intend to implement your own specialized flow control and error recovery, consider using TCP instead.

Related

Connecting to Serial->Ethernet converter box via Telnet, getting strange response (no matter what I send)

I'm trying to communicate with a device that has a Serial COM port that goes out (using RS232 Protocol), which I've hooked up to a converter box that converts the connection to Ethernet.
I've successfully connected to the converter box (which has its own IP) and I've successfully communicated with the device by sending it commands over telnet by using PuTTY, to which it has responded with various data that I've been able to parse.
I've established a connection by creating a new TcpClient, and I'm able to send strings to the device, but every time I get a response back, it's always "??\u0003" which I've researched and found that \uhhhh is a Unicode escape protocol. This confuses me because I have used ASCII encoding for everything.
public string TcpConnect(string cmd)
{
var client = new TcpClient();
//cmd = "ping";
Console.WriteLine("Connecting to server");
client.Connect("169.254.20.40", 23); //22 = ssh, 23 = telnet, 80 = http
Console.WriteLine("CONNECTED SUCCESSFULLY");
Stream tcpStream = client.GetStream();
ASCIIEncoding A = new ASCIIEncoding();
byte[] enable = A.GetBytes("enable" + Environment.NewLine);
byte[] connect = A.GetBytes("connect line 1" + Environment.NewLine);
byte[] ba = A.GetBytes(cmd);
Console.WriteLine("Transmitting.....");
tcpStream.Write(enable, 0, enable.Length);
tcpStream.Write(connect, 0, connect.Length);
tcpStream.Write(ba, 0, ba.Length);
byte[] responseBytes = new byte[4096];
int numBytesRead = tcpStream.Read(responseBytes, 0, responseBytes.Length);
var message = A.GetString(responseBytes, 0, numBytesRead);
Console.WriteLine("\nServer Closed.");
return message;
}
If I were to pass in "$TEAA4B9\r\n" as the message, I would expect something along the lines of "$TEA,086,040,031,000,3798" which is nowhere close to what I'm getting (which is ??\u0003)
Nevermind figured it out
Just kidding! Here's what I did: I added a "System.Threading.Thread.Sleep("1000") before the "tcpStream.Read" line at the bottom, and now it outputs the data I need. The device was outputting garbage on the first line (perhaps a handshake, not sure) and that's all that was being read before it was being stored into "message" and returned (not enough time was spent reading before it moved on to the next line of code)

Minecraft Server Ping with C# [duplicate]

So found this little code snippet that would allow you to ping a Minecraft server in PHP, but now i want to do this in C#.
I tried doing this on my own but for some reason its just not working
UdpClient client = new UdpClient();
IPEndPoint ep;
try
{
ep = new IPEndPoint(IPAddress.Parse("-snip-"), -snip-);
client.Connect(ep);
}
catch { Console.WriteLine("Error"); Console.ReadLine(); return; }
byte[] bytes = new byte[1];
bytes[0] = (byte)0xFE;
client.Send(bytes, bytes.Length);
IPEndPoint rep = new IPEndPoint(IPAddress.Any, 0);
byte[] recv = client.Receive(ref rep);
Console.WriteLine(ASCIIEncoding.ASCII.GetString(recv));
Console.ReadLine();
The server seems to just completely ignore the packet. This is the code snippet i found:
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fp) return false;
//Send 0xFE: Server list ping
fwrite($fp, "\xFE");
//Read as much data as we can (max packet size: 241 bytes)
$d = fread($fp, 256);
//Check we've got a 0xFF Disconnect
if ($d[0] != "\xFF") return false;
Could anyone please point out what mistake i'm making? Thank you!
As described here
The client initiates a TCP connection to the minecraft server on the
standard port. Instead of doing auth and logging in (as detailed in
Protocol Encryption), it sends the two byte sequence FE 01. This is a
0xFE server list ping packet. If the second byte (the 0x01) is
missing, the server waits about 1000ms then replies with the Server ->
Client format used in 1.3 and earlier.
you need to send a TCP request whereas you're sending an UDP packet...

How to Specify what Data should be stored in a variable with Client & Server in C#?

So, I am working on a Game that uses a Server. I am trying to add a username & password system, but have run into a issue. When I send the Data from the client to the server, the Server receives it, but I can't think of a system to specify what the data is and where is should be stored.
For example, say I send the Username from my Client to the Server. The Server receives it, but how can I let it know that it's a username, not a password?
If anyone can help, thank you.
Note: If it helps, I am using C# in Visual Studio.
Server Code
int recv; // Holds how much data we are reading
byte[] data = new byte[1024]; // Byte Array of data, used for everything recived and sent to the server
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 904); // Listener for connections
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Stores connection from client
socket.Bind(endpoint); // Bind incoming connection to socket
Console.WriteLine(" >> Waiting for client...");
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 904); // Wait for connection, once recived, sets sender to connected IP
EndPoint tmpRemote = (EndPoint)sender; // Stores client temp
recv = socket.ReceiveFrom(data, ref tmpRemote); // Stores all client info, get data it's sending (And how much data is in it)
Console.WriteLine(" >> Data received from {0}", tmpRemote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); // Convert data into string and display it
string welcome = " >> Welcome to AlphaNET!"; // Welcome Message
data = Encoding.ASCII.GetBytes(welcome); // Convert Welcome to sendable bytes
if (socket.Connected) //Checking if socket is still connected, if so, send welcome message
{
socket.Send(data); // Send welcome message
}
while (true) // Our loop to check for data, goes on forever
{
if (!socket.Connected) // Checks to see if client is not connected, if true, write to console and break the loop
{
Console.WriteLine(" >> Data Sent");
}
data = new byte[1024]; // Resets data var
recv = socket.ReceiveFrom(data, ref tmpRemote);
if (recv == 0) // If no info is recived, break loop
{
break;
}
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
}
Console.ReadLine();
socket.Close();
Client Code
public void sendUsr()
{
String username = usrBox.Text;
byte[] packetData = System.Text.ASCIIEncoding.ASCII.GetBytes(username);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(IP), port);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Makes socket to send data
socket.SendTo(packetData, ep); // Sends data to server
}
As rob said, you may want to format your data using data-interchange format, before you send them. I prefer use JSON provided by Newtonsoft.Json libary. You need to have a reference to it.
Client Code
String dataToSend = JsonConvert.SerializeObject(new { username = usrBox.Text, password = pwdBox.Text });
Server Code
recv = socket.ReceiveFrom(data, ref tmpRemote); // Stores all client info, get data it's sending (And how much data is in it)
dynamic receivedData = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(data, 0, recv));
String username = (string)receivedData.username;
String password = (string)receivedData.password;

Trouble with sending using TCP File Transfer Client

I have to develop a simple TCP File Transfer Client as part of an exercise/demonstration but I am having trouble with data delivery.
I am already provided with the TCP File server which will receive the incoming files and I have to code a Client that will connect to and send a file to the server. Thus far I have been successful as far as converting the data of the selected file into to a format ready to transferring and successfully opening a connection and then sending of the data, however even encounter a problem on server that is receiving - I am not allowed to change the code of the server and should thus change my client code in such a way that the data sent can be interpreted by the server. Here is the code I use (some is left out which is simple overhead, like input-box to get IP address etc.):
Link for TCP Server VS Solution (if you prefer): https://www.mediafire.com/?682owf9wtdzmxac
TCP File Transfer Client Sending method:
private void TransferFile(string _sFileName, string _sIPAdress)
{
//Convert data for transfer
Stream strmfilestream = File.OpenRead(_sFileName);
Byte[] bFileBuffer = new Byte[strmfilestream.Length];
//Open TCP/IP Connection
TcpClient tcpClientSocket = new TcpClient(_sIPAdress,8080);
NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
nsNetworkStream.Write(bFileBuffer,0,bFileBuffer.GetLength(0));
nsNetworkStream.Close();
}
*Note: _sFileName is just the full file path + File name from a OpenFileDialog.
Here is the Load Method of the server to get things going:
if (!Directory.Exists(#"C:\TCPFileServer"))
Directory.CreateDirectory(#"C:\TCPFileServer");
//Get Ip address of server host machine
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
lblServerIP.Text = IPHost.AddressList[5].ToString();
lstSockets = new ArrayList();
Thread thdListener = new Thread(new ThreadStart(listenerThread));
thdListener.IsBackground = true; //This will enabe the thread to terminate when application is closed
thdListener.Start();
Here is the listener thread method:
public void listenerThread()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 8080);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
this.Invoke((Action)(() => lstConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.")));
lock (this)
{
lstSockets.Add(handlerSocket);
}
ThreadStart thdsHandler = new ThreadStart(handlerThread);
Thread thdHandler = new Thread(thdsHandler);
thdHandler.Start();
}
}
}
And then lasty here is the handler thread method:
public void handlerThread()
{
try
{
int iBlockSize = 1024 * 3000; //3mb block size
Byte[] dataByte = new Byte[iBlockSize];
Byte[] rcvdData = new Byte[128000 * 1024];//128mb File Limit
Socket handlerSocket = (Socket)lstSockets[lstSockets.Count - 1];
NetworkStream networkStream = new NetworkStream(handlerSocket);
int i = 0;
int iRcvdBytes = 0;
while (true)
{
//Read from socket and store to buffer 'dataByte'
iRcvdBytes = networkStream.Read(dataByte, 0, iBlockSize);
dataByte.CopyTo(rcvdData, i);//Copy recieved bytes,from buffer, to another byte array
i += iRcvdBytes;
if (iRcvdBytes == 0) break;
}
//Get the File name length, BitConvertor occupies the first 4 bytes
int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);
//Get the file name using length as the size and 4 as the offset
string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);
Stream fileStream = File.Open("C:\\TCPFileServer\\" + sFileName, FileMode.Create);
//Populate raw File on local machine
fileStream.Write(rcvdData, 4 + iFileNameLength, i - 4 - iFileNameLength);
fileStream.Close();
//Update BRS Net Files Server Log
this.Invoke((Action)(() => lstConnections.Items.Add(sFileName + ": Transfered.")));
//Close Connection
networkStream.Close();
handlerSocket = null; //Clear socket
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Now I have debugged and as far I can determine, the first time I can see a problem is when we are trying to determine the file name length where the code reads int iFileNameLength = BitConverter.ToInt32(rcvdData, 0); - When debugging this variable is always determined as '0', which I assume is not correct? I am not sure. The required results that needs to be achieved is that the Server should receive the file and after the successful transfer, the file name should be displayed in the ListBox.
Here is screen shots showing the problem i'm experiencing:
We can see that bytes are definitely received:
Note that the file name can not be retrieved from using the file name length and offset:
And thus, the following error occurs:
My experience and expertise lie elsewhere and this is the first time I am coding within this paradigm(File transfer over network). I do however have theoretical knowledge about/studied the OSI model and TCP/IP Protocol stack, but never coded anything like this. One note given to me was that the server was coded with the assumption that it will be executed on a specific PC and I am allowed to change code of the Server application if it is absolutely necessary.
Try this. You have to do thinks in reverse on the client and using a List makes things easier.
private void TransferFile(string _sFileName, string _sIPAdress)
{
List<Byte> bFileBuffer = File.ReadAllBytes(_sFileName).ToList();
byte[] bFileName = Encoding.ASCII.GetBytes(_sFileName);
bFileBuffer.InsertRange(0, bFileName);
//Get the File name length, BitConvertor occupies the first 4 bytes
byte[] brcvdDataCount = BitConverter.GetBytes((UInt32)_sFileName.Count());
bFileBuffer.InsertRange(0, brcvdDataCount);
//Open TCP/IP Connection
TcpClient tcpClientSocket = new TcpClient(_sIPAdress, 8080);
NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
nsNetworkStream.Write(bFileBuffer.ToArray(), 0, bFileBuffer.Count);
nsNetworkStream.Close();
}​​
There are two things with the server code you should be aware of
/Get the File name length, BitConvertor occupies the first 4 bytes
int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);
//Get the file name using length as the size and 4 as the offset
string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);​
1) You need to add a byte count to beginning of upload.
2) The code is using Ascii Encoding which means you can not upload binary data.

Send server multiple messages? C#

I have a quick and dirty question. So as it stands, i have two clients and a server running. I can communicate messages from the clients to the server without any problem. my problem appears when i want to read two messages from the client - rather than just one message.
The error which i receive is: IOException was unhandled. Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Here is my code on the server side:
private static void HandleClientComm(object client)
{
/** creating a list which contains DatabaseFile objects **/
List theDatabase = new List();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
// Blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
// Message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
Console.WriteLine("To: " + tcpClient.Client.LocalEndPoint);
Console.WriteLine("From: " + tcpClient.Client.RemoteEndPoint);
Console.WriteLine(encoder.GetString(message, 0, bytesRead));
if (encoder.GetString(message, 0, bytesRead) == "OptionOneInsert")
{
byte[] message2 = new byte[4096];
int bytesRead2 = 0;
**bytesRead2 = clientStream.Read(message, 0, 4096);** //ERROR occurs here!
Console.WriteLine("Attempting to go inside insert)");
Menu.Insert(theDatabase, bytesRead2);
}
Here is my client code:
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("OptionOneInsert");
Console.ReadLine();
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
NetworkStream clientStream2 = client.GetStream();
String text = System.IO.File.ReadAllText("FirstNames.txt");
clientStream2.Write(buffer, 0, buffer.Length);
clientStream2.Flush();
ASCIIEncoding encoder2 = new ASCIIEncoding();
byte[] buffer2 = encoder2.GetBytes(text);
Console.WriteLine("buffer is filled with content");
Console.ReadLine();
When the client sends the message "optionOne" it is received by the server just fine. It's only when i attempt to send the string called "text" that the issues appears!
Any help would be greatly appreciated - I'm not all that familiar with Sockets, hence i've been struggling with trying to understand this for sometime now
You've got a big problem here - there's nothing to specify the end of one message and the start of another. It's quite possible that the server will receive two messages in one go, or half a message and then the other half.
The simplest way of avoiding that is to prefix each message with the number of bytes in it, e.g. as a fixed four-byte format. So to send a message you would:
Encoding it from a string to bytes (ideally using UTF-8 instead of ASCII unless you're sure you'll never need any non-ASCII text)
Write out the length of the byte array as a four-byte value
Write out the content
On the server:
Read four bytes (looping if necessary - there's no guarantee you'd even read those four bytes together, although you almost certainly will)
Convert the four bytes into an integer
Allocate a byte array of that size
Loop round, reading from "the current position" to the end of the buffer until you've filled the buffer
Convert the buffer into a string
Another alternative is simply to use BinaryReader and BinaryWriter - the ReadString and WriteString use length-prefixing, admittedly in a slightly different form.
Another alternative you could use is to have a delimiter (e.g. carriage-return) but that means you'll need to add escaping in if you ever need to include the delimiter in the text to transmit.

Categories