Skip to content

Instantly share code, notes, and snippets.

@csh

csh/ServerPing.cs

Last active Jan 20, 2021
Embed
What would you like to do?
Server ping written in C#, complete with coloured console output.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
#if DEBUG
using System.Diagnostics;
#endif
namespace MCServerPing
{
class ServerPing
{
private static readonly Dictionary<char, ConsoleColor> Colours = new Dictionary<char, ConsoleColor>
{
{ '0', ConsoleColor.Black },
{ '1', ConsoleColor.DarkBlue },
{ '2', ConsoleColor.DarkGreen },
{ '3', ConsoleColor.DarkCyan },
{ '4', ConsoleColor.DarkRed },
{ '5', ConsoleColor.DarkMagenta },
{ '6', ConsoleColor.Yellow },
{ '7', ConsoleColor.Gray },
{ '8', ConsoleColor.DarkGray },
{ '9', ConsoleColor.Blue },
{ 'a', ConsoleColor.Green },
{ 'b', ConsoleColor.Cyan },
{ 'c', ConsoleColor.Red },
{ 'd', ConsoleColor.Magenta },
{ 'e', ConsoleColor.Yellow },
{ 'f', ConsoleColor.White },
{ 'k', Console.ForegroundColor },
{ 'l', Console.ForegroundColor },
{ 'm', Console.ForegroundColor },
{ 'n', Console.ForegroundColor },
{ 'o', Console.ForegroundColor },
{ 'r', ConsoleColor.White }
};
private static NetworkStream _stream;
private static List<byte> _buffer;
private static int _offset;
private static void Main(string[] args)
{
Console.Title = "Minecraft Server Ping";
var client = new TcpClient();
var task = client.ConnectAsync("localhost", 25565);
Console.WriteLine("Connecting to Minecraft server..");
while (!task.IsCompleted)
{
#if DEBUG
Debug.WriteLine("Connecting..");
#endif
Thread.Sleep(250);
}
if (!client.Connected)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unable to connect to the server");
Console.ResetColor();
Console.ReadKey(true);
Environment.Exit(1);
}
_buffer = new List<byte>();
_stream = client.GetStream();
Console.WriteLine("Sending status request");
/*
* Send a "Handshake" packet
* http://wiki.vg/Server_List_Ping#Ping_Process
*/
WriteVarInt(47);
WriteString("localhost");
WriteShort(25565);
WriteVarInt(1);
Flush(0);
/*
* Send a "Status Request" packet
* http://wiki.vg/Server_List_Ping#Ping_Process
*/
Flush(0);
/*
* If you are using a modded server then use a larger buffer to account,
* see link for explanation and a motd to HTML snippet
* https://gist.github.com/csh/2480d14fbbb33b4bbae3#gistcomment-2672658
*/
var buffer = new byte[Int16.MaxValue];
// var buffer = new byte[4096];
_stream.Read(buffer, 0, buffer.Length);
try
{
var length = ReadVarInt(buffer);
var packet = ReadVarInt(buffer);
var jsonLength = ReadVarInt(buffer);
#if DEBUG
Console.WriteLine("Received packet 0x{0} with a length of {1}", packet.ToString("X2"), length);
#endif
var json = ReadString(buffer, jsonLength);
var ping = JsonConvert.DeserializeObject<PingPayload>(json);
Console.WriteLine("Software: {0}", ping.Version.Name);
Console.WriteLine("Protocol: {0}", ping.Version.Protocol);
Console.WriteLine("Players Online: {0}/{1}", ping.Players.Online, ping.Players.Max);
WriteMotd(ping);
Console.ReadKey(true);
}
catch (IOException ex)
{
/*
* If an IOException is thrown then the server didn't
* send us a VarInt or sent us an invalid one.
*/
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unable to read packet length from server,");
Console.WriteLine("are you sure it's a Minecraft server?");
#if DEBUG
Console.WriteLine("Here are the details:");
Console.WriteLine(ex.ToString());
#endif
Console.ResetColor();
}
}
private static void WriteMotd(PingPayload ping)
{
Console.Write("Motd: ");
var chars = ping.Motd.ToCharArray();
for (var i = 0; i < ping.Motd.Length; i++)
{
try
{
if (chars[i] == '\u00A7' && Colours.ContainsKey(chars[i + 1]))
{
Console.ForegroundColor = Colours[chars[i + 1]];
continue;
}
if (chars[i - 1] == '\u00A7' && Colours.ContainsKey(chars[i]))
{
continue;
}
}
catch (IndexOutOfRangeException)
{
// End of string
}
Console.Write(chars[i]);
}
Console.WriteLine();
Console.ResetColor();
}
#region Read/Write methods
internal static byte ReadByte(byte[] buffer)
{
var b = buffer[_offset];
_offset += 1;
return b;
}
internal static byte[] Read(byte[] buffer, int length)
{
var data = new byte[length];
Array.Copy(buffer, _offset, data, 0, length);
_offset += length;
return data;
}
internal static int ReadVarInt(byte[] buffer)
{
var value = 0;
var size = 0;
int b;
while (((b = ReadByte(buffer)) & 0x80) == 0x80)
{
value |= (b & 0x7F) << (size++*7);
if (size > 5)
{
throw new IOException("This VarInt is an imposter!");
}
}
return value | ((b & 0x7F) << (size*7));
}
internal static string ReadString(byte[] buffer, int length)
{
var data = Read(buffer, length);
return Encoding.UTF8.GetString(data);
}
internal static void WriteVarInt(int value)
{
while ((value & 128) != 0)
{
_buffer.Add((byte) (value & 127 | 128));
value = (int) ((uint) value) >> 7;
}
_buffer.Add((byte) value);
}
internal static void WriteShort(short value)
{
_buffer.AddRange(BitConverter.GetBytes(value));
}
internal static void WriteString(string data)
{
var buffer = Encoding.UTF8.GetBytes(data);
WriteVarInt(buffer.Length);
_buffer.AddRange(buffer);
}
internal static void Write(byte b)
{
_stream.WriteByte(b);
}
internal static void Flush(int id = -1)
{
var buffer = _buffer.ToArray();
_buffer.Clear();
var add = 0;
var packetData = new[] {(byte) 0x00};
if (id >= 0)
{
WriteVarInt(id);
packetData = _buffer.ToArray();
add = packetData.Length;
_buffer.Clear();
}
WriteVarInt(buffer.Length + add);
var bufferLength = _buffer.ToArray();
_buffer.Clear();
_stream.Write(bufferLength, 0, bufferLength.Length);
_stream.Write(packetData, 0, packetData.Length);
_stream.Write(buffer, 0, buffer.Length);
}
#endregion
}
#region Server ping
/// <summary>
/// C# represenation of the following JSON file
/// https://gist.github.com/thinkofdeath/6927216
/// </summary>
class PingPayload
{
/// <summary>
/// Protocol that the server is using and the given name
/// </summary>
[JsonProperty(PropertyName = "version")]
public VersionPayload Version { get; set; }
[JsonProperty(PropertyName = "players")]
public PlayersPayload Players { get; set; }
[JsonProperty(PropertyName = "description")]
public string Motd { get; set; }
/// <summary>
/// Server icon, important to note that it's encoded in base 64
/// </summary>
[JsonProperty(PropertyName = "favicon")]
public string Icon { get; set; }
}
class VersionPayload
{
[JsonProperty(PropertyName = "protocol")]
public int Protocol { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
}
class PlayersPayload
{
[JsonProperty(PropertyName = "max")]
public int Max { get; set; }
[JsonProperty(PropertyName = "online")]
public int Online { get; set; }
[JsonProperty(PropertyName = "sample")]
public List<Player> Sample { get; set; }
}
class Player
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
}
#endregion
}
@csh

This comment has been minimized.

Copy link
Owner Author

@csh csh commented Jul 30, 2015

Depends on JSON.NET library.

@ImaginaryDevelopment

This comment has been minimized.

Copy link

@ImaginaryDevelopment ImaginaryDevelopment commented Dec 27, 2015

does this guy work on the most recent pc version of minecraft?

@ImaginaryDevelopment

This comment has been minimized.

Copy link

@ImaginaryDevelopment ImaginaryDevelopment commented Dec 31, 2015

@csh

This comment has been minimized.

Copy link
Owner Author

@csh csh commented Mar 29, 2016

does this guy work on the most recent pc version of minecraft?

My apologies for not replying earlier @ImaginaryDevelopment, apparently gists don't have notifications - or at least I don't receive them. :(

I designed this for 1.7 and 1.8, I don't know if the protocol has changed for 1.9 but I can look into it.

@JonathanBourassa

This comment has been minimized.

Copy link

@JonathanBourassa JonathanBourassa commented Aug 8, 2018

Added Bonus here method to translate motd to html(all inline style):
N.B. The obfuscated tag will render a <span id="obfuscated">text</span>. You'll need to find a javascript to take it's content and shuffle it.

static string MotdToHtml(string motd)
        {
            var brInducedMotd = motd.Replace("\n", "<br />");
            var formatParts = brInducedMotd.Split(new[] { '\u00A7' }, StringSplitOptions.RemoveEmptyEntries);
            var motdStartWithFormat = motd.IndexOf('\u00A7') == 0;
            var formatBeforeResetCount = 0;
            var htmlFormatedString = new StringBuilder();
            for (var i = 0; i < formatParts.Length; i++)
            {
                if (!motdStartWithFormat && i == 0)
                {
                    htmlFormatedString.Append(formatParts[i]);
                    continue;
                }
                var formatKey = formatParts[i].Substring(0, 1);
                switch (formatKey)
                {
                    case "0":
                        htmlFormatedString.Append($"<span style=\"color:#000;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "1":
                        htmlFormatedString.Append($"<span style=\"color:#00A;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "2":
                        htmlFormatedString.Append($"<span style=\"color:#0A0;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "3":
                        htmlFormatedString.Append($"<span style=\"color:#0AA;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "4":
                        htmlFormatedString.Append($"<span style=\"color:#A00;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "5":
                        htmlFormatedString.Append($"<span style=\"color:#A0A;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "6":
                        htmlFormatedString.Append($"<span style=\"color:#FA0;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "7":
                        htmlFormatedString.Append($"<span style=\"color:#AAA;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "8":
                        htmlFormatedString.Append($"<span style=\"color:#555;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "9":
                        htmlFormatedString.Append($"<span style=\"color:#55F;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "a":
                        htmlFormatedString.Append($"<span style=\"color:#5F5;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "b":
                        htmlFormatedString.Append($"<span style=\"color:#5FF;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "c":
                        htmlFormatedString.Append($"<span style=\"color:#F55;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "d":
                        htmlFormatedString.Append($"<span style=\"color:#F5F;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "e":
                        htmlFormatedString.Append($"<span style=\"color:#FF5;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "f":
                        htmlFormatedString.Append($"<span style=\"color:#FFF;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "k":
                        htmlFormatedString.Append($"<span id=\"obfuscated\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "l":
                        htmlFormatedString.Append($"<span style=\"font-weight:bold;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "m":
                        htmlFormatedString.Append($"<span style=\"text-decoration:line-through;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "n":
                        htmlFormatedString.Append($"<span style=\"text-decoration:underline;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "o":
                        htmlFormatedString.Append($"<span style=\"font-style:italic;\">{formatParts[i].Substring(1)}");
                        formatBeforeResetCount++;
                        break;
                    case "r":
                        for (var j = 0; j < formatBeforeResetCount; j++)
                        {
                            htmlFormatedString.Append("</span>");
                        }
                        htmlFormatedString.Append($"{formatParts[i].Substring(1)}");
                        formatBeforeResetCount = 0;
                        break;
                }
            }
            for (var k = 0; k < formatBeforeResetCount; k++)
            {
                htmlFormatedString.Append("</span>");
            }
            return htmlFormatedString.ToString();
        }
@JonathanBourassa

This comment has been minimized.

Copy link

@JonathanBourassa JonathanBourassa commented Aug 8, 2018

Just an other addition if you're running this code with a FTB modded server increase the var buffer = new byte[4096]; to var buffer = new byte[32768]; FTB respond with a lot of info including an extensive mod list array.
N.B. For n00bs that's increasing the buffer from 4K to 32K. Don't worry @csh code is so clean it can handle the change.

@BlinkSun

This comment has been minimized.

Copy link

@BlinkSun BlinkSun commented Sep 25, 2018

can someone help me with 1.13.1 ... look like the DeserializeObject did'nt work, dont know why, is'nt my Newtonsoft.Json version too recent ?

Newtonsoft.Json.JsonReaderException: 'Error reading string. Unexpected token: StartObject. Path 'description', line 1, position 16.'

@csh

This comment has been minimized.

Copy link
Owner Author

@csh csh commented Oct 5, 2018

@JonathanBourassa nice HTML snippet to make this that bit sweeter!
Cheers for mentioning the mod list, it's not something I considered throwing this together, I'll bump the amount in the gist and link your comment for explanation.

@BlinkSun are you able to gist a sample of the returned JSON and link it? I'm unaware if the protocol has changed as I've not been actively following Minecraft for quite some time now. I do plan on doing some work with it soon though.

@hexxone

This comment has been minimized.

Copy link

@hexxone hexxone commented Oct 19, 2018

It seems the "description" changed from being a string to being an object with additional parameters, wich causes an error with newtonsoft lib.
It now contains "extra" as an object array and "text" as string.
Each "extra-object" will have the parameters: "color" and or "strikethrough" aswell as "text".

Hope this helps :)

@hexxone

This comment has been minimized.

Copy link

@hexxone hexxone commented Oct 19, 2018

P.S.:
the base-info-object also got new params "modinfo" and "modList", but I cant really tell how theyre used yet

@Xogush

This comment has been minimized.

Copy link

@Xogush Xogush commented Oct 23, 2018

Im trying to use the program to connect to a server but it cant deserialize the string.
image
This is throwing an error because of the first ":".
Can someone help me with this?

@ForeverZer0

This comment has been minimized.

Copy link

@ForeverZer0 ForeverZer0 commented Mar 31, 2019

Ran this, and it worked well, but as far as implementation in a larger scale project with a more varied range of values used, I don't see where this accounts for converting the endian where necessary. According to the spec, all values are big-endian with the exception of VarInt and VarLong.

So shouldn't this....

		internal static void WriteShort(short value)
		{
			_buffer.AddRange(BitConverter.GetBytes(value));
		}

....be something more like this?

		internal static void WriteShort(short value)
		{
			var bytes = BitConverter.GetBytes(value);
			if (BitConverter.IsLittleEndian)
				Array.Reverse(bytes);
			_buffer.AddRange(BitConverter.GetBytes(value));
		}

EDIT:
Strangely enough, did some testing, and when I sent the port as big-endian (on a little endian machine), it does not respond correctly.. The spec clearly states that all values are big-endian, so this is slightly confusing to me, but do think it would be nice to be able to omit the extra overhead of swapping endian.

@Justin99b

This comment has been minimized.

Copy link

@Justin99b Justin99b commented Aug 20, 2019

Im trying to use the program to connect to a server but it cant deserialize the string.
image
This is throwing an error because of the first ":".
Can someone help me with this?

@Xogush they changed the value from "description" to a JObject some point.

Just replace
[JsonProperty(PropertyName = "description")]
with

[JsonProperty(PropertyName = "description")]
public JObject Description { get; set; }

public string Motd {
	get { return Description.GetValue("text").ToString(); }
}

somewhere arround at line 249.

(if you know a better way to get the path let me know (im still lerning ^^))

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

kaboom.pw wont connect for me.

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

image
I get this error when trying to connect to mccentral.org or mc.snapcraft.net

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

but PLAY.ROYALLEGACY.NET works for me can anyone tell me why this happens

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

I tried pinging each and it looked like they all reply the same
image

also it seems that servers that have waterfall: in the title in the server list work, but others don't because reasons?

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

also how would you ping commands and read chat

@xCOOLxGUYx

This comment has been minimized.

Copy link

@xCOOLxGUYx xCOOLxGUYx commented Jul 12, 2020

Like if I wanted too ping '"/plugins" and then see the output that the server pings back. How would I do that

@Firewolf06

This comment has been minimized.

Copy link

@Firewolf06 Firewolf06 commented Jul 14, 2020

When I run this I get an error at line 124: Console.WriteLine("Software: {0}", ping.Version.Name);
It says: System.NullReferenceException: 'Object reference not set to an instance of an object.' ping was null.
Can anyone help me with this?

@jwoff78

This comment has been minimized.

Copy link

@jwoff78 jwoff78 commented Jul 17, 2020

When I run this I get an error at line 124: Console.WriteLine("Software: {0}", ping.Version.Name);
It says: System.NullReferenceException: 'Object reference not set to an instance of an object.' ping was null.
Can anyone help me with this?

I had same problem, in debug I learned the json tree, and I solved it by
public string Motd { get { return (string)Description["extra"][0]["text"]; } }

@laolarou726

This comment has been minimized.

Copy link

@laolarou726 laolarou726 commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which cause the deserialize to fail. How can I fix this problem?

@do-loop

This comment has been minimized.

Copy link

@do-loop do-loop commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which cause the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

// buffer.ToArray();
@laolarou726

This comment has been minimized.

Copy link

@laolarou726 laolarou726 commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which cause the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

@do-loop

This comment has been minimized.

Copy link

@do-loop do-loop commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which cause the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

Replace original code (98-100 line) with this one.

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

... also don't forget add buffer.ToArray() in the next lines where it's necessary, but better use different variable.

For example:

var batch = new byte[4096];
var bufferTemp = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    bufferTemp .AddRange(batch);

    if (!_stream.DataAvailable) break;
}

var buffer = bufferTemp.ToArray();
@laolarou726

This comment has been minimized.

Copy link

@laolarou726 laolarou726 commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which causes the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

Replace original code (98-100 line) with this one.

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

... also don't forget add buffer.ToArray() in the next lines where it's necessary, but better use different variable.

For exeample:

var batch = new byte[4096];
var bufferTemp = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    bufferTemp .AddRange(batch);

    if (!_stream.DataAvailable) break;
}

var buffer = bufferTemp.ToArray();

Unfortunately, the code still can not fetch the complete JSON string. Are there any other solutions?

@do-loop

This comment has been minimized.

Copy link

@do-loop do-loop commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which causes the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

Replace original code (98-100 line) with this one.

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

... also don't forget add buffer.ToArray() in the next lines where it's necessary, but better use different variable.
For exeample:

var batch = new byte[4096];
var bufferTemp = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    bufferTemp .AddRange(batch);

    if (!_stream.DataAvailable) break;
}

var buffer = bufferTemp.ToArray();

Unfortunately, the code still can not fetch the complete JSON string. Are there any other solutions?

Can you send image with debug info?
image

@laolarou726

This comment has been minimized.

Copy link

@laolarou726 laolarou726 commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which causes the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

Replace original code (98-100 line) with this one.

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

... also don't forget add buffer.ToArray() in the next lines where it's necessary, but better use different variable.
For exeample:

var batch = new byte[4096];
var bufferTemp = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    bufferTemp .AddRange(batch);

    if (!_stream.DataAvailable) break;
}

var buffer = bufferTemp.ToArray();

Unfortunately, the code still can not fetch the complete JSON string. Are there any other solutions?

image
image

@do-loop

This comment has been minimized.

Copy link

@do-loop do-loop commented Jan 20, 2021

I just tested this code using "mc.hypixel.net". It seems that the server did not return the complete JSON at one time. Which causes the deserialize to fail. How can I fix this problem?

Hi, try collect all data from stream like this:

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!stream.DataAvailable) break;
}

// buffer.ToArray();

Could you please give a more specific place that I need to replace? (Maybe the line of the code is better). Thank you so much!

Replace original code (98-100 line) with this one.

var batch = new byte[4096];
var buffer = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    buffer.AddRange(batch);

    if (!_stream.DataAvailable) break;
}

... also don't forget add buffer.ToArray() in the next lines where it's necessary, but better use different variable.
For exeample:

var batch = new byte[4096];
var bufferTemp = new List<byte>();

while (true)
{
    _stream.Read(batch, 0, batch.Length);

    bufferTemp .AddRange(batch);

    if (!_stream.DataAvailable) break;
}

var buffer = bufferTemp.ToArray();

Unfortunately, the code still can not fetch the complete JSON string. Are there any other solutions?

image
image

I get it. It also doesn't work for me in some cases.
The solution is almost correct, loop's working more faster than network communication (DataAvailable property depends on it).
If set breakpoint on line 122 and wait some time and so on you will read full response.
It remains to figure out how to fix this problem.

See more: https://stackoverflow.com/questions/4261365/tcpclient-getstream-dataavailable-returns-false-but-stream-has-more-data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment