C#:如何使用套接字执行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请求格式规范

您必须在最后包含content-length和double new line以指示标题的结尾。

 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

我对SNP一无所知。 您的代码在接收部分有点混乱。 我使用示例bellow来发送和读取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 \ 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(); 

这可能是在C#中执行此操作的最糟糕的方法,在.NET中有大量的类来处理HTTP请求和响应,但如果您需要它,它仍然有效。

您的要求不正确。 根据维基百科,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"; 

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 

编辑:我很抱歉以前的糟糕答案。 它没有制定,我添加了答案的主要想法/解决方案(没有简单的信息)。 另外,我添加了源代码。

我在几个网站上测试过,效果很好。 如果它不起作用,那么你应该通过添加更多标题(最可能的解决方案)来修复它。