С#: Как выполнить HTTP-запрос с использованием сокетов?
Я пытаюсь сделать HTTP request
с помощью сокетов. Мой код выглядит следующим образом:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class test
{
public static void Main(String[] args)
{
string hostName = "127.0.0.1";
int hostPort = 9887;
int response = 0;
IPAddress host = IPAddress.Parse(hostName);
IPEndPoint hostep = new IPEndPoint(host, hostPort);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(hostep);
string request_url = "http://127.0.0.1/register?id=application/vnd-fullphat.test&title=My%20Test%20App";
response = sock.Send(Encoding.UTF8.GetBytes(request_url));
response = sock.Send(Encoding.UTF8.GetBytes("\r\n"));
bytes = sock.Receive(bytesReceived, bytesReceived.Length, 0);
page = page + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
Console.WriteLine(page);
sock.Close();
}
}
Теперь, когда я выполняю вышеуказанный код, ничего не происходит, тогда как при вводе моего request_url
в браузере я получаю уведомление от Snarl о том, что Application Registered
и ответ, который я получаю от браузера,
SNP/2.0/0/OK/556
Ответ, который я получаю от моего кода, SNP/3.0/107/BadPacket
.
Итак, что не так с моим кодом.
Спецификация формата запроса Snarl
Ответы
Ответ 1
В конце вы должны указать длину содержимого и двойную новую строку, чтобы указать конец заголовка.
var request = "GET /register?id=application/vnd-fullphat.test&title=My%20Test%20App HTTP/1.1\r\n" +
"Host: 127.0.0.1\r\n" +
"Content-Length: 0\r\n" +
"\r\n";
Спецификацию HTTP 1.1 можно найти здесь: http://www.w3.org/Protocols/rfc2616/rfc2616.html
Ответ 2
Я ничего не знаю о SNP. Ваш код немного запутан в принимающей части. Я использовал приведенный ниже пример для отправки и чтения ответа сервера для запроса HTTP GET. Сначала рассмотрим запрос, а затем рассмотрим ответ.
Запрос HTTP GET:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Accept: text/html
User-Agent: CSharpTests
string - "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: keep-alive\r\nAccept: text/html\r\nUser-Agent: CSharpTests\r\n\r\n"
Заголовок HTTP-ответа сервера:
HTTP/1.1 200 OK
Date: Sun, 07 Jul 2013 17:13:10 GMT
Server: Apache/2.4.4 (Win32) OpenSSL/0.9.8y PHP/5.4.16
Last-Modified: Sat, 30 Mar 2013 11:28:59 GMT
ETag: \"ca-4d922b19fd4c0\"
Accept-Ranges: bytes
Content-Length: 202
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
string - "HTTP/1.1 200 OK\r\nDate: Sun, 07 Jul 2013 17:13:10 GMT\r\nServer: Apache/2.4.4 (Win32) OpenSSL/0.9.8y PHP/5.4.16\r\nLast-Modified: Sat, 30 Mar 2013 11:28:59 GMT\r\nETag: \"ca-4d922b19fd4c0\"\r\nAccept-Ranges: bytes\r\nContent-Length: 202\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n"
Я намеренно омрачил тело ответа сервера, потому что мы уже знаем, что это точно 202 байта, как указано в Content-Length в заголовке ответа.
Просмотр спецификации HTTP показывает, что заголовок HTTP заканчивается пустой новой строкой ( "\ r\n\r\n" ). Поэтому нам просто нужно его искать.
Посмотрите на код в действии. Предположим, что переменный сокет типа System.Net.Sockets.Socket.
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("127.0.0.1", 80);
string GETrequest = "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: keep-alive\r\nAccept: text/html\r\nUser-Agent: CSharpTests\r\n\r\n";
socket.Send(Encoding.ASCII.GetBytes(GETrequest));
Мы отправили запрос на сервер, чтобы получить и правильно разобрать ответ.
bool flag = true; // just so we know we are still reading
string headerString = ""; // to store header information
int contentLength = 0; // the body length
byte[] bodyBuff = new byte[0]; // to later hold the body content
while (flag)
{
// read the header byte by byte, until \r\n\r\n
byte[] buffer = new byte[1];
socket.Receive(buffer, 0, 1, 0);
headerString += Encoding.ASCII.GetString(buffer);
if (headerString.Contains("\r\n\r\n"))
{
// header is received, parsing content length
// I use regular expressions, but any other method you can think of is ok
Regex reg = new Regex("\\\r\nContent-Length: (.*?)\\\r\n");
Match m = reg.Match(headerString);
contentLength = int.Parse(m.Groups[1].ToString());
flag = false;
// read the body
bodyBuff = new byte[contentLength];
socket.Receive(bodyBuff, 0, contentLength, 0);
}
}
Console.WriteLine("Server Response :");
string body = Encoding.ASCII.GetString(bodyBuff);
Console.WriteLine(body);
socket.Close();
Это, пожалуй, самый худший способ сделать это на С#, есть тонны классов для обработки HTTP-запросов и ответов в .NET, но, если вам это нужно, он работает.
Ответ 3
Ваш запрос неверен. Согласно wikipedia, запрос HTTP Get должен выглядеть так:
string request = "GET /register?id=application/vnd-fullphat.test&title=My%20Test%20App HTTP/1.1\r\nHost: 127.0.0.1\r\n";
Ответ 4
Минимальное требование для HTTP-запроса
"GET/HTTP/1.0\r\n\r\n" (если удаление хоста разрешено).
Но в SNARL вы должны ввести длину содержимого (что я больше всего слышал).
Итак,
Socket sck = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
sck.Connect(ip, port);
sck.Send(Encoding.UTF8.GetBytes("THE HTTP REQUEST HEADER"));
Console.WriteLine("SENT");
string message = null;
byte[] bytesStored = new byte[ReceiveBufferSize];
int k1 = sck.Receive(bytesStored);
for (int i = 0; i < k1; i++)
{
message = message + Convert.ToChar(bytesStored[i]).ToString();
}
Console.WriteLine(message); // PRINT THE RESPONSE
EDIT: Я очень сожалею о предыдущем плохом ответе. Он был неконформирован, и я добавил основную идею/решение ответа (нет простой информации). Кроме того, я добавил исходный код.
Я тестировал несколько сайтов и отлично работает. Если это не сработало, вы должны исправить это, добавив больше заголовков (скорее всего, решение).