singrdk/base/Windows/TcpBlast/TcpBlastWin.cs

389 lines
11 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: TcpBlast.cs
//
using System;
using System.Net;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
static class TcpBlast
{
public static int Main(string[] args)
{
try {
Dictionary<String, String> namedargs;
string[] posargs;
ParseArgs(args, out namedargs, out posargs);
if (posargs.Length == 0) {
Usage();
return 1;
}
if (posargs[0] == "accept") {
return Accept(namedargs);
}
else if (posargs[0] == "connect") {
return Connect(namedargs);
}
else {
Usage();
return 1;
}
}
catch (Exception ex) {
ShowException(ex);
return 1;
}
}
static void Usage()
{
Console.WriteLine("This program tests TCP/IP implementations by sending or receiving");
Console.WriteLine("known sequences of bytes.");
Console.WriteLine();
Console.WriteLine("Usage:");
Console.WriteLine();
Console.WriteLine(" tcpblast accept [-port:<port>]");
Console.WriteLine(" tcpblast connect -dest:<ipaddress> [-port:<port>]");
}
static void ParseArgs(
string[] rawargs,
out Dictionary<String, String> namedargs,
out string[] posargs)
{
Dictionary<String, String> namedlist = new Dictionary<String, String>();
List<String> poslist = new List<String>();
foreach (string arg in rawargs) {
if (String.IsNullOrEmpty(arg)) {
continue;
}
if (arg[0] == '/' || arg[0] == '-') {
int separator = arg.IndexOf(':', 1);
if (separator == -1) {
separator = arg.IndexOf('=', 1);
}
string name;
string value;
if (separator != -1) {
name = arg.Substring(1, separator - 1);
value = arg.Substring(separator + 1);
}
else {
name = arg.Substring(1);
value = "";
}
namedlist[name] = value;
}
else {
poslist.Add(arg);
}
}
namedargs = namedlist;
posargs = poslist.ToArray();
}
static void Connect(string[] args)
{
for (int i = 1; i < args.Length; i++) {
}
}
const int DefaultPort = 4000;
static IInt32SequenceFactory GetSequenceFactory(Dictionary<String, String> args)
{
string name;
if (!args.TryGetValue("seq", out name)) {
return delegate { return new AscendingSequence(0, 1); };
}
IInt32SequenceFactory factory = WellKnownSequences.GetWellKnownSequence(name);
return factory;
}
static int Accept(Dictionary<String, String> args)
{
IInt32SequenceFactory sequenceFactory = GetSequenceFactory(args);
if (sequenceFactory == null) {
Console.WriteLine("Invalid sequence specified.");
return 1;
}
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) {
int port = DefaultPort;
string portString;
if (args.TryGetValue("port", out portString)) {
if (!Int32.TryParse(portString, out port)) {
Console.WriteLine("Invalid port string.");
return 1;
}
}
IPEndPoint any = new IPEndPoint(IPAddress.Any, port);
try { listener.Bind(any); }
catch (Exception ex) {
Console.WriteLine("Bind failed.");
ShowException(ex);
return 1;
}
try { listener.Listen(5); }
catch (Exception ex) {
Console.WriteLine("Listen failed.");
ShowException(ex);
return 1;
}
for (; ; ) {
Socket client;
Console.WriteLine("Waiting for client to connect at port: " + listener.LocalEndPoint);
try { client = listener.Accept(); }
catch (Exception ex) {
Console.WriteLine("Accept failed.");
ShowException(ex);
break;
}
Console.WriteLine("Accepted client.");
try {
RunClient(args, client, sequenceFactory);
}
catch (Exception ex) {
ShowException(ex);
}
finally {
client.Close();
}
Console.WriteLine();
}
}
return 0;
}
static int Connect(Dictionary<String, String> args)
{
IInt32SequenceFactory sequenceFactory = GetSequenceFactory(args);
if (sequenceFactory == null) {
Console.WriteLine("Invalid sequence specified.");
return 1;
}
string destText;
if (!args.TryGetValue("dest", out destText)) {
Console.WriteLine("Connect requires /dest:[xxx] parameter.");
return 1;
}
int port = DefaultPort;
string portString;
if (args.TryGetValue("port", out portString)) {
if (!Int32.TryParse(portString, out port)) {
Console.WriteLine("Invalid port string.");
return 1;
}
}
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try {
try {
socket.Connect(destText, port);
}
catch (Exception ex) {
Console.WriteLine("Failed to connect to '{0}' at port {1}.", destText, port);
ShowException(ex);
return 1;
}
Console.WriteLine("Connected to {0}.", socket.RemoteEndPoint);
RunClient(args, socket, sequenceFactory);
}
finally {
socket.Close();
}
return 0;
}
static void RunClient(Dictionary<String, String> args, Socket client, IInt32SequenceFactory sequenceFactory)
{
Console.WriteLine("Running tests.");
bool blast = args.ContainsKey("blast");
if (blast) {
RunBlast(args, client, sequenceFactory);
}
else {
RunGulp(args, client, sequenceFactory);
}
}
static void RunBlast(Dictionary<String, String> args, Socket client, IInt32SequenceFactory sequenceFactory)
{
Console.WriteLine("Blasting TCP client...");
IInt32Sequence sequence = sequenceFactory();
int blockSize = 5112;
long sequenceNumber = 0;
byte[] block = new byte[blockSize];
RateWatcher rate = new RateWatcher();
for (; ; ) {
for (int i = 0; i < blockSize; i++) {
int f = sequence.GetNext();
block[i] = (byte)(f & 0xff);
// Debug.WriteLine(String.Format("{0,3} -> 0x{1:x}", i, block[i]));
}
int bytesTransferred = client.Send(block, 0, blockSize, SocketFlags.None);
if (bytesTransferred != blockSize) {
Console.WriteLine("The send transferred fewer bytes than requested!");
break;
}
sequenceNumber += blockSize;
rate.AddBytes(blockSize);
}
}
static void RunGulp(Dictionary<String, String> args, Socket client, IInt32SequenceFactory sequenceFactory)
{
Console.WriteLine("Running Gulp.");
IInt32Sequence sequence = sequenceFactory();
long sequenceNumber = 0;
int blockSize = 5112;
byte[] block = new byte[blockSize];
int ticksAtLastPrint = Environment.TickCount;
RateWatcher rate = new RateWatcher();
for (; ; ) {
int bytesRead = client.Receive(block);
if (bytesRead == 0) {
Console.WriteLine("The socket has closed.");
return;
}
// Verify that the contents match the expected sequence.
for (int i = 0; i < bytesRead; i++) {
int f = sequence.GetNext();
byte expected = (byte)(f & 0xff);
if (block[i] != expected) {
Console.WriteLine("Received sequence does not match expected sequence!");
Console.WriteLine("At stream offset {0} (0x{0:x}), expected 0x{1:x}, received 0x{2:x}.",
sequenceNumber,
expected,
block[i]);
return;
}
}
sequenceNumber += bytesRead;
rate.AddBytes(bytesRead);
}
}
class RateWatcher
{
public void AddBytes(int count)
{
_bytesSinceLastReport += count;
int ticksNow = Environment.TickCount;
TimeSpan elapsed = TimeSpan.FromMilliseconds(ticksNow - _ticksAtLastReport);
if (elapsed >= _reportInterval) {
double bytesPerSecond = _bytesSinceLastReport / elapsed.TotalSeconds;
Console.WriteLine("Transfer rate: {0}", BytesPerSecondToString(bytesPerSecond));
_bytesSinceLastReport = 0;
_ticksAtLastReport = ticksNow;
}
}
int _ticksAtLastReport = Environment.TickCount;
long _bytesSinceLastReport;
TimeSpan _reportInterval = TimeSpan.FromSeconds(3);
public TimeSpan ReportInterval
{
get { return _reportInterval; }
set { _reportInterval = value; }
}
public static string BytesPerSecondToString(double bps)
{
if (bps < 1000) {
return String.Format("{0:F3} Bytes/Sec", bps);
}
if (bps < 1e6) {
return String.Format("{0:F3} KBytes/Sec", bps / 1000.0);
}
if (bps < 1e9) {
return String.Format("{0:F3} MBytes/Sec", bps / 1e6);
}
return String.Format("{0:F3} GBytes/Sec", bps / 1e9);
}
}
static void ShowException(Exception ex)
{
Console.WriteLine("{0}: {1}", ex.GetType().FullName, ex.Message);
for (Exception inner = ex.InnerException; inner != null; inner = inner.InnerException) {
Console.WriteLine("{0}: {1}", inner.GetType().FullName, inner.Message);
}
}
}
class AFewPrimes : IInt32Sequence
{
static readonly int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
int index;
public int GetNext()
{
index = (index + 1) % primes.Length;
return primes[index];
}
}