C# Wait until data received and go to next iteration - c#

I'm using Serial Port to get data from device in for loop iteration.
The problem is in loop iteration i need to get data from serial port, validate it and going to the next iteration.
How i can achieved this?
Here are my code :
private void processData()
{
// Loop Procedure
int x = Int32.Parse(master["Cycle"].ToString());
int y = Int32.Parse(master["MinWeight"].ToString());
// Loop for each line
for (int i = this.CLine; i < 2; i++)
{
this.CLine = i;
if (i == 0)
label15.Text = master["LLINE"].ToString();
else
label15.Text = master["RLINE"].ToString();
IDictionary<string, string> dic = (Dictionary<String, String>)master[i.ToString()];
label18.Text = this.CProcess = dic["PROCESSID"];
int z = Int32.Parse(dic["PRODLANE"].ToString());
// Loop for each sampling session (Cycle)
for (int j = this.CCycle; j <= x; j++)
{
this.CCycle = j;
// Loop for production lane
for (int k = this.CLane; k <= z; k++)
{
this.CLane = k;
label16.Text = k.ToString();
// In this section i want to send command over serial port
// get value from my device
// validate it if current weight bellow standard weight
// do it again (get data from device)
// else we can go to next iteration
while (this.CWeight < y)
{
XApi.l("xxx2 " + this.CWeight + " vs " + y + " " + k.ToString() + " " + this.isDataReady);
SendData("Q");
}
// Commit Transaction
// XDb.CommitTrans(this.CCycle.ToString(), dic["LINEID"].ToString(), this.CLane.ToString(), weight.ToString(), this.isTrialStage == true ? "1" : "0");
}
}
}
}
I've tried this
while (this.CWeight < y)
{
XApi.l("xxx2 " + this.CWeight + " vs " + y + " " + k.ToString() + " " + this.isDataReady);
SendData("Q");
}
but it seems blocked UI thread and make my application solaggy.
Anyone can give me some idea? Thanks in advance.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == System.IO.Ports.SerialData.Eof)
return;
// If the com port has been closed, do nothing
if (!comport.IsOpen)
return;
// Update flag data received
this.isDataReady = true;
// Determain which mode (string or binary) the user is in
if (CurrentDataMode == DataMode.Text)
{
// Read all the data waiting in the buffer
string data = comport.ReadExisting();
// Update result
result += data;
if (result.Length > 16)
{
SetText(result.ToString());
}
// Display the text to the user in the terminal
Log(LogMsgType.Incoming, data);
}
else
{
// Obtain the number of bytes waiting in the port's buffer
int bytes = comport.BytesToRead;
// Create a byte array buffer to hold the incoming data
byte[] buffer = new byte[bytes];
// Read the data from the port and store it in our buffer
comport.Read(buffer, 0, bytes);
// Show the user the incoming data in hex format
Log(LogMsgType.Incoming, ByteArrayToHexString(buffer));
}
}
private void SendData(String msg)
{
this.isDataReady = false;
result = "";
if (CurrentDataMode == DataMode.Text)
{
// Send the user's text straight out the port
comport.Write(msg + "\r\n");
// Show in the terminal window the user's text
Log(LogMsgType.Outgoing, msg + "\n");
}
else
{
try
{
// Convert the user's string of hex digits (ex: B4 CA E2) to a byte array
byte[] data = HexStringToByteArray(txtSendData.Text);
// Send the binary data out the port
comport.Write(data, 0, data.Length);
// Show the hex digits on in the terminal window
Log(LogMsgType.Outgoing, ByteArrayToHexString(data) + "\n");
}
catch (FormatException)
{
// Inform the user if the hex string was not properly formatted
Log(LogMsgType.Error, "Not properly formatted hex string: " + txtSendData.Text + "\n");
}
}
}

Anyone can give me some idea?
You can use async/await in your code not to block your UI by writing an extension method like below. Usage would be:
async void SomeMethod()
{
SerialPort serialPort = .......
while (true)
{
serialPort.Write(.....);
var retval = await serialPort.ReadAsync();
}
}
The keyword here is using TaskCompletionSource class with your events...
static public class SerialPortExtensions
{
public static Task<byte[]> ReadAsync(this SerialPort serialPort)
{
var tcs = new TaskCompletionSource<byte[]>();
SerialDataReceivedEventHandler dataReceived = null;
dataReceived = (s, e) =>
{
serialPort.DataReceived -= dataReceived;
var buf = new byte[serialPort.BytesToRead];
serialPort.Read(buf, 0, buf.Length);
tcs.TrySetResult(buf);
};
serialPort.DataReceived += dataReceived;
return tcs.Task;
}
}

Related

Detecting repetition of part of received data

Based on the code shown.. Am I writing the right coding if i want to compare the data that were being stream in? Basically starting from the part
while(serialPort1.IsOpen)
For instance first string of data received was T 12 29.5 then next string was T 12 29.5 followed by T 20 24.5 and on so.. basically unpredictable what going to be received next.
I want to program to be able to detect/count the number of appearance for the middle value..like...
====================
[number] | [Repeated times]
12 | 2
=================== but when another different number received,
[number] | [Repeated]
20 | 1
=================== the counter for the number will be overwrite and reset whenever a different number was received.
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string time = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss.ff");
RxString = serialPort1.ReadLine();
string[] split = RxString.Split('.');
string dp = split[1];
Char c = dp[0];
split[1] = c.ToString();
RxString = split[0] + "." + split[1];
while (serialPort1.IsOpen)
{
string[] number = RxString.Split(' ');
string unit = number[1];
int count = 1;
for(int i = 1; i < unit.Count(); i++)
{
if(unit[i-1] == unit[i])
count++;
else
count = 1;
if(count == 4)
{
//execute some parameters
}
}
}
this.Invoke(new EventHandler(DisplayText));
StreamWriter MyStreamWriter = new StreamWriter(#"C:\Users\acer\Documents\Data3.txt", true);
MyStreamWriter.Write(time + " " + RxString + "\r\n");
MyStreamWriter.Flush();
MyStreamWriter.Close();
}
EDIT V2
Why wont the prog record data which only has count of 1?
string[] number = RxString.Split(' '); //split RxString by ' '
string unit = number[1]; //unit = unit no.
int count = 1;
for (int i = 1; i < unit.Count(); i++)
{
if (unit[i - 1] == unit[i])
count++;
else
{
count = 1;
StreamWriter MyStreamWriter = new StreamWriter(#"C:\Users\acer\Documents\Data3.txt", true); //True tell SW to append to file instead of overwriting
MyStreamWriter.Write(time + " " + RxString + "\r\n"); //Write time + string
MyStreamWriter.Flush();
MyStreamWriter.Close();
}
You should use a dictionary to store each element and its own count :
var dict = new Dictionary<string, int?>();
while (serialPort1.IsOpen)
{
string[] number = RxString.Split(' ');
string unit = number[1];
if (dict.ContainsKey(unit))
{
if (dict[unit].HasValue)
{
dict[unit]++;
if (dict[unit] == 4)
{
// execute some parameters
dict[unit] = null;
}
}
}
else
{
dict.Add(unit, 1);
}
}
I'd create a special struct for that:
struct DataInfo
{
public string Number { get; set; }
public int Counter { get; set; }
... Other data you require to work with
}
And use either List<DataInfo> or Dictionary<string, DataInfo> to store values;

Parse unique string from complicated serial data C#

I need to parse this string from serial:-
!00037,00055#
00037 as one string, 00055 as another string
However this string is came out when the robot's tire is rotated and some other string may also display before and after the string that I need to parse. For example this is the some of the transmission received:-
11,00085#R-STOPR-STOP!00011,00095#!00001,00015#R-STOP!00001,00085#!00003,00075#!00006,00015#R-STOP!00009,00025#!00011,00035#!00011,00085#R-STOPR-STOP!00011,00095#!00001,00015#R-STOP!00001,00085#!00003,00075#!00006,00015#R-STOP!00009,00025#!00011,00035#R-STOP!00001,00085#!00003,00075#!00006,00015#R-STOP!00009,00025#!00011,00035#R-STOP!00037,00055#!00023,00075#R-STOPR-STOP!00022,00065#!00011,00085#R-STOPR-STOP!00011,00095#!00001,00015#R-STOP!00001,00085#!00003,00075#!00006,00015#R-STOP!00009,00025#!00011,00035#R-STOP!00037,00055#!00023,00075#R-STOPR-STOP!00022,00065#!00011,00085#R-STOPR-STOP!00011,00095#!00001,00015#
So far I'm stuck at what to do next after SerialPort.ReadExisting()
Here is some code to retrieve the serial data:-
private void serialCom_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
InputData = serialCom.ReadExisting();
if (InputData != String.Empty)
{
this.BeginInvoke(new SetTextCallback(IncomingData), new object[] { InputData });
}
}
catch
{
MessageBox.Show("Error");
}
}
and display incoming serial data inside textbox
private void IncomingData(string data)
{
tb_incomingData.AppendText(data);
tb_incomingData.ScrollToCaret();
}
This code is using .NET Framework 4.0 and Windows Form.
Finally solve it using indexof and substring.
private void IncomingData(string data)
{
//Show received data in textbox
tb_incomingData.AppendText(data);
tb_incomingData.ScrollToCaret();
//Append data inside longdata (string)
longData = longData + data;
if (longData.Contains('#') && longData.Contains(',') && longData.Contains('!'))
{
try
{
indexSeru = longData.IndexOf('!'); //retrieve index number of the symbol !
indexComma = longData.IndexOf(','); //retrieve index number of the symbol ,
indexAlias = longData.IndexOf('#'); //retrieve index number of the symbol ,
rotation = longData.Substring(indexSeru + 1, 5); //first string is taken after symbol ! and 5 next char
subRotation = longData.Substring(indexComma + 1, 5); //second string is taken after symbol ! and 5 next char
//tss_distance.Text = rotation + "," + subRotation;
longData = null; //clear longdata string
}
catch
{
indexSeru = 0;
indexComma = 0;
indexAlias = 0;
}
}
}
You can determine your pattern to transform this string into a array using SPLIT function.
This code, send "!00037,00055#" returns two itens: 00037 and 00055.
static void Main(string[] args)
{
string k = "!00037,00055#";
var array = k.ToString().Split(',');
Console.WriteLine("Dirty Itens");
for (var x = 0; x <= array.Length - 1; x++)
{
var linha = "Item " + x.ToString() + " = " + array[x];
Console.WriteLine(linha);
}
Console.WriteLine("Cleaned Itens");
for (var x = 0; x <= array.Length - 1; x++)
{
var linha = "Item " + x.ToString() + " = " + CleanString(array[x]);
Console.WriteLine(linha);
}
Console.ReadLine();
}
public static string CleanString(string inputString)
{
string resultString = "";
Regex regexObj = new Regex(#"[^\d]");
resultString = regexObj.Replace(inputString, "");
return resultString;
}

Thread with while (true) loop exits somehow

I have a thread that is supposed to run continuously in my program and parse incoming serial data from a collection of sensors.
//initialized as a global variable
System.Threading.Thread processThread = new System.Threading.Thread(ProcessSerialData);
//this gets called when you press the start button
processThread.Start();
private void ProcessSerialData()
{
while (true)
{
//do a whole bunch of parsing stuff
}
int howDidYouGetHere = 0;
}
How is it possible that my program is reaching the "int howDidYouGetHere = 0" line??
Full code can be found here:
/// <summary>
/// ProcessSerialData thread will be used to continue testing the connection to the controller,
/// process messages in the incoming message queue (actually a linked list),
/// and sends new messages for updated data.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ProcessSerialData()
{
while (true)
{
UpdateAhTextbox(test.ampHoursOut.ToString());
if (!relayBoard.OpenConn())
{
MessageBox.Show("Connection to controller has been lost.");
testInterrupted = "Lost connection. Time = " + test.duration;
UpdateStatusText(false);
ShutErDown();
}
/////////////////////////////////////////////////////
if (incomingData.Count > 0)
{
string dataLine = "";
try
{
dataLine = incomingData.First();
UpdateParsedDataTextbox(dataLine + "\r\n");
}
catch (System.InvalidOperationException emai)
{
break; //data hasn't come in yet, it will by the time this runs next.
}
incomingData.RemoveFirst();
if (dataLine.Contains("GET")) // some sensor values (analog/temp/digital) has come in
{
if (dataLine.Contains("GETANALOG")) // an analog value has come in
{
int index = dataLine.IndexOf("CH");
int pin = (int)Char.GetNumericValue(dataLine[index + 2]);
double value = 0;
int dataLineLength = dataLine.Length;
if (dataLineLength > 13) // value is appended to end of line
{
try
{
value = Convert.ToDouble(dataLine.Substring(13));
}
catch // can't convert to double
{
int index2 = dataLine.IndexOf("CH", 3);
if (index2 != -1) // there happen to be two sets of commands stuck together into one
{
string secondHalf = dataLine.Substring(index2);
incomingData.AddFirst(secondHalf);
}
}
}
else // value is on the next line
{
try
{
value = Convert.ToDouble(incomingData.First());
incomingData.RemoveFirst();
}
catch // can't convert to double
{
MessageBox.Show("Error occured: " + dataLine);
}
}
switch (pin)
{
case 1:
ReadVoltage(value);
break;
case 2:
ReadAmperage(value);
break;
}
}
else if (dataLine.Contains("GETTEMP")) // received reply with temperature data
{
int index = dataLine.IndexOf("CH");
int pin = (int)Char.GetNumericValue(dataLine[index + 2]); // using index of CH, retrieve which pin this message is coming from
double value = 0;
int dataLineLength = dataLine.Length;
if (dataLineLength > 11) // value is appended to end of line
{
try
{
value = Convert.ToDouble(dataLine.Substring(11));
}
catch // can't convert to double
{
int index2 = dataLine.IndexOf("CH", 3);
if (index2 != -1) // there happen to be two sets of commands stuck together into one
{
string secondHalf = dataLine.Substring(index2);
incomingData.AddFirst(secondHalf);
}
}
}
else // value is on the next line
{
value = Convert.ToDouble(incomingData.First());
incomingData.RemoveFirst();
}
ReadTemperature(pin, value);
}
else // must be CH3.GET
{
int index = dataLine.IndexOf("CH");
int pin = (int)Char.GetNumericValue(dataLine[index + 2]); // using index of CH, retrieve which pin this message is coming from
if (pin == 3) // only care if it's pin 3 (BMS), otherwise it's a mistake
{
double value = 0;
int dataLineLength = dataLine.Length;
if (dataLineLength > 7) // value is appended to end of line
{
try
{
value = Convert.ToDouble(dataLine.Substring(7));
}
catch // can't convert to double
{
int index2 = dataLine.IndexOf("CH", 3);
if (index2 != -1) // there happen to be two sets of commands stuck together into one
{
string secondHalf = dataLine.Substring(index2);
incomingData.AddFirst(secondHalf);
}
}
}
else // value is on the next line
{
value = Convert.ToDouble(incomingData.First());
incomingData.RemoveFirst();
}
ReadBMS(value);
}
}
}
else if (dataLine.Contains("REL")) // received reply about relay turning on or off.
{
if (dataLine.Contains("RELS")) // all relays turning on/off
{
if (dataLine.Contains("ON"))
{
for (int pin = 1; pin <= 4; pin++)
{
test.contactors[pin] = true;
}
}
else // "OFF"
{
for (int pin = 1; pin <= 4; pin++)
{
test.contactors[pin] = false;
}
}
}
else // single relay is turning on/off
{
int index = dataLine.IndexOf("REL");
int pin = (int)Char.GetNumericValue(dataLine[index + 3]);
if (dataLine.Contains("ON"))
{
test.contactors[pin] = true;
}
else if (dataLine.Contains("OFF"))
{
test.contactors[pin] = false;
}
else if (dataLine.Contains("GET"))
{
if (Convert.ToInt32(incomingData.First()) == 1)
test.contactors[pin] = true;
else
test.contactors[pin] = false;
incomingData.RemoveFirst();
}
}
}
}
/////////////////////////////////////////////////////
// we only want more data if we're done processing the current data, otherwise we're stuck with too much and processing is heavily delayed.
if (isTestRunning && incomingData.Count < 3)
{
//read & output v, a, bms state
sendToController("CH1.GETANALOG"); // get voltage
sendToController("CH2.GETANALOG"); // get amperage
sendToController("CH3.GET"); // get BMS state
//read & output temperature
sendToController("CH4.GETTEMP"); // get temperature
sendToController("CH5.GETTEMP");
string lines = "Ah Out: " + test.ampHoursOut + ", Voltage: " + test.voltage +
", Amperage: " + test.amperage + ", Cell Temperature: " + test.tempBattery +
", Load Temperature: " + test.tempLoad;
WriteToLog(lines);
}
}
int howDidYouGetHere = 0;
}
The break (ignoring those inside the nested switch) breaks out of the while loop.
Perhaps you have tried to update your UI using UpdateParsedDataTextbox This will cause InvalidOperationException(then breaks the while loop) because you tries to access the UI control from thread that doesn't own the control.

Why sometimes I received some random data from serial port? using c#

Data supposed to be received should be something like"-31.12345 167.12345", but sometimes I received data like "2.378999E11 3.593719E"? I have checked my port setting they are using same parameter. My code as following:
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
byte rxChar=0;
byte[] rxDataBuffer = new byte[240];
int rxdata = 0;
rxNumberDataBytes = (byte)serialPort.BytesToRead;
//SerialPort sp = (SerialPort)sender;
//rxdata = sp.Read(rxDataBuffer, 0, 8);
while (serialPort.BytesToRead > 0)
{
rxChar = (byte)serialPort.ReadByte(); // read data
// to display bytes received in hex,check was all data received
Invoke(new Action(() =>
{
textBox3.Text += " " + rxChar.ToString("X") + "\r\n";
}));
switch (rxState)
{
case RxIdleState:
if (rxChar == 0x5A)
{
rxState = RxInstructionState;
}
break;
case RxInstructionState:
rxInstruction = rxChar;
rxState = RxNumberofbytesState;
break;
case RxNumberofbytesState:
rxChar = rxNumberDataBytes;
rxState = RxDataState;
rxdata = 0;
break;
case RxDataState:
// count number of rxdata until 8 bytes real data
rxDataBuffer[rxdata] = rxChar;
rxdata++;
if (rxdata == 8)
{
float f11 = BitConverter.ToSingle(rxDataBuffer, 0);
float f22 = BitConverter.ToSingle(rxDataBuffer, 4);
Invoke(new Action(() =>
{
textBox3.Text += f11.ToString() + " " + f22.ToString() + "\r\n";
}));
rxState = RxStopState;
}
break;
case RxStopState:
if (rxChar == 0x2C)
{
rxState = RxIdleState;
}
break;
default:
rxState = RxIdleState;
break;
}
}
}
}
I think you're grabbing wrong data due to a wrong set operation.
In the following, you are setting the number of bytes you want and then setting the rxChar to the first available byte in the stream. That seems fine.
rxNumberDataBytes = (byte)serialPort.BytesToRead;
while (serialPort.BytesToRead > 0)
{
rxChar = (byte)serialPort.ReadByte(); // read data
....
}
However, in the following, you are then ignoring that rxChar value and setting it to the number of bytes that were available for reading.
case RxNumberofbytesState:
rxChar = rxNumberDataBytes; // <--- This is correct?
rxState = RxDataState;
rxdata = 0;
break;
You are then using the new rxChar value to add to your rxDataBuffer instead of the first byte that was available in the serial port.
Looking at the flow of the code, the rest of the 7 bytes look like they will be correct, but the first one will always be wrong.
May also just be floating point precision issue ;)

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