Kinda new to C# asynchronous/network programming, trying to write a program that fetches a bunch of GET request responses using plain TCP sockets, however I've noticed that most of the time, my callback functions are not being called (and on some occasions they are, which is even weirder).
Here's my code:
class CallbackService
{
private static ConcurrentDictionary<String, String> results;
private List<string> urlList;
private const int PORT = 80;
public CallbackService(List<string> list)
{
urlList = list;
results = new ConcurrentDictionary<string, string>(urlList.Count * 2, urlList.Count);
}
public void Run()
{
foreach (string url in urlList)
{
Work(url);
}
}
private static void Work(string url)
{
string host = Utility.getHostFromURL(url);
string resource = Utility.getResourceFromURL(url);
IPAddress ipAddress = Utility.getIPFromHost(host);
IPEndPoint endpoint = new IPEndPoint(ipAddress, PORT);
Socket socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
RequestState state = new RequestState(socket, endpoint, host, resource);
state.socket.BeginConnect(state.endpoint, ConnectCallback, state);
}
private static void ConnectCallback(IAsyncResult connectState)
{
RequestState state = (RequestState)connectState.AsyncState;
state.socket.EndConnect(connectState);
string request = Utility.getRequestString(state.host, state.resource);
Byte[] requestBytes = Encoding.ASCII.GetBytes(request);
state.socket.BeginSend(requestBytes, 0, request.Length, 0, SendCallback, state);
}
private static void SendCallback(IAsyncResult sendState)
{
RequestState state = (RequestState)sendState.AsyncState;
int bytesSent = state.socket.EndSend(sendState);
state.socket.BeginReceive(state.data, 0, state.data.Length, 0, ReceiveCallback, state);
}
private static void ReceiveCallback(IAsyncResult sendState)
{
RequestState state = (RequestState)sendState.AsyncState;
int responseSize = state.socket.EndReceive(sendState);
string response = Encoding.ASCII.GetString(state.data, 0, responseSize);
results.TryAdd(state.host, response);
state.socket.Shutdown(SocketShutdown.Both);
state.socket.Close();
}
public void PrintResults()
{
foreach (KeyValuePair<string, string> entry in results)
{
Console.WriteLine("Result from host " + entry.Key + ": " + entry.Value);
}
}
The utility functions (pretty sure they're working fine):
class Utility
{
public static string getHostFromURL(string url)
{
return url.Split("/")[0];
}
public static string getResourceFromURL(string url)
{
var split = url.Split("/", 2);
return split.Length > 1 ? split[1] : "/";
}
public static IPAddress getIPFromHost(string host)
{
return Dns.GetHostEntry(host).AddressList[0];
}
public static string getRequestString(string host, string resource)
{
return "GET " + resource + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36\r\n" +
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,#1#*;q=0.8\r\n" +
"Accept-Language: en-US,en;q=0.9,ro;q=0.8\r\n" +
"Accept-Encoding: gzip, deflate\r\n" +
"Upgrade-Insecure-Requests: 1\r\n" +
"Pragma: no-cache\r\n" +
"Cache-Control: no-cache\r\n" +
"Content-Length: 0\r\n\r\n";
}
}
And the state class:
class RequestState
{
public RequestState(Socket socket, IPEndPoint endpoint, string host, string resource)
{
this.socket = socket;
this.endpoint = endpoint;
this.host = host;
this.resource = resource;
this.data = new byte[2048];
}
public Socket socket;
public IPEndPoint endpoint;
public string host;
public string resource;
public byte[] data;
}
So generally, ConnectCallback
will not be called at all, but sometimes it will (but then the same thing happens with SendCallback
). Not sure what could be going wrong. From what I've noticed, the domain names are being resolved to the correct addresses. What am I missing here?