I did this as a refresher for raw sockets, and the TCP/IP stack. Written in C#, the following class can be used to tally the amount of time spent waiting for a site. It measures the time between the request, an HTTP GET, and the end of the response, the TCP FIN.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net; // for IPEndPoint
using System.Net.Sockets; // for socket
using System.IO;
namespace User.Network
{
class SocketMonitor
{
// members
private bool _bIsRunning;
private DateTime _dtLastReset;
private DateTime _dtTimeStart;
private DateTime _dtTimeEnd;
private TimeSpan _tsCumulative;
private TimeSpan _tsMax;
private TimeSpan _tsMin;
private TimeSpan _tsLast;
// properties
public IPAddress ipaTarget { get; private set; }
public int iPort { get; private set; }
public DateTime dtLastReset
{
get
{
return _dtLastReset;
}
private set
{
_dtLastReset = value;
}
}
public TimeSpan tsCumulative
{
get
{
return _tsCumulative;
}
private set
{
_tsCumulative = value;
}
}
public TimeSpan tsMax
{
get
{
return _tsMax;
}
private set
{
_tsMax = value;
}
}
public TimeSpan tsMin
{
get
{
return _tsMin;
}
private set
{
_tsMin = value;
}
}
public TimeSpan tsLast
{
get
{
return _tsLast;
}
private set
{
_tsLast = value;
}
}
// constructor
public SocketMonitor(IPAddress target, int port)
{
ipaTarget = target;
iPort = port;
_bIsRunning = false;
_dtTimeStart = DateTime.MinValue;
_dtTimeEnd = DateTime.MinValue;
Reset();
}
// member methods
// timer control
public void Reset()
{
tsCumulative = TimeSpan.Zero;
tsMax = TimeSpan.Zero;
tsMin = TimeSpan.MaxValue;
tsLast = TimeSpan.Zero;
dtLastReset = DateTime.Now;
}// of method Reset()
private void Start()
{
if (!_bIsRunning)
{
_bIsRunning = true;
_dtTimeStart = DateTime.Now;
}
}// of method Start()
private void Stop()
{
if(_bIsRunning)
{
_bIsRunning = false;
_dtTimeEnd = DateTime.Now;
TimeSpan duration = _dtTimeEnd - _dtTimeStart;
if (duration > TimeSpan.Zero)
{
tsLast = duration;
tsCumulative += duration;
if (duration > tsMax) tsMax = duration;
if (duration < tsMin) tsMin = duration;
Console.WriteLine("{0} Total: {1}, Max: {2}, Min: {3}, Last: {4}",
DateTime.Now.ToShortTimeString(), tsCumulative, tsMax, tsMin, tsLast);
}
}
}// of method Stop()
// executable
// much of this taken from here: https://social.msdn.microsoft.com/Forums/en-US/6d19f326-0d8f-4672-90f9-29d3497fc803/raw-sockets-promiscuous-mode-only-sees-datagrams-tofrom-single-machine?forum=ncl
public void Run()
{
int len_receive_buf = 4096;
byte[] receive_buf = new byte[len_receive_buf];
int cout_receive_bytes;
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
socket.Blocking = false;
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
socket.ReceiveBufferSize = 65535;
// the following linq frag was found here: http://stackoverflow.com/questions/1069103/how-to-get-my-own-ip-address-in-c
IPAddress thisMachine = Dns.GetHostEntry(Dns.GetHostName()).AddressList.
Where(o => o.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).First();
IPEndPoint ipEP = new IPEndPoint(thisMachine, 0); //(IPAddress.Any, 0);
socket.Bind(ipEP);
// found this here: http://www.progamercity.net/code-tut/5370-c-creating-simple-network-sniffer.html
byte[] byTrue = new byte[4] { 1, 0, 0, 0 };
byte[] byOut = new byte[4];
socket.IOControl(IOControlCode.ReceiveAll, byTrue, byOut);
while (true)
{
IAsyncResult ar =
socket.BeginReceive(receive_buf, 0, len_receive_buf, SocketFlags.None, null, this);
cout_receive_bytes = socket.EndReceive(ar);
Receive(receive_buf, cout_receive_bytes);
}
}// of method Run()
private void Receive(byte[] buf, int len)
{
if ((len >= 20) && ((buf[0] >> 4) == 4))
{
//check IPv4 only; header info
int IHL = buf[0] & 0xf; // number of words in header
int byIHL = IHL * 4; // number of bytes in header
IPAddress ipSender = new IPAddress((long)BitConverter.ToUInt32(buf, 12));
IPAddress ipReceiver = new IPAddress((long)BitConverter.ToUInt32(buf, 16));
// here are the protocol numbers: http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
if (buf[9] == 6)
{
// tcp = 6; header info
int sourcePort = buf[byIHL] << 8 | buf[byIHL + 1];
int destPort = buf[byIHL + 2] << 8 | buf[byIHL + 3];
int dataOffset = buf[byIHL + 12] >> 4; // number of words in TCP header
int flags = (buf[byIHL + 12] & 1) << 8 | buf[byIHL + 13];
int byDataOffset = (dataOffset * 4) + byIHL; // offset past the IP & tcp headers
if ((ipReceiver.ToString() == ipaTarget.ToString()) && (destPort == iPort))
{
// from us -- looking for the GET in the payload
if (len > byDataOffset)
{
// a payload exists
byte[] payload = new byte[len - byDataOffset];
for (int index = 0; index < len - byDataOffset; index++)
{
payload[index] = buf[index + byDataOffset];
}
string outline1 = Encoding.ASCII.GetString(payload);
if (outline1.TrimStart().ToUpper().StartsWith("GET"))
{
// found the get... start the timer
Start();
}
}
}
if ((ipSender.ToString() == ipaTarget.ToString()) && (sourcePort == iPort))
{
// to us -- looking for a FIN flag (flags, bit 0)
if ((flags & 1) == 1)
{
// found the fin... stop the timer & save
Stop();
}
}
}
}
}// of method Receive(byte[], int)
}
}
Have fun!
Steve
2015-03-11
Breakpoints
Getting breakpoints to work with Classic ASP and ASP.NET 2.0, with IIS running locally.
- Ensure web.config has debug="True"
- Ensure that you are attaching to the correct w3wp.exe process
- Ensure that the App Pool configuration that is associated with this site in IIS has Maximum Worker Processes set to 1 (found in the Process Model section).
- Ensure that the ASP configuration for the site in IIS allows Client and Server debugging (found in the Debugging Properties section).
- Ensure that machine.config does not have retail="True" in the deployment tag. The default for this attribute is false, which will permit debugging.
Subscribe to:
Posts (Atom)