SOCKS5 serveris raksta četrus baitus atsevišķi, un klients darbojas tikai pēc tam, kad šīs rakstīšanas ir apvienotas. Apvienošana var mainīt laiku, taču TCP joprojām nesola vienu lasījumu uz katru rakstīšanu.

Klientam ir vajadzīgs atbildes parsētājs. Pēc metodes izvēles un jebkuras nepieciešamās autentifikācijas SOCKS5 komandas atbilde sākas ar četriem baitiem: versija, rezultāts, rezervētais baits un adreses tips. Atlikušais garums ir atkarīgs no šī adreses tipa.

.NET 7+ parsētājs, kuram jāpatērē tikai veiksmīga CONNECT atbilde, var izmantot:

static async Task ReadConnectReply(Stream stream, CancellationToken ct)
{
    byte[] prefix = new byte[4];
    await stream.ReadExactlyAsync(prefix, ct);
    if (prefix[0] != 5 || prefix[2] != 0)
        throw new IOException("Invalid SOCKS5 reply");
    if (prefix[1] != 0)
        throw new IOException($"SOCKS5 request failed: {prefix[1]}");

    int remaining;
    switch (prefix[3])
    {
        case 1: remaining = 4 + 2; break;
        case 4: remaining = 16 + 2; break;
        case 3:
            byte[] length = new byte[1];
            await stream.ReadExactlyAsync(length, ct);
            remaining = length[0] + 2;
            break;
        default:
            throw new IOException("Unknown SOCKS5 address type");
    }
    await stream.ReadExactlyAsync(new byte[remaining], ct);
}

Pēdējie divi baiti ir piesaistītais ports. IPv4 nepieciešami četri baiti; IPv6 nepieciešami sešpadsmit; domēna adrese pirms nosaukuma satur garuma baitu.

Norādiet atcelšanas marķieri ar paredzēto sarunu termiņu. ReadExactlyAsync apstrādā īsākus atsevišķus lasījumus un izmet izņēmumu, kad straume beidzas pirms pieprasītā garuma. Neveiksmes gadījumā atmetiet neizdevušos savienojumu, izmantojot tā īpašnieka tīrīšanas ceļu.

Veiksmes gadījumā apstājieties pie atbildes robežas. Baits pēc tās pieder galamērķa protokolam. Lielākam spekulatīvam lasījumam ir jāsaglabā liekie baiti, nevis jāizmet lietojumprogrammas straumes sākums.

Saistītie raksti