I'm creating an C# app which have to send http GET requests with vertical line symbol inside URI query part and that is impossible due to url encoding by URI class. So in the final url is "%7C" instead of "|" and server app cannot handle it.
The main problem is, that the server side app is developed by our external supplier and I have no access to it's source code and they cannot edit it for some reason, so I really need to do it somehow inside my client app.
I've tryed a lot, but cannot find any solution on the internet. But I have two work-arounds that can almost do what I want:
1) Using sockets
It's works perfectly, but... when I use it asynchoniously, server app seems to cannot handle more sockets at one time, and always run only once, with same response to each socket GET request. Client sockets has same host (my local PC) but run on different local PC port.
2) Using WebBrowser control with Navigate method
Even this solution works almost fine, but I realy don't want to use WebBrowser for every GET request.
Socket GET caller method
private static async Task<string> HttpGetRequestAsync(string url, int timeOut)
{
return await Task.Run(() =>
{
timeOut += Environment.TickCount;
Uri uri = new Uri(url);
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Connect(uri.Host, uri.Port);
string request = string.Format(
"GET {0} HTTP/1.1{2}" +
"Host: {1}{2}" +
"Content-Length: 0{2}" +
"{2}", Uri.UnescapeDataString(uri.PathAndQuery), uri.Host, "\r\n");
socket.Send(Encoding.UTF8.GetBytes(request));
StringBuilder response = new StringBuilder();
byte[] responseData = new byte[BUFFER_SIZE];
int bytesRead = socket.Receive(responseData);
while (bytesRead != 0)
{
if (timeOut < Environment.TickCount) { throw new TimeoutException("TimeOut exception...!"); }
response.Append(Encoding.UTF8.GetChars(responseData), 0, bytesRead);
bytesRead = socket.Receive(responseData);
}
socket.Shutdown(SocketShutdown.Both);
socket.Close();
return response.ToString();
}
});
}
So I really need to find a way, how to send GET request in this format:
http://server:port/sms/send_sms.php?value1|value2
instead of this:
http://server:port/sms/send_sms.php?value1%7Cvalue2
Related
Alright, so I'm pretty new to C# and I'm definitely pretty new to graphical programming. I'm using Visual Studio 2015 and writing my application in C#.
I have this hunk of code that I've been toying around with for a while. Essentially my program will send the HELLO, to the server, but the server isn't sending HELLO back. I have no firewall in the middle of client and server right now, but the process is getting hung waiting for the reply back. I honestly don't even want to do it this way, I want the listener to always run in the background while the user does other stuff so that my program functions, well normal. So I come to you oh great Stackoverflow... because I am definitely doing it wrong! Could someone please point me the right direction?
Current Code:
private void button1_Click(object sender, EventArgs e)
{
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(this.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
this.send_message("127.0.0.1", 10545, 10545, "HELLO");
this.send_message("127.0.0.1", 10545, 10545, "AUTH:" + this.login.Text + ":" + hash);
//ListenForData.Start();
}
private void send_message(string server, int localPort, int remotePort, string message)
{
label4.Text = "Listening on port:" + localPort;
IPEndPoint lep = new IPEndPoint(IPAddress.Any, localPort);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress loginServer = IPAddress.Parse(server.ToString());
byte[] sendbuf = Encoding.ASCII.GetBytes(message);
IPEndPoint ep = new IPEndPoint(loginServer, remotePort);
s.SendTo(sendbuf, ep);
try
{
UdpClient udpClient = new UdpClient(lep);
byte[] bytes = udpClient.Receive(ref lep);
label4.Text = ep.ToString();
} catch ( Exception ex )
{
Console.WriteLine(ex.ToString());
}
}
UDPATE:
private static void UDPListener(object obj)
{
Task.Run(async () =>
{
using (var udpClient = new UdpClient(10545))
{
string rMessage = "";
string[] rArgs = new string[0];
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
rMessage += Encoding.ASCII.GetString(receivedResults.Buffer);
rArgs = rMessage.Split(new char[] { ':' });
if( rArgs[0] == "HELLO")
{
Console.Write("Received HELLO from server.");
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(obj.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
send_message("127.0.0.1", 10545, 10545, "AUTH:" + obj.login.Text + ":" + hash);
}
}
}
});
}
You can safely ignore the advice from Blindy. The UdpClient.ReceiveAsync() method is specifically designed around the Task paradigm, and is much more efficient than dedicating a thread to receiving data. Because the Task is awaitable, it's also easier to integrate the ReceiveAsync() approach with a GUI program (e.g. Winforms or WPF). That said, for all that to work, you want to execute the ReceiveAsync() call in the UI thread, rather than in another Task.
Unfortunately, lacking a good, minimal, complete code example that clearly illustrates your question, it's not possible to say for sure how that would look. But it most likely would involve making your UDPListener() method an async method and calling it from the UI thread. Also, since you say the method can't access non-static members, the obvious solution to that is to make the method itself non-static. E.g.:
private static async Task UDPListener(object obj)
{
using (var udpClient = new UdpClient(10545))
{
string rMessage = "";
string[] rArgs = new string[0];
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
rMessage += Encoding.ASCII.GetString(receivedResults.Buffer);
rArgs = rMessage.Split(new char[] { ':' });
if( rArgs[0] == "HELLO")
{
Console.Write("Received HELLO from server.");
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(obj.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
send_message("127.0.0.1", 10545, 10545, "AUTH:" + obj.login.Text + ":" + hash);
}
}
}
}
It is not clear from your updated question whether you have fixed your failed to receive a reply yet. But if you have not changed your send_message() method, it has some obvious problems, especially in the context of creating a separate UdpClient instance to receive datagrams.
The most obvious issue is that you do not create the UdpClient instance which you're expecting to use to receive the response until after you have sent the message. This is wrong for two reasons:
It's entirely possible that the remote endpoint will send the response before you've created the socket. If that happens, the datagram will just be dropped.
More importantly, the usual design for a server is to send a response to the remote endpoint that sent it the message in the first place. I.e. in this case that would be the socket s. Even if you did create the udpClient object before calling s.SendTo(), the reply would actually be sent to the s socket, not the udpClient.Client socket.
Again, without a good code example it's not possible to know what your server actually does. But whether it behaves like a normal server, or is some non-standard implementation, the code you've posted cannot reliably receive a response from the server.
You should fix your design so that your client creates only a single socket (e.g. an initial UdpClient instance). You would prepare for communication by calling ReceiveAsync(), and only once you've done that, thus ensuring you're ready to receive a response, then you can send data.
Make sure that you create only this single object.
Note also that client-side implementations typically do not bind to a specific port. Instead, you let the OS assign a port. Only the server needs to bind to a specific port, so that inbound requests from unknown endpoints can know to what port to send their request. The server's receive operation will include the port number of the client, so the server will know to what port to send its response, without the client having selected any special port number.
Finally, I strongly recommend you study existing socket programming tutorials, and especially the Winsock Programmer's FAQ. None of the material there is directly applicable to the .NET socket API, but most of the issues you will have trouble with are exactly the kinds of things documented there. It is not possible to use the .NET socket API without also having a good basic comprehension of socket programming generally.
If the above does not get you headed in the right direction, please make sure that any future questions you ask include a good code example, as described in the link I provided above. Note that for any networking question, a complete code example includes both the client and server. It is not possible for anyone to fully understand your question, never mind to test and fix your code example, without implementations of both.
This question already has answers here:
Handling multiple requests with C# HttpListener
(3 answers)
Closed 8 years ago.
I have this HttpListener, which works perfect for a single requesst, but then it shuts down after finishing up the request. What I'm interested in, is a listener that keeps up the connection with the client until there's no more files in the specified URL. I've tried fiddling around with threads and asynchronous calls, but I haven't been able to make anything of it working thus far. I just have a hard time imagining there isn't some relatively easy way to get a HttpListener to keep up the connection instead of shutting down after completing each request.
public static void Listener(string[] prefixes)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}
// URI prefixes are required,
// for example "http://contoso.com:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
foreach (string s in prefixes)
{
listener.Prefixes.Add("http://" + s + "/");
}
listener.Start();
Console.WriteLine("\nListening...");
HttpListenerContext context = listener.GetContext();
Console.WriteLine("Request received...\n");
HttpListenerRequest request = context.Request;
// Obtain a response object.
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;
#region Load image and respond
// Load the image
Bitmap bm = new Bitmap("C:\\MyFolder\\image_1\\");
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;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
listener.Stop();
#endregion
And here's the Program:
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.Listener(ips);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//Manually setting the IP - not optimal!
//string[] ipstring = new string[1] { "10.10.180.11:8080" };
//Response.Listener(ipstring);
}
}
Yes - you're calling GetContext once, serving that request, then stopping.
Instead, you should be calling GetContext in a loop. Depending on whether you want to be able to handle multiple requests concurrently or not, you might have GetContext in one thread, and then hand off each request to a separate (probably thread-pool) thread to respond to it.
The slightly tricky bit is shutting down - if you want a clean shutdown, you'll need to work out when to stop the loop (and what to do if you're in the middle of a GetContext call), and wait for outstanding requests to complete.
It stops listening after processing one request because you just stop listening. You need to implement something like a waiting loop.
Example which should help you can be found on codeproject - example.
Pay attention to this part of the code and how it is used in the example:
private void startlistener(object s)
{
while (true)
{
////blocks until a client has connected to the server
ProcessRequest();
}
}
I have webserver receive data by async sockets:
var e = new SocketAsyncEventArgs();
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
while (true)
{ allDone.Reset();
mySocket.AcceptAsync(e);
allDone.WaitOne();
}
and the other method:
public void e_Completed(object sender, SocketAsyncEventArgs e)
{
var socket = (Socket)sender;
ThreadPool.QueueUserWorkItem(handleTcpRequest, e.AcceptSocket);
e.AcceptSocket = null;
socket.AcceptAsync(e);
}
this is the handleTcpRequest method.in this part I receive data from socket and do operation:
public void handleTcpRequest(object state)
{
string sBuffer = "";
string BufferTotal = "";
byte[] secureMessage;
Byte[] bReceive = new Byte[1024];
var mySocket = (Socket)state;
do
{
try
{
firstBufferRead = mySocket.Receive(bReceive, bReceive.Length, 0);
}
catch (Exception ex)
{
Console.WriteLine("Error Occurred (:))) " + ex.Message);
}
sBuffer += Encoding.GetEncoding(1252).GetString(bReceive, 0, firstBufferRead);
BufferTotal += Encoding.UTF8.GetString(bReceive, 0, firstBufferRead);
} while (mySocket.Available != 0);
.
.
.
.
mySocket.Close();
}
whats wrong?
sometimes connection resets and closes. this happens when distance is far or post data not multipart. but in multipart happens rarely. more with forms not in multipart.
when and where should I close socket?
when I work with socket in handleTcpRequest method its local. isn't it correct? I can't find the origin of the problem
The only way to know that you've received everything in a HTTP request is to understand the HTTP request. And to understand a HTTP request you have to choices:
Use a complete HTTP server
Create a HTTP parser
The reason to why your code fails for multi-part data is probably because the other party sends one part at a time, which means that your code manages to do a mySocket.Available != 0 before the rest is sent.
If you want to do the latter you have to read the HTTP header (in format headerName: headervalue, do note that there are also white space rules that you have to consider). Search for a header named content-length, parse it's value as an integer. Then wait for two line feeds in a row (\r\n\r\n). Finally start count bytes until you have received the number of bytes that was specified in the content-length header.
ohh.. ony more thing.. pray to God that Transfer-Encoding: Chunkedis not used.
My advice is that you give up on using sockets directly as it's apparent that you don't understand how they work or how to do research on them.
If response has a header of Connection: Close, then the socket closes automatically.
I have a server/client type app, Wireshark shows that the client has sent a packet to the server, the server had given the expected response but shows a ICMP Destination port unreachable error.
I'm using a function that was on the MDSN website which has worked for me before.
EDIT: To update I have checked that the packet is being sent after the phone has started listening, I have tried other ports. There is no socket exception so i'm just looking for the best way to go about debugging network errors.
Any ideas?
public string Receive()
{
string response = "Operation Timeout";
// We are receiving over an established socket connection
if (udpSocket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new DnsEndPoint(SERVER, RECIVEPORT);
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// Retrieve the data from the buffer
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
Debug.WriteLine("Listening now:" + DateTime.Now.Second + ":" + DateTime.Now.Millisecond);
try
{
Debug.WriteLine("No socket exception");
udpSocket.ReceiveFromAsync(socketEventArg);
}
catch (SocketException e)
{
Debug.WriteLine(e.SocketErrorCode);
}
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
"ICMP Destination port unreachable" means that there was no application bound to the port you were sending to. Make sure that your sendto() is targeting to correct IP address and port number. Also check that your listener is calling bind() on INADDR_ANY and the correct port. A common mistake is to forget to convert the port number to network byte order (big-endian). See htons().
So, for a bit of background :
This class is created to accept and respond to calls made remotely in an HTTP format.
The problem is when the method of the request is POST, sometimes the request is processed correctly, but most of the times the class just ends up being irresponsive.
Also, the line "Debug1" and "Debug2" are never written to the console, even when the request is processed correctly.
The line "Debug3" appears only when the request is processed correctly.
I know this will probably look messy, C# is only a hobby for me, and I'm learning :)
Thanks for spending some time to go through this code!
Here is the code:
class WebServer
{
private TcpListener myListener;
public WebServer(int port)
{
//Threading the listener
try
{
myListener = new TcpListener(IPAddress.Any, port) ;
myListener.Start();
Thread th = new Thread(new ThreadStart(StartListen));
th.Start() ;
}
catch(Exception e)
{
Logs.Add("WebServer|An Exception Occurred while Listening :" +e.ToString());
}
}
private void StartListen()
{
int iStartPos = 0;
string sHttpVersion;
string sResponse = "";
string sCode = " 200 OK";
while(true)
{
//Accept a new connection
Socket mySocket = myListener.AcceptSocket();
if(mySocket.Connected)
{
Byte[] bReceive = new Byte[1024];
int i = mySocket.Receive(bReceive,bReceive.Length,SocketFlags.None);
string sBuffer = Encoding.ASCII.GetString(bReceive).TrimEnd('\0');
iStartPos = sBuffer.IndexOf("HTTP",1);
sHttpVersion = sBuffer.Substring(iStartPos,8); //http version (ex: "HTTP/1.1")
if (sBuffer.StartsWith("GET / "))
{
Logs.Add("WebServer|Connected:" + mySocket.RemoteEndPoint.ToString());
sResponse = ArrayToJson();
}
else if (sBuffer.StartsWith("POST"))
{
Console.WriteLine("Debug1");
//This is a POST request, so more data is waiting to be retreived...
bReceive = new Byte[2048];
i = mySocket.Receive(bReceive,bReceive.Length,SocketFlags.None);
sBuffer = Encoding.ASCII.GetString(bReceive).TrimEnd('\0');
Console.WriteLine("Debug2");
//Parsing the request
string[] sParams = sBuffer.Split(',');
Console.WriteLine(sParams.Length);
Console.WriteLine("Debug3: {0} - {1} - {2} - {3} - {4}", sParams[0], sParams[1], sParams[2], sParams[3], sParams[4]);
//I do what needs to be done here
Logs.Add("WebServer|BotStartRequest:" + mySocket.RemoteEndPoint.ToString());
sResponse = "Accepted";
}
//Sending response and closing socket
SendHeader(sHttpVersion, "text/html", sResponse.Length, sCode, ref mySocket);
SendToBrowser(sResponse, ref mySocket);
mySocket.Close();
}
}
}
}
}
Implementing HTTP/1.1 is not a simple task. The basic protocol looks quite simple, but it's really hard to get even a minimal server implementation right: You have at least to think about persistent connections, in the case of POST of the Expect: 100-continue header, correctly parsing the header, and much more.
I strongly recommend you have a look at existing libraries/code. For example, the HttpListener class is built into the .NET Framework and probably already provides all you'll ever need.
If you really want to implement a server from scratch, have a look at Microsoft Cassini, a simple HTTP server written in C# licensed under Ms-PL.