I have a HttpListener which I want to not shut down after each request, so I'm using BeginGetContext to retrieve requests asynchronously. It's just not working properly.
Main starts properly, finding and assigning my IP address for the StartListening() function. However, when I get to listener.BeginGetContext(new AsyncCallback(OnRequest), listener); in StartListening() and it jumps to Response.StartListening(ips); in Main and then just stops. I'm not sure why. Any hints?
Here's what I have so far.
This is where I start listening for requests:
public static void StartListening(string[] prefixes)
{
HttpListener listener = new HttpListener();
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
foreach (string s in prefixes)
{
listener.Prefixes.Add("http://" + s + "/");
}
listener.Start();
Console.WriteLine("\nListening...");
listener.BeginGetContext(new AsyncCallback(OnRequest), listener);
}
And here's where I handle the requests:
public static void OnRequest(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;
HttpListenerContext context = listener.EndGetContext(result);
string url = context.Request.RawUrl;
string[] split = url.Split('/');
int lastIndex = split.Length - 1;
int x, y, z;
x = Convert.ToInt32(split[lastIndex]);
y = Convert.ToInt32(split[lastIndex - 1]);
z = Convert.ToInt32(split[lastIndex - 2]);
HttpListenerResponse response = context.Response;
Regex imageRegex = new Regex(#"SomethingSomething");
var matches = imageRegex.Match(url);
if (matches.Success)
{
string path = #"C:\SomeDir";
path = String.Format(path, matches.Groups[1].Captures[0],
matches.Groups[2].Captures[0],
matches.Groups[3].Captures[0]);
// Load the image
Bitmap bm = new Bitmap(path);
MemoryStream bmStream = new MemoryStream();
bm.Save(bmStream, ImageFormat.Png);
byte[] buffer = bmStream.ToArray();
// Get a response stream and write the response to it.
response.ContentLength64 = bmStream.Length;
response.ContentType = "image/png";
response.KeepAlive = true;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
listener.Stop();
}
response.Close();
listener.BeginGetContext(new AsyncCallback(OnRequest), listener);
}
And here's my main:
class Program
{
static void Main(string[] args)
{
string name = (args.Length < 1) ? Dns.GetHostName() : args[0];
try
{ //Find the IPv4 address
IPAddress[] addrs = Array.FindAll(Dns.GetHostEntry(string.Empty).AddressList,
a => a.AddressFamily == AddressFamily.InterNetwork);
Console.WriteLine("Your IP address is: ");
foreach (IPAddress addr in addrs)
Console.WriteLine("{0} {1}", name, addr);
//Automatically set the IP address
string[] ips = addrs.Select(ip => ip.ToString()).ToArray();
Response.StartListening(ips);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
After BeginGetContext, it fetches requests asynchronously, so it does not block the calling thread (the Main thread, in this case). And because it doesn't block it, the Main thread ends and thus your program also ends, because it's the Main thread.
You can fix this, by using a ManualResetEvent (in the System.Threading namespace). This blocks the Main thread.
class Program
{
public static ManualResetEvent ServerManualResetEvent;
static void Main(string[] args)
{
try
{
// your code to start the server
ServerManualResetEvent = new ManualResetEvent(false);
ServerManualResetEvent.WaitOne();
}
catch
{
// your catch code
}
}
}
Now the Main thread is blocked and your program only stops if you close it, or if you stop it from code:
Program.ServerManualResetEvent.Set();
Then it does not block the Main thread anymore.
Related
I have this Windows form app that wants to receive some calls from some external source.
I did some example based on this :
https://learn.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-5.0
Its almost the same thing, i just did it to run on another thread.
private static Form1 form;
public static Thread httpServer;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new Form1();
form.Load += OnFormLoad;
Application.Run(form);
}
private static void OnFormLoad(object sender, EventArgs e)
{
httpServer = CreateHttp();
}
private static Thread CreateHttp()
{
HttpListener listener = new HttpListener();
string[] prefixes = new string[1];
prefixes[0] = "http://+:3070/";
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
listener.Start();
var listeningThread = new Thread(() =>
{
while (true)
{
HttpListenerContext context = listener.GetContext();
ThreadPool.QueueUserWorkItem(param =>
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string url = request.RawUrl;
string responseString = "<HTML><BODY> Hello World </BODY></HTML>";
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}, null);
}
});
listeningThread.IsBackground = true;
listeningThread.Start();
return listeningThread;
}
When I call from localhost:3070 or 127.0.0.1:3070 it works, but if i try from ipadress:3070 I only get timeouts.
I'm already included this "3070" ports in my firewall....I also tried turning off my entire firewall
Also checked if the listener is working with the command :
netstat -na | find "3070"
TCP 0.0.0.0:3070 0.0.0.0:0 LISTENING
TCP [::]:3070 [::]:0 LISTENING
And also checked if this url is reserved with the command:
"netsh http show urlacl"
URL reservada : http://+:3070/
Usuário: \Todos
Escutar: Yes
Delegar: No
SDDL: D:(A;;GX;;;WD)
Anything I'm missing ?
I would create a tcp server with TcpListener, but I don't know what's the best solution to do that.
I tried with 3 examples. See below.
Example 1
(I used BeginAcceptTcpClient)
class Program
{
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
AcceptTcpClient(listener);
while (true)
{
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
Example 2
(I used BeginAcceptTcpClient with AutoResetEvent)
class Program1
{
private static readonly AutoResetEvent CONNECTION_WAIT_HANDLE = new AutoResetEvent(false);
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
listener.BeginAcceptTcpClient(ClientConnectedHandle, listener);
CONNECTION_WAIT_HANDLE.WaitOne();
CONNECTION_WAIT_HANDLE.Reset();
}
}
public static void ClientConnectedHandle(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
CONNECTION_WAIT_HANDLE.Set();
DoAsync(client);
}
}
Example 3
(I used AcceptTcpClientAsync)
class Program2
{
static async Task Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
var client = await listener.AcceptTcpClientAsync();
DoAsync(client);
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
I think the best solution is the last (Example 3) but I'm not sure. What do you think of that?
This is the code that I'm using in my project. It's a receive only asynchronous server but you can modify it to your liking according to your needs in Task.Run(). I have commented out the code so that you can understand how it works.
static async Task Main(string[] args)
{
await RunServer();
}
static async Task RunServer()
{
TcpListener Listener = new TcpListener(IPAddress.Any, YOURPORTHERE); // Set your listener
Listener.Start(); // Start your listener
while (true) // Permanent loop, it may not be the best solution
{
TcpClient Client = await Listener.AcceptTcpClientAsync(); // Waiting for a connection
_ = Task.Run(() => { // Connection opened. Queues the specified job to run in the ThreadPool, meanwhile the server is ready to accept other connections in parallel
try
{
var Stream = Client.GetStream(); // (read-only) get data bytes
if (Stream.CanRead) // Verify if the stream can be read.
{
byte[] Buffer = new byte[Client.ReceiveBufferSize]; // Initialize a new empty byte array with the data length.
StringBuilder SB = new StringBuilder();
do // Start converting bytes to string
{
int BytesReaded = Stream.Read(Buffer, 0, Buffer.Length);
SB.AppendFormat("{0}", Encoding.ASCII.GetString(Buffer, 0, BytesReaded));
} while (Stream.DataAvailable); // Until stream data is available
if (SB != null) // Stream data is ready and converted to string
// Do some stuffs
}
}
catch (Exception Ex) // In case of errors catch it to avoid the app crash
{
ConsoleMessage.Error(Ex.ToString()); // Detailed exception
}
});
}
}
I'm not to acquainted with TcpListener and sockets, but I have the following code that execute correctly sometimes in my Initializer class from my App_Code of my Wcf project, but then the first correct execute it show me errors sometimes and then execute correctly other ones without pattern.
The error stop in this line code:
Socket soc = listener.AcceptSocket();
And then shows this aditional information:
Additional Information: Not in Listening. Call the Start () method before calling this method.
But like you can see I call start method before listener.AcceptSocket()…
I suspect that this is for try to begin a init daemon in a WCF project.
public static void AppInitialize()
{
// This will get called on startup
new Initializer().StartListener();
}
static TcpListener listener;
const int LIMIT = 5; //5 concurrent clients
private void StartListener()
{
List<int> puertos = new List<int>();
puertos.Add(5494);
puertos.Add(5495);
puertos.Add(5496);
puertos.Add(5497);
foreach (int puerto in puertos)
{
IPAddress localAddr = IPAddress.Parse(ConfigurationManager.AppSettings["ServerIP"]);
listener = new TcpListener(localAddr, puerto);
listener.Start();
for (int i = 0; i < LIMIT; i++)
{
Thread t = new Thread(new ThreadStart(Service));
t.Start();
}
}
}
private void Service()
{
while (true)
{
//Error happen hear, but listener.Start execute before... .
Socket soc = listener.AcceptSocket();
try
{
byte[] resp = new byte[2000];
var memStream = new MemoryStream();
var bytes = 0;
NetworkStream s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
while (true)
{
string trama = "";
if (s.CanRead)
{
do
{
bytes = s.Read(resp, 0, resp.Length);
trama = Util.Util.ByteArrayToHexString(resp);
}
while (s.DataAvailable);
}
if (trama == "" || trama == null) break;
}
s.Close();
}
catch (Exception e)
{
}
finally
{
soc.Close();
}
}
}
Well, it's not clear why if this is a WCF program, you are using Socket or TcpListener directly. The point of WCF is to let it handle the network I/O for you.
That said…
You are getting the exception because the listener field is shared between all of your threads and one or more of your threads has managed to get to AcceptSocket() just after the first thread has created a new TcpListener object, but before it's called Start().
It's actually good you got the exception. Your code could easily have run without that exception, if you were unlucky enough, and then you'd have a much harder problem to debug because the only symptom would be that, mysteriously, not all of your listeners were accepting any clients.
IMHO, it would be best to design the code, such that you have separate object instances handling each listening socket (and use non-static members for values). That way, you can be sure each listener is operating correctly and independently.
But, the code you have here can be fixed, at least with respect to the exception, by passing the correct TcpListener object to each thread:
private void StartListener()
{
List<int> puertos = new List<int>();
puertos.Add(5494);
puertos.Add(5495);
puertos.Add(5496);
puertos.Add(5497);
foreach (int puerto in puertos)
{
IPAddress localAddr = IPAddress.Parse(ConfigurationManager.AppSettings["ServerIP"]);
TcpListener listener = new TcpListener(localAddr, puerto);
listener.Start();
for (int i = 0; i < LIMIT; i++)
{
Thread t = new Thread(() => Service(listener));
t.Start();
}
}
}
private void Service(TcpListener listener)
{
while (true)
{
Socket soc = listener.AcceptSocket();
try
{
byte[] resp = new byte[2000];
var memStream = new MemoryStream();
var bytes = 0;
NetworkStream s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
while (true)
{
string trama = "";
if (s.CanRead)
{
do
{
bytes = s.Read(resp, 0, resp.Length);
trama = Util.Util.ByteArrayToHexString(resp);
}
while (s.DataAvailable);
}
if (trama == "" || trama == null) break;
}
s.Close();
}
catch (Exception e) { }
finally
{
soc.Close();
}
}
}
Be sure to remove the static TcpListener listener; field.
One last note: you should never catch Exception, except in a part of the code where all that will happen is that, optionally the exception is logged, and the process is terminated.
My code
This code for server
class Program
{
private static readonly byte[] Localhost = {127,0,0,1};
private const int Port = 8567;
static void Main(string[] args)
{
var address = new IPAddress( Localhost );
var endPoint = new IPEndPoint(address, Port);
var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(endPoint);// Error in this line
listener.Listen(3);
String data = "";
while (true)
{
Console.WriteLine("Listening on sport {0}", endPoint);
byte[] buffer = new byte[4096];
// handle incoming connection ...
var handler = listener.Accept();
Console.WriteLine("Handling incoming connection ...");
while (true)
{
int count = handler.Receive(buffer);
data += Encoding.UTF8.GetString(buffer, 0, count);
// Find start of MLLP frame, a VT character ...
int start = data.IndexOf((char) 0x0B);
if (start >= 0)
{
// Now look for the end of the frame, a FS character
int end = data.IndexOf((char) 0x1C);
if (end > start)
{
string temp = data.Substring(start + 1, end - start);
// handle message
string response = HandleMessage(temp);
// Send response
handler.Send(Encoding.UTF8.GetBytes(response));
break;
}
}
}
// close connection
handler.Shutdown( SocketShutdown.Both);
handler.Close();
Console.WriteLine("Connection closed.");
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught: {0}", e.Message);
}
Console.WriteLine("Terminating - press ENTER");
Console.ReadLine();
}
private static string HandleMessage(string data)
{
Console.WriteLine("Received message");
var msg = new Message();
msg.Parse(data);
Console.WriteLine("Parsed message : {0}", msg.MessageType() );
Console.WriteLine("Message timestamp : {0}", msg.MessageDateTime() );
Console.WriteLine("Message control id : {0}", msg.MessageControlId());
// *********************************************************************
// Here you could do something usefull with the received message ;-)
// *********************************************************************
// todo
// Create a response message
//
var response = new Message();
var msh = new Segment("MSH");
msh.Field(2, "^~\\&");
msh.Field(7, DateTime.Now.ToString("yyyyMMddhhmmsszzz"));
msh.Field(9, "ACK");
msh.Field(10, Guid.NewGuid().ToString() );
msh.Field(11, "P");
msh.Field(12, "2.5.1");
response.Add(msh);
var msa = new Segment("MSA");
msa.Field(1, "AA");
msa.Field(2, msg.MessageControlId());
response.Add(msa);
// Put response message into an MLLP frame ( <VT> data <FS><CR> )
//
var frame = new StringBuilder();
frame.Append((char) 0x0B);
frame.Append(response.Serialize());
frame.Append( (char) 0x1C);
frame.Append( (char) 0x0D);
return frame.ToString();
}
}
but I am getting following error:
SocketException was caught :- An attempt was made to access a socket in a way forbidden by its access permissions
Please give me any solution.
Exception message tells that you don't have access rights to the socket you created. This can be caused by either socket being already used or user running this process having lower rights than necessary (non-admin rights; this is less likely the reason of the exception in your case).
To check whether some process is already using the socket, open Command Prompt and execute:
netstat -o | find "8567"
This is a program to search for strings from a file. The string required by the client is given from the client side, in my case, using telnet. The program I have written is a server side one. It accepts multiple clients.
But, the problems I am unable rectify are-
It doesn't check for strings from the file.
As soon as the client gets connected, the client cannot type in the strings they want to search in that particular file.
It doesn't send the reply back (i.e. If the string is present in the file or not) to the client. Its only shown on the server side.
How do I proceed further? Could someone tell me where am I going wrong? Could someone please help me out with the code?
This is my try at the program..
class Program
{
static void Main(string[] args)
{
IPAddress ipad = IPAddress.Parse("192.168.0.181");
TcpListener serversocket = new TcpListener(ipad, 8888);
TcpClient clientsocket = default(TcpClient);
Byte[] bytes = new Byte[256];
serversocket.Start();
Console.WriteLine(">> Server Started");
while(true)
{
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accepted Connection From Client");
LineMatcher lm = new LineMatcher(clientsocket);
Thread thread = new Thread(new ThreadStart(lm.Run));
thread.Start();
Console.WriteLine("Client connected");
}
Console.WriteLine(" >> exit");
Console.ReadLine();
clientsocket.Close();
serversocket.Stop();
}
}
public class LineMatcher //I've jumbled it up here. Don't know what exactly to do..
{
public string fileName = "c:/myfile2.txt";
private TcpClient _client;
public LineMatcher(TcpClient client)
{
_client = client;
}
public void Run()
{
try
{
StreamReader sr = new StreamReader("c:/myfile2.txt");
using (var reader = new StreamReader(_client.GetStream()))
{
string line ="";
int lineNumber = 0;
while (null != (line = sr.ReadLine()))
{
lineNumber += 1;
byte[] data = new byte[1024];
NetworkStream stream = _client.GetStream();
//if (line.Equals(line))
for (int ct = stream.Read(data,0, data.Length-1); 0 < ct; ct = stream.Read(data,0,data.Length-1))
line += Encoding.ASCII.GetString(data, 0, ct);
line = line.Trim();
{
lineNumber.ToString();
data = Encoding.ASCII.GetBytes(line);
_client.Client.Send(data, data.Length, SocketFlags.None);
Console.WriteLine("Line {0} matches {1}", lineNumber, line);
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
}
I think you got some pieces in your Run-method swapped - here is a version that should do the job:
public void Run()
{
byte[] data;
try
{
using (var r = new StreamReader("c:/myfile2.txt"))
{
string line ="";
int lineNumber = 0;
while (null != (line = r.ReadLine()))
{
data = Encoding.ASCII.GetBytes(line + "\n");
_client.Client.Send(data, data.Length, SocketFlags.None);
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
Please note that I'm not 100% sure what you are trying to do (I think you want your textfile send line-by-line to your Terminal) - so you might have to change some bits here and there.
Don't know where the Stream-messes in your code came from but I guess you tried various tutorials/snippets and forgot to clean up ;)