I'm creating an RCON web application for Call of Duty Black Ops. COD uses rcon and udp packets to send and receive information. Using the following code, I've been able to send and receive information with a COD4 server. Now that COD7 is out, I'm no longer receiving responses back.
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.Connect(IPAddress.Parse(gameServerIP), gameServerPort);
string command;
command = password + " " + rconCommand;
byte[] bufferTemp = Encoding.ASCII.GetBytes(command);
byte[] bufferSend = new byte[bufferTemp.Length + 5];
//intial 5 characters as per standard
bufferSend[0] = byte.Parse("255");
bufferSend[1] = byte.Parse("255");
bufferSend[2] = byte.Parse("255");
bufferSend[3] = byte.Parse("255");
bufferSend[4] = byte.Parse("02");
int j = 5;
for (int i = 0; i < bufferTemp.Length; i++)
{
bufferSend[j++] = bufferTemp[i];
}
//send rcon command and get response
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
client.Send(bufferSend, SocketFlags.None);
//big enough to receive response
byte[] bufferRec = new byte[65000];
client.Receive(bufferRec);
Does anyone have any ideas? Black Ops ships with its own Rcon tool that I've tried using Wireshark to capture the outgoing packets to copy. The outgoing packets between my application and theirs are next to identical, except I get no replies back when I use mine.
i knwo why cause i make a tool myself.
What's wrong in your code is that : bufferSend[4] = byte.Parse("02");
the good one is : bufferSend[4] = byte.Parse("00");
Try it, works for me!
Here my piece of code, i use a thread to run it:
how to do:
in your class set the private command, then call the worker, when thread finish, just read the private response.
private IPEndPoint ipendpoint;
private string command;
private string response;
private void worker()
{
UdpClient client = new UdpClient();
var result1 = string.Empty;
var result2 = string.Empty;
bool sent = false;
bool DoubleTrame = false;
Byte[] bufferTemp = Encoding.ASCII.GetBytes(this.command);
Byte[] bufferSend = new Byte[bufferTemp.Length + 5];
Byte[] bufferRec;
Byte[] bufferRec2;
bufferSend[0] = Byte.Parse("255");
bufferSend[1] = Byte.Parse("255");
bufferSend[2] = Byte.Parse("255");
bufferSend[3] = Byte.Parse("255");
bufferSend[4] = Byte.Parse("00");
for (int i = 0; i < bufferTemp.Length; i++)
{
bufferSend[i + 5] = bufferTemp[i];
}
while (!sent)
{
client.Send(bufferSend, bufferSend.Length, ipendpoint);
Thread.Sleep(200);
if (client.Available > 0)
{
sent = true;
if (client.Available > 1200)
{
DoubleTrame = true;
}
}
}
bufferRec = client.Receive(ref ipendpoint);
if (DoubleTrame)
{
bufferRec2 = client.Receive(ref ipendpoint);
result2 = Encoding.ASCII.GetString(bufferRec2);
if (result2.Contains("\n\n"))
{
result2 = result2.Remove(result2.IndexOf("\n\n"));
}
result2 = result2.Substring(12);
}
result1 = Encoding.ASCII.GetString(bufferRec);
this.response = result1 + result2;
}
I am doing a similar thing using vb.net
I have written rcon tools for COD MW and COD WW no problem however so far I have not been able to get a response back from my black ops server.
In fact, i have done the saame thing as you, i used WireShark to look the byte sent and received with the default rconTool provide in steam for Black Ops.
Other tip:
The command "status" give you many information about the current players but not the team of each.
You better use "teamstatus" instead, this one give you the same information but with the team of each player.
I have trouble right now to perfectly parse the response, but to give a readeable answer use this:
replace :
byte[] bufferRec = new byte[65000];
client.Receive(bufferRec);
by:
byte[] bufferRec;
while (client.Available == 0)
{
Thread.Sleep(10);
}
client.Receive(bufferRec);
string response=Encoding.ASCII.GetString(bufferRec);
var list= response.Split('\n');
This way you'll have an array with each player separate in a row.
Btw: i'm mack, i'm now registered, wasn't this night
Edit: oups, i didn't notice you've already tried the teamstatus command.
You need to look at the number return by client.Avalaible, because the server only send 1168 byte at once, so if client.Avalaible>1168, you need a second buffer to get the second flow with client.receive.
In fact there's only two possible number for client.avalaible : 1168 and 2336 (yes, the double) i don't know why, but they didn't managed to send the exact number of data, the buffer is always full or empty.
I noticed also that the second receive() is like "paste" on the first buffer.
YOu'll have at hte begginig the complementary information of the first Receive(), then the "noise" of the old one.
Just take a look, you will see what i mean.
I'm at work now, but this evening i will post my code to help.
Related
Im currently creating a project that will run in a browser & has an c# server connected.
The Server uses an TcpListener to accept connections & receive messages, but I want the server to be able to respond to the client. This has given me a few issues.
Here is the code for my client:
private ClientWebSocket socket;
internal async Task InitAsync(string host, int port, GamePacketParser parser)
{
Logger.Info("Setting up the socket connection...");
socket = new ClientWebSocket();
await socket.ConnectAsync(new Uri($"ws://{host}:{port}/"), CancellationToken.None);
Logger.Info("Successfully established the connection.");
this.parser = parser;
buffer = new byte[GameSocketManagerStatics.BUFFER_SIZE];
Task.Run(recieve);
}
private async Task recieve()
{
Logger.Debug("Starting Reciever.....");
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var packet = new byte[result.Count];
Array.Copy(buffer, packet, result.Count);
///parser.handlePacketData(packet);
Logger.Debug($"Recieved: {Encoding.UTF8.GetString(packet)}");
///Task.Run(recieve); //Start receiving again
}
public async Task SendData(byte[] data)
{
Logger.Debug("Triggerd send");
string packet = BitConverter.ToString(data);
await socket.SendAsync(new ArraySegment<byte>(data), WebSocketMessageType.Text, true, CancellationToken.None);
Logger.Info($"Sended Data: {packet}");
}
The code above simply connects to the server over a web socket. Sending packets works fine. The second the server sends data back, the client won't send any data anymore to the server. Like its stuck.
static void Main(string[] args)
{
string ip = "127.0.0.1";
int port = 30000;
var server = new TcpListener(IPAddress.Parse(ip), port);
server.Start();
Console.WriteLine("Server has started on {0}:{1}, Waiting for a connection...", ip, port);
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
NetworkStream stream = client.GetStream();
if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
{
Console.WriteLine("=====Handshaking from client=====\n{0}", s);
// 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
// 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
// 3. Compute SHA-1 and Base64 hash of the new value
// 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker
byte[] response = Encoding.UTF8.GetBytes(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: websocket\r\n" +
"Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");
stream.Write(response, 0, response.Length);
}
byte[] message = Encoding.UTF8.GetBytes("Connection is established");
stream.Write(message, 0, message.Length);
}
The problem is probably because it is not encoded for WebSockets, but I tried a lot of online solutions for encoding (For example: How can I send and receive WebSocket messages on the server side?) But even with those encoders, it did not seem to solve the problem.
Thanks for your help in advance. Im still new to WebSockets, so spoonfeeding is allowed.
aepot your answer is a good one, but i really wanted my server on the TCP level, I would have needed to change to much code if I wanted to use it on my official server that uses sockets.
I have been doing some more digging into WebSockets, after some searching I figured it out, I basically needed to send a header before sending the data. I did not know how to create that header, but I found some code online that did. (I have been searching for about 12 hours :?)
The solution:
protected int GetHeader(bool finalFrame, bool contFrame)
{
int header = finalFrame ? 1 : 0;//fin: 0 = more frames, 1 = final frame
header = (header << 1) + 0;//rsv1
header = (header << 1) + 0;//rsv2
header = (header << 1) + 0;//rsv3
header = (header << 4) + (contFrame ? 0 : 1);//opcode : 0 = continuation frame, 1 = text
header = (header << 1) + 0;//mask: server -> client = no mask
return header;
}
protected byte[] IntToByteArray(ushort value)
{
var ary = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(ary);
}
return ary;
}
public static IEnumerable<string> SplitInGroups(this string original, int size)
{
var p = 0;
var l = original.Length;
while (l - p > size)
{
yield return original.Substring(p, size);
p += size;
}
yield return original.Substring(p);
}
public static void SendMessage(string packet) {
Queue<string> que = new Queue<string>(packet.SplitInGroups(125)); //Make it so the message is never longer then 125 (Split the message into parts & store them in a queue)
int len = que.Count;
while (que.Count > 0)
{
var header = GetHeader(
que.Count > 1 ? false : true,
que.Count == len ? false : true
); //Get the header for a part of the queue
byte[] list = Encoding.UTF8.GetBytes(qui.Dequeue()); //Get part of the message out of the queue
header = (header << 7) + list.Length; //Add the length of the part we are going to send
//Send the header & message to client
stream.write(IntToByteArray((ushort)header));
stream.write(list);
}
}
I have not coded this myself, but sadly I cant find the link where I got it from to credit the person who did.
I have a Bluetooth OBDII dongle for my car (the brand is Veepeak), and I'm trying to write a Windows app that can communicate with it. So far it seems that I'm able to connect to the device from my laptop, send commands, and receive some sort of response, but the responses I receive are not what I expect. I am using the 32feet communication library to handle the Bluetooth stuff.
Here is the code I am using to connect and also the functions I am using to send messages:
BluetoothClient client;
Stream stream;
client = new BluetoothClient();
Guid uuid = new Guid("00001101-0000-1000-8000-00805f9b34fb");
client.BeginConnect(SelectedDevice.DeviceAddress, uuid, bluetoothClientConnectCallback, client);
private void bluetoothClientConnectCallback(IAsyncResult result)
{
client = (BluetoothClient)result.AsyncState;
client.EndConnect(result);
clientConnected = true;
stream = client.GetStream();
UIWriteLine("Client connected");
}
private string sendMessage(string message)
{
byte[] encodedMessage = Encoding.ASCII.GetBytes(message);
stream.Write(encodedMessage, 0, encodedMessage.Length);
Thread.Sleep(100);
int count = 0;
byte[] buffer = new byte[1024];
string retVal = string.Empty;
count = stream.Read(buffer, 0, buffer.Length);
retVal += Encoding.ASCII.GetString(buffer, 0, count);
return retVal.Replace("\n", "");
}
private string getValue(string pid)
{
byte[] encodedMessage = Encoding.ASCII.GetBytes(pid + "\r");
stream.Write(encodedMessage, 0, encodedMessage.Length);
Thread.Sleep(100);
bool cont = true;
int count = 0;
byte[] buffer = new byte[1024];
string retVal = string.Empty;
while (cont)
{
count = stream.Read(buffer, 0, buffer.Length);
retVal += Encoding.ASCII.GetString(buffer, 0, count);
if (retVal.Contains(">"))
{
cont = false;
}
}
return retVal.Replace("\n", "");
}
I use the sendMessage method to send AT commands, and the getValue method to get a specific PID (these methods are borrowing code from an OBDII library I found here).
When I send AT commands, I seem to only get an echo of whatever I send, and when I send PIDs, I get a response of a single question mark, which to my understanding means the command is invalid.
Is it possible that my dongle does not have an ELM327? Am I doing something wrong with my Bluetooth communication or is my UUID wrong? Thanks.
I also have a Veepeak. It comes quite highly recommended in the relevant reviews and works very well with the available trial apps and my android phone. I'm struggling with initialization in my own python app, however.
On the python based application that I'm developing on the raspi, I have to open a 'virtual' serial port that is mapped to the previously paired device by it's mac address. The pairing and noting of the mac address is done at the operating system level with generic bluetooth tools.
I'm sorry but I'm kinda having a confusing problem here...
I was using Unity recently and try to make a simple TCP server that can broadcast through all its clients, also to himself where the server itself is one of the client, like chat room or something.
so I did successfully done so, but the problem is, all the data that received by the client is actually twice of the initially data send from client, below is the example of my code
public void broadcast(string data)
{
print("Broadcast");
byte[] dataByte = Encoding.ASCII.GetBytes(data);
print(ClientList.Count);
for(int x = 0; x<ClientList.Count;x++)
{
ClientList[x].Send(dataByte);
print ("something" +ClientList[x].Send(dataByte));
print ("loop");
}
}
and this is how the client will receive it
private void ReceiveData(IAsyncResult ar)
{
print ("ReceiveData Client");
Socket handler = (Socket)ar.AsyncState;
try
{
int x = handler.EndReceive(ar);
print("Receiving Data...");
print (x);
if (x > 0)
{
StringBuilder sb = new StringBuilder();
sb.Append(Encoding.ASCII.GetString(buffer, 0, x));
string content = sb.ToString();
print("Data Received: " + content);
//string[] data = content.Split(';');
//for (int i = 0; i < data.Length; i++)
//{
this.ProcessData(x, content, handler);
//}
sb.Remove(0, sb.Length);
handler.BeginReceive(buffer, 0, 1024, 0, new AsyncCallback(ReceiveData), handler);
}
else
{
print("Connection Closed...");
}
}
catch (Exception e)
{
print(e.Message);
}
}
I try to send test;this is client
and the result is below
Broadcast
1
something20
ReceiveData Client
loop
Receiving data...
40
Data Received: test;this is client test; this is client"
I don't know what or how this went wrong, any help will be appreciated. Thanks b4
The problem is within these two lines:
ClientList[x].Send(dataByte);
print ("something" +ClientList[x].Send(dataByte));
Notice how you've executed ClientList[x].Send(dataByte) twice? That's why you're getting it 2 times on the receiving end. Just remove one of the two lines and you should be fine.
I developed a simple TCP client on Windows Phone, as shown here on MSDN
This is working just as expected.
Now, I want to send very large Base64 strings though this client (for transferring images).
But, when I try to send Base64 strings from this client, I only receive a portion of the string at the server, due to which I'm not able to generate the entire image at the server.
The server side code for receiving strings is: (Edited)
IPAddress ipAd = IPAddress.Any;
Console.Write("Port No. (leave blank for port 8001): ");
string port;
port = Console.ReadLine();
if (port == "")
port = "8001";
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, int.Parse(port));
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("\nThe server is running at port " + port);
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint);
Console.WriteLine("\nWaiting for a connection.....");
Socket s = myList.AcceptSocket();
Console.WriteLine("\nConnection accepted from " + s.RemoteEndPoint);
byte[] b = new byte[5 * 1024 * 1024]; // BIG SIZE for byte array, is this correct?
String message = String.Empty;
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
System.IO.File.WriteAllText(#"Message.txt", message); // write it to a file
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\n\nSent Acknowledgement");
/* clean up */
s.Close();
myList.Stop();
I'm really stuck here.
Please help me.
I think the problem is with the client and not the server.
Please assist me.
The class I've used in the client can be found at the MSDN article referred to above.
PS: I've already tried to increase the values of TIMEOUT_MILLISECONDS and MAX_BUFFER_SIZE in the class. But it did not help.
Update:
Here's some client side code (look here on MSDN for reference):
// Make sure we can perform this action with valid data
if (ValidateRemoteHost() && ValidateInput())
{
// Instantiate the SocketClient
SocketClient client = new SocketClient();
// Attempt to connect to the echo server
Log(String.Format("Connecting to server '{0}' over port {1} (echo) ...", txtRemoteHost.Text, ECHO_PORT), true);
string result = client.Connect(txtRemoteHost.Text, ECHO_PORT);
Log(result, false);
byte[] bytearray = null;
// Attempt to send our message to be echoed to the echo server
Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
if (checkBox1.IsChecked == true) // this checkbox is for image selection
{
// This is the part where we send images
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap wbitmp = new WriteableBitmap((BitmapImage)image1.Source);
wbitmp.SaveJpeg(ms, (int)wbitmp.PixelWidth, (int)wbitmp.PixelHeight, 0, 10);
bytearray = ms.ToArray();
string str = Convert.ToBase64String(bytearray);
result = client.Send(str);
System.Diagnostics.Debug.WriteLine("\n\nMessge sent:\n\n" + str + "\n\n");
}
}
else
{
result = client.Send(txtInput.Text);
}
Log(result, false);
// Receive a response from the server
Log("Requesting Receive ...", true);
result = client.Receive();
Log(result, false);
// Close the socket connection explicitly
client.Close();
}
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Edit: now that section of code has been reduced down to only
int k = s.Receive(b);
is bad: it assumes all the data sends perfectly in one go, which isn't how networking works.
Two options:
At the start of the string, include how long it should.
At the end of the string, have an end symbol (a null perhaps) that won't be anywhere else in the message
Then that while loop should keep going until either the entire length is found or the end symbol is found.
(Also, sending Base64 is a bad idea when you can avoid it. Why not send as a stream of raw bytes?)
[ED: This portion is no longer relevant](Also, why is the server choosing where to save the file [and delaying everything until the server makes a pick] - the client should indicate where to save it at the start, and then the server merely sanity checks it. [Unless you have a very good reason not do it that way])
EDIT: a quick simple implementation of what I was saying:
This server code
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
change to
while (true)
{
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
char bc = Convert.ToChar(b[i]); // This is a very wrong way of doing this but it works I guess meh.
if (bc == ' ')
{ // You've struck the end! Get out of this infinite loop!
goto endmyloop;
}
message += bc;
Console.Write(bc);
}
}
endmyloop:
This piece of client code
result = client.Send(str);
change to
result = client.Send(str + " ");
-- Base64 can never have a space in it, so that will be used to mark the end.
Be warned that if the client errors (and doesn't send a space at the end for some weird reason), this code will be trapped in the while loop forever (zero-CPU-usage infinite-wait)
I am trying to send a request to an existing server solution and write out the results. The server is sending a total of 4 messages with my particular request but the number of messsages back can vary depending on the initial query.
I am able to successfully send the query to the server but when it comes to reading the response i can only read one message. The server logs show that 4 were sent back.
Please help.
IPHostEntry hostEntry = Dns.GetHostEntry(server_textbox.Text);
IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], port);
string data = String.Empty;
testclient = new TcpClient(server_textbox.Text, port);
testclient.ReceiveBufferSize = 1024;
testclient.SendBufferSize = 1024;
NetworkStream netStream = testclient.GetStream();
Byte[] message_byte = new System.Text.ASCIIEncoding().GetBytes(msg2);
netStream.Write(message_byte, 0, message_byte.Length);
Byte[] returnMessage = new byte[1024];
Int32 totalBytesReceived = 0;
Int32 bytesReceived = 0;
try
{
while ((bytesReceived = netStream.Read(returnMessage, totalBytesReceived, returnMessage.Length)) > 0)
{
totalBytesReceived += bytesReceived;
data += "\n" + ASCIIEncoding.ASCII.GetString(returnMessage);
bytesReceived = 0;
}
}
catch (Exception error)
{
MessageBox.Show(error.ToString());
}
result_box.Text += data;
netStream.Close();
testclient.Close();
}
My guess is that all your messages are read in the first Read. When the server replies, all the data gets stuck in the windows receive buffer and gets read all at once.
I would recommend using Wireshark, which is more or less mandatory when doing network programming. You'll be able to see the 4 messages coming back from the server as at least 4 different tcp packets.