I am writing client-server type applications. Text data will be transmitted via the Internet, the speed and stability of which leaves much to be desired. The client takes the data from the file, adds his ID to it, then all this is in Json format with Gzip compression and sends it using TCPClient + StreamWriter. The server receives the original data using TCPListner + StreamReader and writes to the database.

Communication between applications are via TCP.

Now questions: the client sends data to the server and waits for confirmation to send the following. Here's how the server should respond? Bytes, service teams of some kind or maybe there is a ready-made solution for this? Just reluctant to reinvent the wheel. And the second question: is the concept of the application generally correct? Maybe I overdid it with technology (json, gzip) and it was not worth the trouble.

PS Data is sent every second, the size is approximately 1400 bytes. At the initial stages there will be no more than 10 clients.

  • I do not pretend to answer, but if memory serves me, the TCP protocol itself implies a guarantee of packet delivery, unlike, for example, from UDP: TCP: the protocol is oriented to work with connections and transmits data as byte streams. .... TCP is a "reliable" protocol, because it uses checksums to check the integrity of the data and send confirmations to ensure that the transmitted data is received without distortion. (1) . Because you can not send, I think, the client confirmation. - BlackWitcher
  • one
    The server should respond so that the client would understand. Personally, I would add a number to each message and the server would reply back with an indication of this number. When connecting, the Client requests the last received number from the server - this will solve the problem of a lost packet. But this scheme has one drawback - it is slow. Therefore, parcels and acknowledgments must be asynchronous. In general, I would take some mq ( zeromq.org for example) and did everything on it. This will solve a lot of problems. - KoVadim
  • Still here was a close question. - BlackWitcher
  • one
    So what is ZeroMQ not for you? No need to compare with MSMQ, there is a completely different approach. - Pavel Mayorov
  • one
    @ Nikolai you see, you figure it out yourself ... - Pavel Mayorov

1 answer 1

You can specify the port in the _listener prefix, the "+" sign means that all IP addresses will be obeyed (you can specify a specific one). By adding functions like "ListenerCallback" you can run several listeners (by adding the necessary delegate to the BeginGetContext method) on different ports and for each of them make your own handler. Select ports of type 30XXX and you will not disturb anyone most likely. Asynchrony is implemented under the old .Net, without using async await; You said you need to compress the data. The example uses the Ionic.Zip.dll library ( https://dotnetzip.codeplex.com/ ). In addition to this, I still advise you to familiarize yourself with 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() { } } 
  • one
    Of course interesting! A couple of times on the forums I came across information that you can use HTTP, but somehow it didn’t get to the implementation. And I immediately had a question: will port 80 be used? Browser operation will not somehow interfere with the transfer of data? - Nikolay
  • @ Nikolay please read about TCP protocol in order not to ask such questions. No, the browser does not hurt. But Skype is famous for the fact that it loves to “pry” its 80th port. - Pavel Mayorov