0

I'm working on a C# Docker application, where I am creating a microservice in order to handle TCP socket communication. This works, but it seems to be very unstable (some packets pass, some not). I have added a log entry, which might explain something (it's about sending a message over a TCP socket):

Source code (shown on multiple lines, but it's a oneliner):

Debug.WriteLine(
  $"T[{System.Threading.Thread.CurrentThread.ManagedThreadId}], 
  {DateTime.UtcNow}: Handle().
  Trying to send [{Message}] to [{ConnectionName}]");

Results:

T[14], 12/14/2022 15:26:08: Handle(). Trying to send [abc] to [XL_Test]
T[19], 12/14/2022 15:26:32: Handle(). Trying to send [abc] to [XL_Test]

As you can see, apparently my application always uses another thread to handle the requests. So, I'm left with a very simple question: is multithreaded programming allowed when working with TCP sockets?

For your information: I have already worked with multithreaded applications on TCP sockets before, where one thread was used for regular checking the connection and another for sending the messages, but here I have one thread which regularly checks the connection, while for sending messages, always another thread gets opened.

Edit: I don't know if this is helpful, but the name of the thread, handling the message, is .Net ThreadPool Worker.

Edit2: this is the way this Send() method is called:

await _mediator.Send(command);

... where _mediator is an IMediator from the MediatR library.

The first comment refers to another StackOverflow post which is using locks, but while trying this, I got a compilation error:

object lockobject = new object();
lock(lockobject)
{ 
    await _mediator.Send(command);
}

The compiler message is CS1996: Cannot await in the body of a lock statement. (Pardon my ignorance, but I'm very new at this)

David Maze
  • 130,717
  • 29
  • 175
  • 215
Dominique
  • 16,450
  • 15
  • 56
  • 112
  • Here is similar question: https://stackoverflow.com/q/37459837/5311735 – Evk Dec 15 '22 at 07:40
  • 2
    TCP is *implemented* using packets but that's not the abstraction exposed to us. The abstraction TCP provides is an *endless stream of bytes*. If you want "packets" or "messages" atop TCP, it's up to *you* to perform message framing. – Damien_The_Unbeliever Dec 15 '22 at 07:40
  • @Evk: I've tried to add a lock, as mentioned in the referred post, but this seems not to be possible. For your information, I can't remove the `await` command. – Dominique Dec 15 '22 at 07:54
  • If you have no specific reason to use raw TCP, I would recommend using an existing protocol, since this will handle message frameing etc for your. See Stephen clearys [article about TCP](https://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html) for all the things you need to do yourself otherwise. `TcpClient` is not thread safe, so while it can be used in a multithreaded application, but it cannot be used from multiple threads. It is not very clear what you are actually doing, so it will be difficult to provide specific help. – JonasH Dec 15 '22 at 07:56
  • @JonasH: I must use TCP sockets (the whole firm is based on this technology, I can't get out of this), and I'm not using the `TcpClient` class (it's nowhere to be found in my application). – Dominique Dec 15 '22 at 07:58
  • https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket?view=net-7.0#thread-safety, However, what does `Send()` do? – Jodrell Dec 15 '22 at 08:06
  • @Jodrell: `Send()` tries to send a message over a TCP socket. First it tries to connect, then it checks the connection and in case the connection is oké, the message is sent. I fear that, when this is handled every time by another thread, that something might go wrong. – Dominique Dec 15 '22 at 08:11
  • 1
    As mentioned in that answer - socket is thread safe. That doesn't mean your program as a whole will be thread safe though. You might or might not need locks but we can't tell without more code. There are async constructs with lock semantics if you would need them. However, "some packets loss" is likely caused by something else, for example by assuming TCP has a concept of message as mentioned in comments above. – Evk Dec 15 '22 at 08:21
  • @Evk: we send data over TCP sockets and use `Encoding.GetEncoding(1252).GetString(sent_data)` for decoding it into messages. The goal of my question was to judge if the multithreaded approach might be the cause of the instability I'm facing. Your answer is "*most probably not*", which I accept as an answer, and I'll look for other possible causes of the instability. Thanks a lot for your time and effort on this. – Dominique Dec 15 '22 at 08:26
  • 2
    The most common problem with sending data with tcp is people do Send(someData) and then expect, on the other side, to get this data with single Receive. If you send strings for example, you need to prefix it with length (or use some other framing mechanism), Then on receive side you first read bytes with length (say length is int, so 4 bytes, you read 4 bytes first). Now you know the length and then you keep reading until you get all bytes. Sending just strings without framing might often work on localhost, but fail in general. – Evk Dec 15 '22 at 08:34
  • 1
    I confirm: there's no issue with reading/writing sockets from different threads. In fact, this is the normal approach. I usually recommend having a continuous read going (as soon as one completes, start the next), and queueing writes. So there's only one read and zero or one writes going at a time. Any of these reads and writes can be done from any thread. – Stephen Cleary Dec 15 '22 at 10:43

0 Answers0