Mp4 streaming with c# asp.net - c#

I am developing a system that makes mp4 stream with c # asp.net. Chromium-based browsers can stream videos without error, but firefox and internet explorer can not stream videos. I response http request with byte array (partial 206). here is the code Where does the problem come from
thanks.
/// source code
/// Base on
/// http://videostreamer.codeplex.com/
int KBps;
switch (res)
{
case NResolution.HD1080p:
KBps = 1250000;
break;
case NResolution.HD720p:
KBps = 750000; break;
case NResolution.HD480p:
KBps = 750000; break;
case NResolution.HD320p:
KBps = 400000; break;
case NResolution.HD144p:
KBps = 200000; break;
default:
KBps = 200000; break;
}
using (var reader = new FileStream(fullpath,FileMode.Open,FileAccess.Read,FileShare.Read,KBps,FileOptions.SequentialScan))
{
var size = reader.Length;
var end = size - 1;
var start = 0;
Int64 anotherStart = 0;
Int64 anotherEnd = 0;
resp.AddHeader("Accept-Ranges","0-"+size.ToString());
resp.StatusCode = 206;
var rng = req.Headers.Get("Range");
if (!string.IsNullOrEmpty(rng))
{
if (rng.IndexOf(",") > -1)
{
resp.AddHeader("Content-Range","bytes " + start + "-" + end +"/" + size);
throw new HttpException(416,"Error...");
}
if (rng.StartsWith("-"))
{
anotherStart = Int64.Parse(rng.Substring(1));
}
else
{
anotherStart = Int64.Parse(rng.Split('=')[1].Split('-')[0]);
}
if (anotherStart + KBps <= end)
{
anotherEnd = anotherStart + KBps;
}
else
{
anotherEnd = end;
}
var length = anotherEnd - anotherStart + 1 ;
resp.AddHeader("Content-Range","bytes " + anotherStart + "-" +anotherEnd + "/" + size);
resp.AddHeader("Content-Length",length.ToString());
var buf = new byte[length];
reader.Seek(anotherStart, SeekOrigin.Begin);
reader.Read(buf, 0, buf.Length);
resp.OutputStream.Write(buf,0,buf.Length);
resp.Flush();
resp.End();
}
resp.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
resp.AddHeader("Content-Length", "0");
}

How are you setting the request header 'Range'. Please check that.

Related

Unity 3D Object Rotation with MPU6050

Basically, I am calibrating and applying offsets within unity. But the range of rotation isn't accurate and I'm wondering if its because of the wrong sensitivity application. I wanted help figuring out a way to stabilize the rotation as well as increase the range of rotation as it goes only form 0-90 and it shakes a lot.
Unity Code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
public class MPU6050_3 : MonoBehaviour
{
public GameObject target;
SerialPort stream = new SerialPort("COM3", 115200);
string[] accgyValues = new string[10];
int buffersize = 1000; //Amount of readings used to average, make it higher to get more precision but sketch will be slower (default:1000)
int acel_deadzone = 2; //Acelerometer error allowed, make it lower to get more precision, but sketch may not converge (default:8)
int giro_deadzone = 1; //Giro error allowed, make it lower to get more precision, but sketch may not converge (default:1)
float ax, ay, az, gx, gy, gz, gx_f, gy_f, gz_f;
float mean_ax, mean_ay, mean_az, mean_gx, mean_gy, mean_gz, state = 0;
float ax_offset = 0, ay_offset = 0, az_offset = 0, gx_offset = 0, gy_offset = 0, gz_offset = 0;
bool cal;
public float factor = 1;
public bool enableRotation;
public bool enableTranslation;
//float acc_normalizer_factor = 0.00025f;
float gyro_normalizer_factor = 1.0f/65.5f;
void Awake()
{
stream.Open();
//stream.ReadTimeout=50;
}
void Update()
{
if (state == 0)
{
accel();
Debug.Log("\nReading sensors for first time...");
state++;
Debug.Log("State is:"+state);
}
else if (state == 1)
{
Debug.Log("\nCalculating offsets...");
calibration();
state++;
Debug.Log("State is:" + state);
}
else if (state == 2)
{
accel();
Debug.Log("SensorW/Offset:" + mean_ax + ":" + mean_ay + ":" + mean_az + ":" + mean_gx + ":" + mean_gy + ":" + mean_gz);
Debug.Log("Offset:" + ax_offset + ":" + ay_offset + ":" + az_offset + ":" + gx_offset + ":" + gy_offset + ":" + gz_offset);
state++;
Debug.Log("State is:" + state);
}
else if (state == 3)
{
getaccgy();
//if (enableTranslation) target.transform.position = new Vector3(ax+ax_offset, az-az_offset, ay-ay_offset);
gx_f = (gx + gx_offset) * gyro_normalizer_factor;
gy_f = (gy + gy_offset) * gyro_normalizer_factor;
gz_f = -(gz + gz_offset) * gyro_normalizer_factor ;
if (enableRotation) target.transform.rotation = Quaternion.Euler(gx_f * factor, gz_f * factor, gy_f * factor);
Debug.Log("ValueRot "+ gx_f +" " + gy_f + " " + gz_f);
Debug.Log("State is:" + state);
}
}
public void getaccgy()
{
stream.Write("r");
Debug.Log("In accel");
string value;
accgyValues = new string[10];
value = stream.ReadLine();
accgyValues = value.Split(",");
ax = int.Parse(accgyValues[0]); //* acc_normalizer_factor;
ay = int.Parse(accgyValues[1]); //* acc_normalizer_factor;
az = int.Parse(accgyValues[2]); //* acc_normalizer_factor;
gx = int.Parse(accgyValues[3]); //* gyro_normalizer_factor;
gy = int.Parse(accgyValues[4]); //* gyro_normalizer_factor;
gz = int.Parse(accgyValues[5]); //* gyro_normalizer_factor;
Debug.Log("GetACCGY");
Debug.Log("SensorW/Offset:" + ax + ":" + ay + ":" + az + ":" + gx + ":" + gy + ":" + gz);
}
void accel()
{
float i = 0f, buff_ax = 0f, buff_ay = 0f, buff_az = 0f, buff_gx = 0f, buff_gy = 0f, buff_gz = 0f;
while (i < 1101)
{
getaccgy();
if (cal)
{
ax = ax + ax_offset;
ay = ay + ay_offset;
az = az + az_offset;
gx = gx + gx_offset;
gy = gy + gy_offset;
gz = gz + gz_offset;
}
if (i > 99 && i < (buffersize + 100))
{ //First 100 measures are discarded
buff_ax += ax;
buff_ay += ay;
buff_az += az;
buff_gx += gx;
buff_gy += gy;
buff_gz += gz;
}
if (i == (buffersize + 100))
{
mean_ax = buff_ax / buffersize;
mean_ay = buff_ay / buffersize;
mean_az = buff_az / buffersize;
mean_gx = buff_gx / buffersize;
mean_gy = buff_gy / buffersize;
mean_gz = buff_gz / buffersize;
Debug.Log("Mean:" + mean_ax + ":" + mean_ay + ":" + mean_az + ":" + mean_gx + ":" + mean_gy + ":" + mean_gz);
}
i++;
Debug.Log("Mean Sensor");
Debug.Log("Buffer Size is" + buffersize + "i mean" + i);
Debug.Log("SensorW/Offset:" + ax + ":" + ay + ":" + az + ":" + gx + ":" + gz);
}
}
void calibration()
{
cal = true;
Debug.Log("Callibration Entered");
ax_offset = -mean_ax / 8;
ay_offset = -mean_ay / 8;
az_offset = (16384 - mean_az) / 8;
gx_offset = -mean_gx / 4;
gy_offset = -mean_gy / 4;
gz_offset = -mean_gz / 4;
int ready = 0;
while (ready < 7)
{
//accelgyro.setXAccelOffset(ax_offset);
//accelgyro.setYAccelOffset(ay_offset);
//accelgyro.setZAccelOffset(az_offset);
//accelgyro.setXGyroOffset(gx_offset);
//accelgyro.setYGyroOffset(gy_offset);
//accelgyro.setZGyroOffset(gz_offset);
accel();
Debug.Log("..." + ready);
if (Math.Abs(mean_ax) <= acel_deadzone) ready++;
else ax_offset = ax_offset - mean_ax / acel_deadzone;
if (Math.Abs(mean_ay) <= acel_deadzone) ready++;
else ay_offset = ay_offset - mean_ay / acel_deadzone;
if (Math.Abs(16384 - mean_az) <= acel_deadzone) ready++;
else az_offset = az_offset + (16384 - mean_az) / acel_deadzone;
if (Math.Abs(mean_gx) <= giro_deadzone) ready++;
else gx_offset = gx_offset - mean_gx / (giro_deadzone + 1);
if (Math.Abs(mean_gy) <= giro_deadzone) ready++;
else gy_offset = gy_offset - mean_gy / (giro_deadzone + 1);
if (Math.Abs(mean_gz) <= giro_deadzone) ready++;
else gz_offset = gz_offset - mean_gz / (giro_deadzone + 1);
if (ready == 6) break;
}
}
}
Arduino Code:
Just a simple code to get the raw values:
// I2Cdev and MPU6050 must be installed as libraries
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
/////////////////////////////////// CONFIGURATION /////////////////////////////
//Change this 3 variables if you want to fine tune the skecth to your needs.
int buffersize=1000; //Amount of readings used to average, make it higher to get more precision but sketch will be slower (default:1000)
int acel_deadzone=8; //Acelerometer error allowed, make it lower to get more precision, but sketch may not converge (default:8)
int giro_deadzone=1; //Giro error allowed, make it lower to get more precision, but sketch may not converge (default:1)
// default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
//MPU6050 accelgyro;
MPU6050 accelgyro(0x68); // <-- use for AD0 high
int16_t ax, ay, az,gx, gy, gz;
int mean_ax,mean_ay,mean_az,mean_gx,mean_gy,mean_gz,state=0;
int ax_offset,ay_offset,az_offset,gx_offset,gy_offset,gz_offset;
/////////////////////////////////// SETUP ////////////////////////////////////
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
Wire.begin();
// COMMENT NEXT LINE IF YOU ARE USING ARDUINO DUE
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz). Leonardo measured 250kHz.
// initialize serial communication
Serial.begin(115200);
// initialize device
accelgyro.initialize();
//wait for ready
//while (Serial.available() && Serial.read()); // empty buffer
//while (!Serial.available()){
//Serial.println(F("Send any character to start sketch.\n"));
//delay(1500);
//}
//while (Serial.available() && Serial.read()); // empty buffer again
}
// start message
//Serial.println("\nMPU6050 Calibration Sketch");
//delay(2000);
//Serial.println("\nYour MPU6050 should be placed in horizontal position, with package letters facing up. \nDon't touch it until you see a finish message.\n");
//delay(3000);
// verify connection
//Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
//delay(1000);
// reset offsets
//accelgyro.setXAccelOffset(0);
//accelgyro.setYAccelOffset(0);
//accelgyro.setZAccelOffset(0);
//accelgyro.setXGyroOffset(0);
//accelgyro.setYGyroOffset(0);
//accelgyro.setZGyroOffset(0);
void loop() {
if(Serial.available() > 0)
{
char ltr = Serial.read();
if(ltr == 'r')
{
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
Serial.print(ax);
Serial.print(",");
Serial.print(ay);
Serial.print(",");
Serial.print(az);
Serial.print(",");
Serial.print(gx);
Serial.print(",");
Serial.print(gy);
Serial.print(",");
Serial.println(gz);
Serial.flush();
}
}
}

DeviceCapabilities generates error: data is invalid

I want to get a printer's list of paper source, paper size, etc.
I slightly modified the codes from http://www.pinvoke.net/default.aspx/Enums/DeviceCapabilities.html?diff=y
The codes sometimes work, sometimes not.
The proplem is DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null) returns -1. the last error is "data is invalid"
Restart computer may not solve the problem. Once getting the problem, next time maybe OK maybe not.
So what is the problem here?
ArrayList arrBinName;
string sError = "";
GetBins("\\Lindy-PC.MyCpmpany.local\HP LaserJet 4000 Series PCL 5", "LPT1", out arrBinName, out sError);
public static bool GetBins(string DeviceName, string strPort, out ArrayList BinName, out string strError)
{
strError = "";
BinName = new ArrayList();
IntPtr pAddr = default(IntPtr);
int offset = 0;
int nRes = DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null); //Returns -1
if (nRes >= 0)
{
try
{
pAddr = Marshal.AllocHGlobal((int)nRes * 24);
nRes = DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, pAddr, (IntPtr)null);
if (nRes < 0)
{
strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "[" + DeviceName + ": " + strPort + ".DC_BINNAMES]";
return false;
}
offset = pAddr.ToInt32();
for (int i = 0; i < nRes; i++)
{
BinName.Add(Marshal.PtrToStringAnsi(new IntPtr(offset + i * 24)));
}
}
finally
{
Marshal.FreeHGlobal(pAddr);
}
}
else
strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "[" + DeviceName + ": " + strPort + ".DC_BINNAMES]";
return true;
}
As aggaton mentioned in his or her comment, DeviceCapabilities requires two calls in certain circumstances and retrieving bin names is one of them. You should first read the documentation for DeviceCapabilities.
Then go back and look at the sample code you used. You omitted a key step:
// BinNames
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null);
pAddr = Marshal.AllocHGlobal((int)nRes * 24);
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, pAddr, (IntPtr)null);
if(nRes < 0)
{
strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "["+ strDeviceName +": "+ strPort +"]";
return false;
}
Notice that there are three calls to DeviceCapabilities in that code. You need all three. (I think the code would be clearer by making each call a separate line of code but that's a style issue.) The doc for DeviceCapabilities plus the sample code above should get you back on track.

Audio Streaming from MemoryStream

I have made an audio streaming handler. It works fine on a 64-bit windows machine.
On a 32-bit machine when using IE and fiddler the audio gets stuck after some audio plays and the audio tag generates error MEDIA_ERR_DECODE.
Streaming code is as below:
public void ProcessRequest(HttpContext context)
{
try
{
//context.Response.Headers.Clear();
string strBrowser = context.Request.Browser.Browser.ToUpper();
string strFileName = Path.GetFileNameWithoutExtension(context.Request.FilePath);
string mimetype;
MemoryStream audioStream = null;
if (strFileName != null && strFileName.Length > 0)
{
switch (strBrowser)
{
case "FIREFOX":
mimetype = "audio/ogg";
break;
default:
mimetype = "audio/mpeg";
break;
}
Dictionary<string, StreamDetails> mapStreamDetails =
(Dictionary<string,StreamDetails>)context.Application["StreamDetails"];
StreamDetails streamDetails = null;
if (mapStreamDetails.ContainsKey(strFileName))
{
streamDetails = mapStreamDetails[strFileName];
}
if (streamDetails != null && streamDetails.AudioStream !=null)
{
audioStream = streamDetails.AudioStream;
context.Response.ContentType = mimetype;
if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
{
//request for chunk
RangeDownload(audioStream, context);
}
else
{
//ask for all
long fileLength = audioStream.Length;//File.OpenRead(fullpath).Length;
context.Response.AddHeader("Content-Length", fileLength.ToString());
byte[] responseBytes = new byte[(int)audioStream.Length];
audioStream.Read(responseBytes, 0, (int)audioStream.Length);
context.Response.BinaryWrite(responseBytes);
}
}
else
{
throw new HttpException(404, "audio stream not found : " + strFileName);
}
}
else
{
context.Response.Write("Invalid request");
}
}
catch (Exception ex)
{
Common.DebugWriteLine("Exception occured" + ex.Message + ex.StackTrace);
}
}
private void RangeDownload(MemoryStream audioStream, HttpContext context)
{
long size, start, end, length, fp = 0;
byte[] responseBytes = null;
size = audioStream.Length;
start = 0;
end = size - 1;
length = size;
context.Response.AddHeader("Accept-Ranges", "0-" + size);
if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
{
long anotherStart = start;
long anotherEnd = end;
string[] arr_split =
context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] {
Convert.ToChar("=") });
string range = arr_split[1];
// Make sure the client hasn't sent us a multibyte range
if (range.IndexOf(",") > -1)
{
// (?) Shoud this be issued here, or should the first
// range be used? Or should the header be ignored and
// we output the whole content?
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end +
"/" + size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
// If the range starts with an '-' we start from the beginning
// If not, we forward the file pointer
// And make sure to get the end byte if spesified
if (range.StartsWith("-"))
{
// The n-number of the last bytes is requested
anotherStart = size - Convert.ToInt64(range.Substring(1));
}
else
{
arr_split = range.Split(new char[] { Convert.ToChar("-") });
anotherStart = Convert.ToInt64(arr_split[0]);
long temp = 0;
anotherEnd = (arr_split.Length > 1 &&
Int64.TryParse(arr_split[1].ToString(),out temp)) ?
Convert.ToInt64(arr_split[1]) : size;
}
// End bytes can not be larger than end.
anotherEnd = (anotherEnd > end) ? end : anotherEnd;
// Validate the requested range and return an error if it's not correct.
if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
{
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end +"/"
+ size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
start = anotherStart;
end = anotherEnd;
length = end - start + 1; // Calculate new content length
fp = audioStream.Seek(start, SeekOrigin.Begin);
context.Response.StatusCode = 206;
responseBytes = new byte[(int)length];
audioStream.Read(responseBytes, (int)0, (int)length);
}
// Notify the client the byte range we'll be outputting
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" +
size);
context.Response.AddHeader("Content-Length", length.ToString());
try
{
if (responseBytes != null)
{
context.Response.BinaryWrite(responseBytes);
}
}
catch (Exception ex)
{
Common.DebugWriteLine("Exception occured in streaming data : " + ex.Message +
"Trace : " + ex.StackTrace);
}
}

Faster than String.Replace()

Is there any other method that is faster than doing like this?
private void EscapeStringSequence(ref string data)
{
data = data.Replace("\\", "\\\\"); // Backslash
data = data.Replace("\r", "\\r"); // Carriage return
data = data.Replace("\n", "\\n"); // New Line
data = data.Replace("\a", "\\a"); // Vertical tab
data = data.Replace("\b", "\\b"); // Backspace
data = data.Replace("\f", "\\f"); // Formfeed
data = data.Replace("\t", "\\t"); // Horizontal tab
data = data.Replace("\v", "\\v"); // Vertical tab
data = data.Replace("\"", "\\\""); // Double quotation mark
data = data.Replace("'", "\\'"); // Single quotation mark
}
-- Edited (Add explanation) --
Q1: Is there a reason why you need to speed it up? Is it causing a huge problem?
This part is used in this project: http://mysqlbackuprestore.codeplex.com/
I'm going to loop lots of various length of strings into this function repeatly. The whole process takes around 6-15 seconds to finished for millions of rows. There are other part get involve too. I'm trying to speed up every part.
Q2: How slow is it now?
OK, I'll capture the exact time used and post it here. I'll come back later. (will post the result tomorrow)
Update 29-06-2012
I have run test. This is the result:
Speed Test: String.Replace() - measured in miliseconds
Test 1: 26749.7531 ms
Test 2: 27063.438 ms
Test 3: 27753.8884 ms
Average: 27189.0265 ms
Speed: 100%
Speed Test: Foreach Char and Append - measured in miliseconds
Test 1: 8468.4547 ms
Test 2: 8348.8527 ms
Test 3: 8353.6476 ms
Average: 8390.3183 ms
Speed: 224% < faster
===================================
Update - Next Test (Another round)
===================================
------
Test Replace String Speed.
Test 1: 26535.6466
Test 2: 26379.6464
Test 3: 26379.6463
Average: 26431.6464333333
Speed: 100%
------
Test Foreach Char String Append.
Test 1: 8502.015
Test 2: 8517.6149
Test 3: 8595.6151
Average: 8538.415
Speed: 309.56%
------
Test Foreach Char String Append (Fix StringBuilder Length).
Test 1: 8314.8146
Test 2: 8330.4147
Test 3: 8346.0146
Average: 8330.41463333333
Speed: 317.29%
Conclusion:
Using Foreach Char Loop and Append is faster than String.Replace().
Thanks you very much guys.
--------
Below are the codes that I used to run the test: (edited)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.Write("Press any key to continue...");
Console.ReadKey();
Console.Write("\r\nProcess started.");
Test();
Console.WriteLine("Done.");
Console.Read();
}
public static Random random = new Random((int)DateTime.Now.Ticks);
public static string RandomString(int size)
{
StringBuilder sb = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
sb.Append(ch);
}
return sb.ToString();
}
public static void Test()
{
string text = "\\_\r\n\a\b\f\t\v\"'" + RandomString(2000) + "\\_\r\n\a\b\f\t\v\"'" + RandomString(2000);
List<TimeSpan> lstTimeUsed = new List<TimeSpan>();
int target = 100000;
for (int i = 0; i < 3; i++)
{
DateTime startTime = DateTime.Now;
for (int j = 0; j < target; j++)
{
if (j.ToString().EndsWith("000"))
{
Console.Clear();
Console.WriteLine("Test " + i.ToString());
Console.WriteLine(j.ToString() + " of " + target.ToString());
}
string data = text;
data = data.Replace("\\", "\\\\"); // Backslash
data = data.Replace("\r", "\\r"); // Carriage return
data = data.Replace("\n", "\\n"); // New Line
data = data.Replace("\a", "\\a"); // Vertical tab
data = data.Replace("\b", "\\b"); // Backspace
data = data.Replace("\f", "\\f"); // Formfeed
data = data.Replace("\t", "\\t"); // Horizontal tab
data = data.Replace("\v", "\\v"); // Vertical tab
data = data.Replace("\"", "\\\""); // Double quotation mark
data = data.Replace("'", "\\'"); // Single quotation mark
}
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
lstTimeUsed.Add(ts);
}
double t1 = lstTimeUsed[0].TotalMilliseconds;
double t2 = lstTimeUsed[1].TotalMilliseconds;
double t3 = lstTimeUsed[2].TotalMilliseconds;
double tOri = (t1 + t2 + t3) / 3;
System.IO.TextWriter tw = new System.IO.StreamWriter("D:\\test.txt", true);
tw.WriteLine("------");
tw.WriteLine("Test Replace String Speed. Test Time: " + DateTime.Now.ToString());
tw.WriteLine("Test 1: " + t1.ToString());
tw.WriteLine("Test 2: " + t2.ToString());
tw.WriteLine("Test 3: " + t3.ToString());
tw.WriteLine("Average: " + tOri.ToString());
tw.WriteLine("Speed: 100%");
tw.Close();
lstTimeUsed = new List<TimeSpan>();
for (int i = 0; i < 3; i++)
{
DateTime startTime = DateTime.Now;
for (int j = 0; j < target; j++)
{
if (j.ToString().EndsWith("000"))
{
Console.Clear();
Console.WriteLine("Test " + i.ToString());
Console.WriteLine(j.ToString() + " of " + target.ToString());
}
string data = text;
var builder = new StringBuilder();
foreach (var ch in data)
{
switch (ch)
{
case '\\':
case '\r':
case '\n':
case '\a':
case '\b':
case '\f':
case '\t':
case '\v':
case '\"':
case '\'':
builder.Append('\\');
break;
default:
break;
}
builder.Append(ch);
}
}
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
lstTimeUsed.Add(ts);
}
t1 = lstTimeUsed[0].TotalMilliseconds;
t2 = lstTimeUsed[1].TotalMilliseconds;
t3 = lstTimeUsed[2].TotalMilliseconds;
tw = new System.IO.StreamWriter("D:\\test.txt", true);
tw.WriteLine("------");
tw.WriteLine("Test Foreach Char String Append. Test Time: " + DateTime.Now.ToString());
tw.WriteLine("Test 1: " + t1.ToString());
tw.WriteLine("Test 2: " + t2.ToString());
tw.WriteLine("Test 3: " + t3.ToString());
tw.WriteLine("Average: " + ((t1 + t2 + t3) / 3).ToString());
tw.WriteLine("Speed: " + ((tOri) / ((t1 + t2 + t3) / 3) * 100).ToString("0.00") + "%");
tw.Close();
lstTimeUsed = new List<TimeSpan>();
for (int i = 0; i < 3; i++)
{
DateTime startTime = DateTime.Now;
for (int j = 0; j < target; j++)
{
if (j.ToString().EndsWith("000"))
{
Console.Clear();
Console.WriteLine("Test " + i.ToString());
Console.WriteLine(j.ToString() + " of " + target.ToString());
}
string data = text;
var builder = new StringBuilder(data.Length + 20);
foreach (var ch in data)
{
switch (ch)
{
case '\\':
case '\r':
case '\n':
case '\a':
case '\b':
case '\f':
case '\t':
case '\v':
case '\"':
case '\'':
builder.Append('\\');
break;
default:
break;
}
builder.Append(ch);
}
}
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
lstTimeUsed.Add(ts);
}
t1 = lstTimeUsed[0].TotalMilliseconds;
t2 = lstTimeUsed[1].TotalMilliseconds;
t3 = lstTimeUsed[2].TotalMilliseconds;
tw = new System.IO.StreamWriter("D:\\test.txt", true);
tw.WriteLine("------");
tw.WriteLine("Test Foreach Char String Append (Fix StringBuilder Length). Test Time: " + DateTime.Now.ToString());
tw.WriteLine("Test 1: " + t1.ToString());
tw.WriteLine("Test 2: " + t2.ToString());
tw.WriteLine("Test 3: " + t3.ToString());
tw.WriteLine("Average: " + ((t1 + t2 + t3) / 3).ToString());
tw.WriteLine("Speed: " + ((tOri) / ((t1 + t2 + t3) / 3) * 100).ToString("0.00") + "%");
tw.Close();
}
}
}
var builder = new StringBuilder(data.Length + 20);
foreach (var ch in data)
{
switch (ch)
{
case '\\':
case '\r':
...
builder.Append('\\');
break;
}
builder.Append(ch);
}
return builder.ToString();
Try using a series of StringBuilder calls.

How to get mx records for a dns name with System.Net.DNS? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 1 year ago.
Improve this question
Is there any built in method in the .NET library that will return all of the MX records for a given domain? I see how you get CNAMES, but not MX records.
Update 2018/5/23:
Check out MichaC's answer for a newer library that has .NET standard support.
Original Answer:
The ARSoft.Tools.Net library by Alexander Reinert seems to do the job pretty well.
It's available from NuGet:
PM> Install-Package ARSoft.Tools.Net
Import the namespace:
using ARSoft.Tools.Net.Dns;
Then making a synchronous lookup is as simple as:
var resolver = new DnsStubResolver();
var records = resolver.Resolve<MxRecord>("gmail.com", RecordType.Mx);
foreach (var record in records) {
Console.WriteLine(record.ExchangeDomainName?.ToString());
}
Which gives us the output:
gmail-smtp-in.l.google.com.
alt1.gmail-smtp-in.l.google.com.
alt2.gmail-smtp-in.l.google.com.
alt3.gmail-smtp-in.l.google.com.
alt4.gmail-smtp-in.l.google.com.
Underneath the hood, it looks like the library constructs the UDP (or TCP) packets necessary to send to the resolver, like you might expect. The library even has logic (invoked with DnsClient.Default) to discover which DNS server to query.
Full documentation can be found here.
Just roled my own library because there was nothing for .net core / xplat support... https://github.com/MichaCo/DnsClient.NET
It works pretty great and gives you dig like log messages if you want.
Simple to use
var lookup = new LookupClient();
var result = await lookup.QueryAsync("google.com", QueryType.ANY);
and works with custom servers running on any ports, multiple servers, etc...
see also DnsClient Website for more details
I spent all day figuring out how to send/receive dns requests and came up with this. Its a complete generic handler. You just have to set the dns server and pass in 'd' eg. my.website.com?d=itmanx.com
<%# WebHandler Language="C#" Class="Handler" %>
using System;
using System.Web;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
public class Handler : IHttpHandler
{
string dns = "dc1"; //change to your dns
string qtype = "15"; //A=1 MX=15
string domain = "";
int[] resp;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
try
{
if (context.Request["t"] != null) qtype = context.Request["t"];
if (context.Request["d"] != null) domain = context.Request["d"];
if (string.IsNullOrEmpty(domain)) throw new Exception("Add ?d=<domain name> to url or post data");
Do(context);
}
catch (Exception ex)
{
string msg = ex.Message;
if (msg == "1") msg = "Malformed packet";
else if (msg == "5") msg = "Refused";
else if (msg == "131") msg = "No such name";
context.Response.Write("Error: " + msg);
}
}
public void Do(HttpContext context)
{
UdpClient udpc = new UdpClient(dns, 53);
// SEND REQUEST--------------------
List<byte> list = new List<byte>();
list.AddRange(new byte[] { 88, 89, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 });
string[] tmp = domain.Split('.');
foreach (string s in tmp)
{
list.Add(Convert.ToByte(s.Length));
char[] chars = s.ToCharArray();
foreach (char c in chars)
list.Add(Convert.ToByte(Convert.ToInt32(c)));
}
list.AddRange(new byte[] { 0, 0, Convert.ToByte(qtype), 0, 1 });
byte[] req = new byte[list.Count];
for (int i = 0; i < list.Count; i++) { req[i] = list[i]; }
udpc.Send(req, req.Length);
// RECEIVE RESPONSE--------------
IPEndPoint ep = null;
byte[] recv = udpc.Receive(ref ep);
udpc.Close();
resp = new int[recv.Length];
for (int i = 0; i < resp.Length; i++)
resp[i] = Convert.ToInt32(recv[i]);
int status = resp[3];
if (status != 128) throw new Exception(string.Format("{0}", status));
int answers = resp[7];
if (answers == 0) throw new Exception("No results");
int pos = domain.Length + 18;
if (qtype == "15") // MX record
{
while (answers > 0)
{
int preference = resp[pos + 13];
pos += 14; //offset
string str = GetMXRecord(pos, out pos);
context.Response.Write(string.Format("{0}: {1}\n", preference, str));
answers--;
}
}
else if (qtype == "1") // A record
{
while (answers > 0)
{
pos += 11; //offset
string str = GetARecord(ref pos);
context.Response.Write(string.Format("{0}\n", str));
answers--;
}
}
}
//------------------------------------------------------
private string GetARecord(ref int start)
{
StringBuilder sb = new StringBuilder();
int len = resp[start];
for (int i = start; i < start + len; i++)
{
if (sb.Length > 0) sb.Append(".");
sb.Append(resp[i + 1]);
}
start += len + 1;
return sb.ToString();
}
private string GetMXRecord(int start, out int pos)
{
StringBuilder sb = new StringBuilder();
int len = resp[start];
while (len > 0)
{
if (len != 192)
{
if (sb.Length > 0) sb.Append(".");
for (int i = start; i < start + len; i++)
sb.Append(Convert.ToChar(resp[i + 1]));
start += len + 1;
len = resp[start];
}
if (len == 192)
{
int newpos = resp[start + 1];
if (sb.Length > 0) sb.Append(".");
sb.Append(GetMXRecord(newpos, out newpos));
start++;
break;
}
}
pos = start + 1;
return sb.ToString();
}
//------------------------------------------------------
public bool IsReusable { get { return false; } }
}
My approach was to use nslookup.exe to retreive the MX record.
The solution is not as fancy as rewriting whole DNS or using a System DLL -> but it works, with a little amount of lines.
To get things right, this code >just works< it's not ressource efficient nor fast and has a lots of room for improvment (multiple hostnames, async, more usefull return value,adding the priority):
static List<string> GetMxRecords(string host){
ProcessStartInfo nslookup_config = new ProcessStartInfo("nslookup.exe");
nslookup_config.RedirectStandardInput = true;
nslookup_config.RedirectStandardOutput = true;
nslookup_config.RedirectStandardError = true;
nslookup_config.UseShellExecute = false;
var nslookup = Process.Start(nslookup_config);
nslookup.StandardInput.WriteLine("set q=mx");
nslookup.StandardInput.WriteLine(host);
nslookup.StandardInput.WriteLine("exit");
List<string> lines = new List<string>();
while (!nslookup.StandardOutput.EndOfStream)
{
string l = nslookup.StandardOutput.ReadLine();
if (l.Contains("internet address ="))
{
while (l.Contains("\t\t"))
{
l = l.Replace("\t\t", "\t");
}
lines.Add(l.Replace("\tinternet address = ","="));
}
}
nslookup.Close();
return lines;
}
Should be working international, since nslookup does not support any translation (I'm working on a German machine and I'm getting english output).
The result are strings like this:
alt4.gmail-smtp-in.l.google.com=74.125.28.27
alt2.gmail-smtp-in.l.google.com=74.125.200.27
alt1.gmail-smtp-in.l.google.com=209.85.233.26
gmail-smtp-in.l.google.com=66.102.1.27
alt3.gmail-smtp-in.l.google.com=108.177.97.27
The accepted answer doesn't work for .NET framework < 4.5, so would suggest that those of you who can't use ARSOFT.Tools can use DNDNs from https://dndns.codeplex.com
Given below is a console application that returns the MX record for a given domain modifying their examples.
using System;
using System.Net.Sockets;
using DnDns.Enums;
using DnDns.Query;
using DnDns.Records;
namespace DnDnsExamples
{
class Program
{
static void Main(string[] args)
{
DnsQueryRequest request3 = new DnsQueryRequest();
DnsQueryResponse response3 = request3.Resolve("gmail.com", NsType.MX, NsClass.INET, ProtocolType.Tcp);
OutputResults(response3);
Console.ReadLine();
}
private static void OutputResults(DnsQueryResponse response)
{
foreach (IDnsRecord record in response.Answers)
{
Console.WriteLine(record.Answer);
Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength);
Console.WriteLine(" |--- Name: " + record.DnsHeader.Name);
Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass);
Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType);
Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive);
Console.WriteLine();
}
}
}
}
Here is a Class I use to look up MX records only.
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Specialized;
namespace Mx.Dns
{
public class Query
{
//Build a DNS query buffer according to RFC 1035 4.1.1 e 4.1.2
private readonly int id;
private readonly int flags;
private readonly int QDcount;
private readonly int ANcount;
private readonly int NScount;
private readonly int ARcount;
private readonly string Qname;
private readonly int Qtype;
private readonly int Qclass;
public byte[] buf;
public Query(int ID, string query, int qtype)
{
//init vectors with given + default values
id = ID;
flags = 256;
QDcount = 1;
ANcount = 0;
NScount = 0;
ARcount = 0;
Qname = query;
Qtype = qtype;
Qclass = 1; //Internet = IN = 1
//build a buffer with formatted query data
//header information (16 bit padding
buf = new byte[12 + Qname.Length + 2 + 4];
buf[0] = (byte)(id / 256);
buf[1] = (byte)(id - (buf[0] * 256));
buf[2] = (byte)(flags / 256);
buf[3] = (byte)(flags - (buf[2] * 256));
buf[4] = (byte)(QDcount / 256);
buf[5] = (byte)(QDcount - (buf[4] * 256));
buf[6] = (byte)(ANcount / 256);
buf[7] = (byte)(ANcount - (buf[6] * 256));
buf[8] = (byte)(NScount / 256);
buf[9] = (byte)(NScount - (buf[8] * 256));
buf[10] = (byte)(ARcount / 256);
buf[11] = (byte)(ARcount - (buf[10] * 256));
//QNAME (RFC 1035 4.1.2)
//no padding
string[] s = Qname.Split('.');
int index = 12;
foreach (string str in s) {
buf[index] = (byte)str.Length;
index++;
byte[] buf1 = Encoding.ASCII.GetBytes(str);
buf1.CopyTo(buf, index);
index += buf1.Length;
}
//add root domain label (chr(0))
buf[index] = 0;
//add Qtype and Qclass (16 bit values)
index = buf.Length - 4;
buf[index] = (byte)(Qtype / 256);
buf[index + 1] = (byte)(Qtype - (buf[index] * 256));
buf[index + 2] = (byte)(Qclass / 256);
buf[index + 3] = (byte)(Qclass - (buf[index + 2] * 256));
}
}
public class C_DNSquery
{
public StringCollection result = new StringCollection();
public int Error = 0;
public string ErrorTxt = "undefined text";
public bool Done = false;
public UdpClient udpClient;
private string DNS;
private string Query;
private int Qtype;
public bool IS_BLACKLIST_QUERY = false;
public C_DNSquery(string IPorDNSname, string query, int type)
{
DNS = IPorDNSname;
Query = query;
Qtype = type;
}
public void doTheJob()
{
//check if provided DNS contains an IP address or a name
IPAddress ipDNS;
IPHostEntry he;
try {
//try to parse an IPaddress
ipDNS = IPAddress.Parse(DNS);
} catch (FormatException ) {
// Console.WriteLine(e);
//format error, probably is a FQname, try to resolve it
try {
//try to resolve the hostname
he = Dns.GetHostEntry(DNS);
} catch {
//Error, invalid server name or address
Error = 98;
ErrorTxt = "Invalid server name:" + DNS;
Done = true;
return;
}
//OK, get the first server address
ipDNS = he.AddressList[0];
}
//Query the DNS server
//our current thread ID is used to match the reply with this process
Query myQuery = new Query(System.Threading.Thread.CurrentThread.ManagedThreadId, Query, Qtype);
//data buffer for query return value
Byte[] recBuf;
//use UDP protocol to connect
udpClient = new UdpClient();
do {
try {
//connect to given nameserver, port 53 (DNS)
udpClient.Connect(DNS, 53);
//send query
udpClient.Send(myQuery.buf, myQuery.buf.Length);
//IPEndPoint object allow us to read datagrams..
//..selecting only packet coming from our nameserver and port
IPEndPoint RemoteIpEndPoint = new IPEndPoint(ipDNS, 53);
//Blocks until a message returns on this socket from a remote host.
recBuf = udpClient.Receive(ref RemoteIpEndPoint);
udpClient.Close();
} catch (Exception e) {
//connection error, probably a wrong server address
udpClient.Close();
Error = 99;
ErrorTxt = e.Message + "(server:" + DNS + ")";
Done = true;
return;
}
//repeat until we get the reply with our threadID
} while (System.Threading.Thread.CurrentThread.ManagedThreadId != ((recBuf[0] * 256) + recBuf[1]));
//Check the DNS reply
//check if bit QR (Query response) is set
if (recBuf[2] < 128) {
//response byte not set (probably a malformed packet)
Error = 2;
ErrorTxt = "Query response bit not set";
Done = true;
return;
}
//check if RCODE field is 0
if ((recBuf[3] & 15) > 0) {
//DNS server error, invalid reply
switch (recBuf[3] & 15) {
case 1:
Error = 31;
ErrorTxt = "Format error. The nameserver was unable to interpret the query";
break;
case 2:
Error = 32;
ErrorTxt = "Server failure. The nameserver was unable to process the query.";
break;
case 3:
Error = 33;
ErrorTxt = "Name error. Check provided domain name!!";
break;
case 4:
Error = 34;
ErrorTxt = "Not implemented. The name server does not support the requested query";
break;
case 5:
Error = 35;
ErrorTxt = "Refused. The name server refuses to reply for policy reasons";
break;
default:
Error = 36;
ErrorTxt = "Unknown. The name server error code was: " + Convert.ToString((recBuf[3] & 15));
break;
}
Done = true;
return;
}
//OK, now we should have valid header fields
int QDcnt, ANcnt, NScnt, ARcnt;
int index;
QDcnt = (recBuf[4] * 256) + recBuf[5];
ANcnt = (recBuf[6] * 256) + recBuf[7];
NScnt = (recBuf[8] * 256) + recBuf[9];
ARcnt = (recBuf[10] * 256) + recBuf[11];
index = 12;
//sometimes there are no erros but blank reply... ANcnt == 0...
if (ANcnt == 0) { // if blackhole list query, means no spammer !!//if ((ANcnt == 0) & (IS_BLACKLIST_QUERY == false))
//error blank reply, return an empty array
Error = 4;
ErrorTxt = "Empty string array";
Done = true;
return;
}
//Decode received information
string s1;
// START TEST
s1 = Encoding.ASCII.GetString(recBuf, 0, recBuf.Length);
// END TEST
if (QDcnt > 0) {
//we are not really interested to this string, just parse and skip
s1 = "";
index = parseString(recBuf, index, out s1);
index += 4; //skip root domain, Qtype and QClass values... unuseful in this contest
}
if (IS_BLACKLIST_QUERY) {
// get the answers, normally one !
// int the four last bytes there is the ip address
Error = 0;
int Last_Position = recBuf.Length - 1;
result.Add(recBuf[Last_Position - 3].ToString() + "." + recBuf[Last_Position - 2].ToString() + "." + recBuf[Last_Position - 1].ToString() + "." + recBuf[Last_Position].ToString());
Done = true;
return;
}
int count = 0;
//get all answers
while (count < ANcnt) {
s1 = "";
index = parseString(recBuf, index, out s1);
//Qtype
int QType = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + QType.ToString();
//QClass
int QClass = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + QClass.ToString();
//TTL (Time to live)
uint TTL = (recBuf[index] * 16777216u) + (recBuf[index + 1] * 65536u) + (recBuf[index + 2] * 256u) + recBuf[index + 3];
index += 4;
s1 += "," + TTL.ToString();
int blocklen = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
if (QType == 15) {
int MXprio = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + MXprio.ToString();
}
string s2;
index = parseString(recBuf, index, out s2);
s1 += "," + s2;
result.Add(s1);
count++;
}
Error = 0;
Done = true;
}
private int parseString(byte[] buf, int i, out string s)
{
int len;
s = "";
bool end = false;
while (!end) {
if (buf[i] == 192) {
//next byte is a pointer to the string, get it..
i++;
s += getString(buf, buf[i]);
i++;
end = true;
} else {
//next byte is the string length
len = buf[i];
i++;
//get the string
s += Encoding.ASCII.GetString(buf, i, len);
i += len;
//check for the null terminator
if (buf[i] != 0) {
//not null, add a point to the name
s += ".";
} else {
//null char..the string is complete, exit
end = true;
i++;
}
}
}
return i;
}
private string getString(byte[] buf, int i)
{
string s = "";
int len;
bool end = false;
while (!end) {
len = buf[i];
i++;
s += Encoding.ASCII.GetString(buf, i, len);
i += len;
if (buf[i] == 192) {
i++;
s += "." + getString(buf, buf[i]);
return s;
}
if (buf[i] != 0) {
s += ".";
} else {
end = true;
}
}
return s;
}
}
}
Here is how you use it.
/// <summary>
/// Get the MX from the domain address.
/// </summary>
public static string getMXrecord(string domain)
{
domain = domain.Substring(domain.IndexOf('#') + 1);
string LocalDNS = GetDnsAdress().ToString();
Console.WriteLine("domain: " + domain);
// resolv the authoritative domain (type=2)
C_DNSquery DnsQry = new C_DNSquery(LocalDNS, domain, 2);
Thread t1 = new Thread(new ThreadStart(DnsQry.doTheJob));
t1.Start();
int timeout = 20;
while ((timeout > 0) & (!DnsQry.Done)) {
Thread.Sleep(100);
timeout--;
}
if (timeout == 0) {
if (DnsQry.udpClient != null) {
DnsQry.udpClient.Close();
}
t1.Abort();
DnsQry.Error = 100;
}
string[] ns1;
string MyNs = "";
if (DnsQry.Error == 0) {
ns1 = DnsQry.result[0].Split(',');
MyNs = ns1[4];
t1.Abort();
} else {
t1.Abort();
MyNs = LocalDNS;
}
// Resolve MX (type = 15)
DnsQry = new C_DNSquery(MyNs, domain, 15);
Thread t2 = new Thread(new ThreadStart(DnsQry.doTheJob));
t2.Start();
timeout = 20;
string TTL = "";
string MXName = "";
Int32 preference = 9910000;
while ((timeout > 0) & (!DnsQry.Done)) {
Thread.Sleep(100);
timeout--;
}
if (timeout == 0) {
if (DnsQry.udpClient != null) {
DnsQry.udpClient.Close();
}
t2.Abort();
DnsQry.Error = 100;
}
if (DnsQry.Error == 0) {
if (DnsQry.result.Count == 1) {
string[] ns2 = DnsQry.result[0].Split(',');
MXName = ns2[5];
TTL = ns2[3];
preference = Int32.Parse(ns2[4]);
Console.WriteLine("domaine: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('#') + 1), MXName,
DateTime.Now, preference, TTL);
} else {
for (int indns = 0; indns <= DnsQry.result.Count - 1; indns++) {
string[] ns2 = DnsQry.result[indns].Split(',');
if (Int32.Parse(ns2[4]) < preference) {
MXName = ns2[5];
TTL = ns2[3];
preference = Int32.Parse(ns2[4]);
Console.WriteLine("domain: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('#') + 1), MXName,
DateTime.Now, preference, TTL);
}
}
}
}
return MXName;
}
I wrote a simply URL for that means
https://devselz.com/social/sign/buttons/dashboard/default.aspx?a=ciee&email=emailaddresstocheckifexistsornot#anydomain.com
Do not abuse
Return 1 if email exists or may exist, 0 if not
Works great in order to check:
gmail and gmail pro (domains not #gmail) accounts.
hotmail
For others like yahoo always returns 1
You can use this open source library to do almost any kind of query you would usually need.
Usage:
DnsClient dnsClient = new DnsClient();
string mxDomain = dnsClient.ResolveMX("example.com");
string mxDomainIP = dnsClient.ResolveMX("example.com", true);
string mxDomainIPv6 = dnsClient.ResolveMX("example.com", true, true);

Categories