C# Socket Programming - How to determine the size of the receive buffer
I a开发者_JS百科m trying to write a simple console app that POSTs to a page and outputs the returned html to the console.
The code I have works, but it only returns part of the response. The only way I can figure out to make it work is to set the byte buffer to a size I know is big enough for the content being returned.
Is there anyway to check how big the buffer needs to be in order to receive the complete response?
Here is the code...
Uri uri = new Uri(@"http://bobssite/");
// Get the IPAddress of the website we are going to and create the EndPoint
IPAddress ipAddress = Dns.GetHostEntry(uri.Host).AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddress, 80);
// Create a new Socket instance and open the socket for communication
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
socket.Connect(endPoint);
// Attempt to send the request
int byteCount = 0;
try
{
string requestString =
"POST " + uri.PathAndQuery + " HTTP/1.1\r\n" +
"Host: " + uri.Host + "\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Content-Length: 11\r\n" +
"\r\n" +
"user=bob";
byte[] bytesToSend = Encoding.ASCII.GetBytes(requestString);
byteCount = socket.Send(bytesToSend, SocketFlags.None);
}
catch (SocketException se)
{
Console.WriteLine(se.Message);
}
// Attempt to receive the response
if (byteCount > 0)
{
byte[] bytesReceived = new byte[256];
try
{
byteCount = socket.Receive(bytesReceived, SocketFlags.None);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("HELP!! --> " + e.Message);
}
// Out the html we received
string html = Encoding.ASCII.GetString(bytesReceived);
Console.WriteLine(html);
}
else
{
Console.WriteLine("byteCount is zero!");
}
Console.Read();
This is overkill for just making a POST! All your code might work but using WebClient
will make the call reduced to a couple of lines.
The point with TCP sockets is that you keep reading until you receive an identifier to close the session. Now that you are using HTTP, this is by reading the headers and finding the value of content-length
and reading the exact byte length from the stream and there is no identifier for closing the session.
Generally speaking, you'd read from a socket in a loop until there's no data left. If you want to avoid that, you could first read a chunk guesstimated to be large enough to contain the HTTP response headers, parse out the Content-Length line, and use the result to allocate your next buffer--but this seems like a pain.
Is there a reason you're doing this at such a low level instead of using the WebClient class?
You might want to check the Content-Length value in the response header.
Also, the server may be sending the data using chunked transfer encoding which allows it to begin transmitting before it knows the actual length (e.g. for data being compressed on the fly).
See also the RFC for HTTP protocol.
I put the Receive call inside a loop to keep calling receive until the received bytes is zero and appended the data returned into a string variable.
Working Code....
Uri uri = new Uri(@"http://bobssite/");
// Get the IPAddress of the website we are going to and create the EndPoint
IPAddress ipAddress = Dns.GetHostEntry(uri.Host).AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddress, 80);
// Create a new Socket instance and open the socket for communication
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
socket.Connect(endPoint);
// Attempt to send the request
int byteCount = 0;
try
{
string requestString =
"POST " + uri.PathAndQuery + " HTTP/1.1\r\n" +
"Host: " + uri.Host + "\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Content-Length: 11\r\n" +
"\r\n" +
"user=bob";
byte[] bytesToSend = Encoding.ASCII.GetBytes(requestString);
byteCount = socket.Send(bytesToSend, SocketFlags.None);
}
catch (SocketException se)
{
Console.WriteLine(se.Message);
}
// Attempt to receive the response
if (byteCount > 0)
{
byte[] bytesReceived = new byte[256];
string page = "";
try
{
while (byteCount > 0)
{
byteCount = socket.Receive(bytesReceived, SocketFlags.None);
page += Encoding.ASCII.GetString(bytesReceived);
Array.Clear(bytesReceived, 0, bytesReceived.Length);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("HELP!! --> " + e.Message);
}
// Out the html we received
Console.WriteLine(page);
}
else
{
Console.WriteLine("byteCount is zero!");
}
Console.Read();
精彩评论