Question:
I write client-server applications. Text data will be transmitted via the Internet, the speed and stability of which leaves much to be desired. The client takes data from the file, adds its ID to it, then all this in Json format with Gzip compression and sends it using TCPClient + StreamWriter. The server receives the raw data using TCPListner + StreamReader and writes it to the database.
Communication between applications is carried out using the TCP protocol.
Now questions: the client is sending data to the server and is waiting for confirmation to send the next. Is this how the server should respond correctly? Byte, some kind of service commands, or maybe there is a ready-made solution for this? Just reluctance to reinvent the wheel. And the second question: is the concept of the application generally correct? Maybe I overdid it with technologies (json, gzip) and shouldn't have made it so complicated.
PS Data is sent every second, the size is about 1400 bytes. At the initial stages, there will be no more than 10 clients.
Answer:
You can specify the port in the _listener prefix, the "+" sign means that all IP addresses will be listened to (you can specify a specific one). By adding functions of the "ListenerCallback" type, you can launch several listeners (by adding the required delegate to the BeginGetContext method) on different ports and create your own handler for each. It will select ports of the 30XXX type and "most likely" you will not bother anyone. Asynchrony is implemented under the old .Net, without using async await; You said that you need to compress data. The example uses the Ionic.Zip.dll library ( https://dotnetzip.codeplex.com/ ). In addition to this, I still advise you to read https://msdn.microsoft.com/ru-ru/library/system.net.httplistener(v=vs.110).aspx ;
public class Server
{
private delegate void AsyncResponse(HttpListenerContext context, ParseRequest parse);
private HttpListener _listener;
public bool Start()
{
int port = 31234;
string prefixMain = String.Format("http://{0}:{1}/", "+", port.ToString());
try
{
_listener = new HttpListener();
_listener.Prefixes.Add(prefixMain);
_listener.Start();
_listener.BeginGetContext(ListenerCallback, _listener);
Console.Write("Запущен прослушиватель запросов по адресу " + prefixMain);
return true;
}
catch (Exception ex)
{
Console.Write("Невозможно запустить прослушиватель запросов по адресу " + prefixMain + "; Ошибка :" + ex.Message);
return false;
}
}
public bool Stop()
{
try
{
_listener.Stop();
_listener = null;
Console.Write(" Сервер успешно остановлен ");
return true;
}
catch (Exception)
{
Console.Write(" Не удалось остановить сервер");
return false;
}
}
private void CallbackDelegate(IAsyncResult result)
{
AsyncResponse getAsyncresponse = (AsyncResponse)result.AsyncState;
getAsyncresponse.EndInvoke(result);
}
private void ListenerCallbackTestAsync(IAsyncResult result, ParseRequest parse, CallBackFunction callBack)
{
HttpListener listener = (HttpListener)result.AsyncState;
if (!listener.IsListening)
return;
HttpListenerContext context = listener.EndGetContext(result);
WaitCallback waite = new System.Threading.WaitCallback(GetAsyncResponse);
WaitCallbacObject waiteCallbackObject = new WaitCallbacObject() { Context = context, Parse = parse };
ThreadPool.QueueUserWorkItem(waite, waiteCallbackObject);
result = listener.BeginGetContext(new AsyncCallback(callBack), listener);
}
private void GetAsyncResponse(object state)
{
try
{
WaitCallbacObject waitCallbackObject = state as WaitCallbacObject;
HttpListenerRequest request = waitCallbackObject.Context.Request;
StreamReader input = new StreamReader(request.InputStream);
var inputText = input.ReadToEnd();
string responseString = string.Empty;
try
{
responseString = waitCallbackObject.Parse(inputText);
}
catch (Exception ex)
{
responseString = ex.ToString();
}
HttpListenerResponse response = waitCallbackObject.Context.Response;
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
Stream output = response.OutputStream;
response.AddHeader("Content-Encoding", "gzip");
byte[] pr = ZipByte(buffer);
response.ContentLength64 = pr.Length;
output.Write(pr, 0, pr.Length);
output.Close();
}
catch (Exception ex)
{
Console.Write("Ошибка при обработке запроса: " + ex.Message);
}
}
private void ListenerCallback(IAsyncResult result)
{
ParseRequest parse = ExecuteControllerMethod;
CallBackFunction callback = ListenerCallback;
ListenerCallbackTestAsync(result, parse, callback);
}
public string ExecuteControllerMethod(string inputText)
{
// Здесь можете добавить обработку вашего "внутреннего протокола"
return string.Empty;
}
private byte[] ZipByte(byte[] byteArray)
{
MemoryStream ms = new MemoryStream();
GZipStream sw = new GZipStream(ms,
CompressionMode.Compress);
sw.Write(byteArray, 0, byteArray.Length);
sw.Close();
return ms.ToArray();
}
}
public delegate void CallBackFunction(IAsyncResult result);
public delegate string ParseRequest(string inputText);
public class WaitCallbacObject
{
public HttpListenerContext Context { get; set; }
public ParseRequest Parse { get; set; }
public WaitCallbacObject() { }
}