This is to a degree a "basics of TCP" question, yet at the same time I have yet to find a convincing answer elsewhere and believe i have a ok/good understanding of the basics of TCP. I am not sure if the combination of questions (or the one questions and while i'm at it the request for confirmation of a couple of points) is against the rules. Hope not.
I am trying to write a C# implementation of a TCP client, that communicates with an existing app containing a TCP server (I don't have access to its code, so no WCF). How do I connect to it, send and receive as needed as new info comes in or out, and ultimately disconnect. Using the following MSDN code as an example where they list "Send" and "Receive" asynchronous methods (or just TcpClient), and ignoring the connect and disconnect as trivial, how can I best go about continuously checking for new packets received and at the same time send when needed?
I initially used TCPClient and GetStream(), and the msdn code still seems to require the loop and sleep described in a bit (counter intuitively), where I run the receive method in a loop in a separate thread with a sleep(10) milliseconds, and Send in the main (or third) thread as needed. This allows me to send fine, and the receive method effectively polls at regular intervals to find new packets. The received packets are then added to a queue.
Is this really the best solution? Shouldn't there be a DataAvailable event equivalent (or something i'm missing in the msdn code) that allows us to receive when, and only when, there is new data available?
As an afterthought I noticed that the socket could be cut from the other side without the client becoming aware till the next botched send. To clarify then, the client is obliged to send regular keepalives (and receive isn't sufficient, only send) to determine if the socket is still alive. And the frequency of the keepalive determines how soon I will know that link is down. Is that correct? I tried Poll, socket.connected etc only to discover why each just doesn't help.
Lastly, to confirm (i believe not but good to make sure), in the above scenario of sending on demand and receiving if tcpclient.DataAvailable every ten seconds, can there be data loss if sending and receiving at the same time? If at the same time I am receiving I try and send will one fail, overwrite the other or any other such unwanted behaviour?
There's nothing wrong necessarily with grouping questions together, but it does make answering the question more challenging... :)
The MSDN article you linked shows how to do a one-and-done TCP communication, that is, one send and one receive. You'll also notice it uses the Socket class directly where most people, including myself, will suggest using the TcpClient class instead. You can always get the underlying Socket via the Client property should you need to configure a certain socket for example (e.g., SetSocketOption()).
The other aspect about the example to note is that while it uses threads to execute the AsyncCallback delegates for both BeginSend() and BeginReceive(), it is essentially a single-threaded example because of how the ManualResetEvent objects are used. For repeated exchange between a client and server, this is not what you want.
Alright, so you want to use TcpClient. Connecting to the server (e.g., TcpListener) should be straightforward - use Connect() if you want a blocking operation or BeginConnect() if you want a non-blocking operation. Once the connection is establish, use the GetStream() method to get the NetworkStream object to use for reading and writing. Use the Read()/Write() operations for blocking I/O and the BeginRead()/BeginWrite() operations for non-blocking I/O. Note that the BeginRead() and BeginWrite() use the same AsyncCallback mechanism employed by the BeginReceive() and BeginSend() methods of the Socket class.
One of the key things to note at this point is this little blurb in the MSDN documentation for NetworkStream:
Read and write operations can be performed simultaneously on an
instance of the NetworkStream class without the need for
synchronization. As long as there is one unique thread for the write
operations and one unique thread for the read operations, there will
be no cross-interference between read and write threads and no
synchronization is required.
In short, because you plan to read and write from the same TcpClient instance, you'll need two threads for doing this. Using separate threads will ensure that no data is lost while receiving data at the same time someone is trying to send. The way I've approached this in my projects is to create a top-level object, say Client, that wraps the TcpClient and its underlying NetworkStream. This class also creates and manages two Thread objects, passing the NetworkStream object to each during construction. The first thread is the Sender thread. Anyone wanting to send data does so via a public SendData() method on the Client, which routes the data to the Sender for transmission. The second thread is the Receiver thread. This thread publishes all received data to interested parties via a public event exposed by the Client. It looks something like this:
Client.cs
public sealed partial class Client : IDisposable
{
// Called by producers to send data over the socket.
public void SendData(byte[] data)
{
_sender.SendData(data);
}
// Consumers register to receive data.
public event EventHandler<DataReceivedEventArgs> DataReceived;
public Client()
{
_client = new TcpClient(...);
_stream = _client.GetStream();
_receiver = new Receiver(_stream);
_sender = new Sender(_stream);
_receiver.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
Client.Receiver.cs
private sealed partial class Client
{
private sealed class Receiver
{
internal event EventHandler<DataReceivedEventArgs> DataReceived;
internal Receiver(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for receiving data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Client.Sender.cs
private sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
// transition the data to the thread and send it...
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for sending data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Notice that these are three separate .cs files but define different aspects of the same Client class. I use the Visual Studio trick described here to nest the respective Receiver and Sender files under the Client file. In a nutshell, that's the way I do it.
Regarding the NetworkStream.DataAvailable/Thread.Sleep() question. I would agree that an event would be nice, but you can effectively achieve this by using the Read() method in combination with an infinite ReadTimeout. This will have no adverse impact on the rest of your application (e.g., UI) since it's running in its own thread. However, this complicates shutting down the thread (e.g., when the application closes), so you'd probably want to use something more reasonable, say 10 milliseconds. But then you're back to polling, which is what we're trying to avoid in the first place. Here's how I do it, with comments for explanation:
private sealed class Receiver
{
private void Run()
{
try
{
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutdownEvent.WaitOne(0))
{
try
{
// We could use the ReadTimeout property and let Read()
// block. However, if no data is received prior to the
// timeout period expiring, an IOException occurs.
// While this can be handled, it leads to problems when
// debugging if we are wanting to break when exceptions
// are thrown (unless we explicitly ignore IOException,
// which I always forget to do).
if (!_stream.DataAvailable)
{
// Give up the remaining time slice.
Thread.Sleep(1);
}
else if (_stream.Read(_data, 0, _data.Length) > 0)
{
// Raise the DataReceived event w/ data...
}
else
{
// The connection has closed gracefully, so stop the
// thread.
ShutdownEvent.Set();
}
}
catch (IOException ex)
{
// Handle the exception...
}
}
}
catch (Exception ex)
{
// Handle the exception...
}
finally
{
_stream.Close();
}
}
}
As far as 'keepalives' are concerned, there is unfortunately not a way around the problem of knowing when the other side has exited the connection silently except to try sending some data. In my case, since I control both the sending and receiving sides, I've added a tiny KeepAlive message (8 bytes) to my protocol. This is sent every five seconds from both sides of the TCP connection unless other data is already being sent.
I think I've addressed all the facets that you touched on. I hope you find this helpful.
Related
I'm building a C# Socket Server. My code currently works but I am not sure if this is the correct way to do it.
When a TcpClient is connected I put it in a new object with the following Methods, I then call Init() to start checking if data is available, when data is available I call an event that I listen on to start reading the buffer using methods I created like ReadInt32(), ReadByte(), ReadString() ReadObject<T>()
public void Init()
{
ThreadPool.QueueUserWorkItem(Read);
}
private void Read(object state)
{
if (IsClientConnected())
{
if (_connected.Available > 0)
{
OnDataAvailable(_connected.Available);
}
Init();
}
}
Should I use a While loop here or should I restart the Init() like I am currently doing? Then should I use a BackgroundWorker, Thread, or Task instead of ThreadPool?
I also was thinking of changing Init() to BeginWait(some sort of callback here) and removing the Init() inside the Read() and then just call BeginWait again where needed
My purpose is to listen to commands and reply on commands. With an x number of clients connected at the same time.
So the scenario is as follow:
I have an application that connects to the server.
The server then Initializes a new object with TcpClient as a parameter in the constructor. The server then adds the connected client to a room with another client. This room listens on each of the client's events DataAvailable look at following
private void Client_DataAvailable(ClientWrapper sender, int data)
{
var command = (Commands)Client.ReadByte();
switch (command)
{
case Commands.RequestConnectId: // 1
var buffer = new WriteBuffer(Commands.RequestConnectId);
buffer.WriteInt32(sender.ConnectId);
sender.Reply(buffer);
break;
case Commands.WriteText: //2
var buffer = new WriteBuffer(Commands.WriteText);
buffer.WriteString(sender.ReadString());
BroadCast(sender.ConnectId,buffer);//Send to the other client
break;
}
}
The correct way to read a socket is to just read from it. The call will not complete until data is ready. There is no need for events. The Available property almost always is a bug so don't use that.
Just execute:
var command = (Commands)Client.ReadByte();
immediately. It is fine to run that on a background thread (as opposed to what was suggested in the comments). Threads become a problem once you have too many of them. If you maintain a few dozen socket connections only there is no issue with that.
You also could use async IO preferably with await. The same idea applies: Just read.
If you want to process a stream of command simply wrap this in a loop:
while (true) {
ReadCommand();
WriteResponse();
}
Multithread programming is a new concept for me. I’ve done a bunch of reading and even with many examples, I just can’t seem to figure it out. I'm new to C# and programming.
I have a winform project with lots of custom controls I’ve imported and will utilize many tcpclients. I’m trying to get each control to be hosted on it’s own separate thread. Right now, I’m trying to get 1 control to behave appropriately with it’s own thread.
I'll show you what I have and then follow up with some questions regarding guidance.
string asyncServerHolder; // gets the server name from a text_changed event
int asyncPortHolder; // gets the port # from a text_changed event
TcpClient wifiClient = new TcpClient();
private void btnStart_Click(object sender, EventArgs e)
{
... // variable initialization, etc.
... // XML setup, http POST setup.
send(postString + XMLString); // Content to send.
}
private void send(string msg)
{
AsyncCallback callBack = new AsyncCallback(ContentDownload);
wifiClient.BeginConnect(asyncServerHolder, asyncPortHolder, callBack, wifiClient);
wifiClient.Client.Send(System.Text.Encoding.ASCII.GetBytes(msg));
}
private void ContentDownload(IAsyncResult result)
{
if (wifiClient.Connected)
{
string response4 = "Connected!!"; //debug msg
byte[] buff = new byte[1024];
int i = wifiClient.Client.Receive(buff);
do
{
response1 = System.Text.Encoding.UTF8.GetString(buff, 0, i);
} while (response1.Length == 0);
response2 = response1.Substring(9, 3); // pick out status code to be displayed after
wifiClient.Client.Dispose();
wifiClient.Close();
}
}
If you're knowledgeable about this, I bet you see lots of problems above. As it stands right now, I always get an exception one my first iteration of running this sequence:
"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied"
Why is this? I have confirmed that my asyncServerHolder and my asyncPortHolder are correct. My second iteration of attempting allowed me to see response4 = "Connected!!" but I get a null response on response1.
Eventually I'd like to substitute in my user controls which I have in a List. I'd just like to gracefully connect, send my msg, receive my response and then allow my form to notify me from that particular control which plays host to that tcp client. My next step would be link up many controls.
Some questions:
1) Do I need more TCP clients? Should they be in a list and be the # of controls I have enabled at that time of btnStart_Click?
2) My controls are on my GUI, does that mean I need to invoke if I'm interacting with them?
3) I see many examples using static methods with this context. Why is this?
Thanks in advance. All criticism is welcome, feel free to be harsh!
BeginConnect returns immediately. Probably, no connection has been established yet when Send runs. Make sure that you use the connection only after having connected.
if (wifiClient.Connected) and what if !Connected? You just do nothing. That's not a valid error recovery strategy. Remove this if entirely.
In your read loop you destroy the previously read contents on each iteration. In fact, you can't split up an UTF8 encoded string at all and decode the parts separately. Read all bytes into some buffer and only when you have received everything, decode the bytes to a string.
wifiClient.Client.Dispose();
wifiClient.Close();
Superstitious dispose pattern. wifiClient.Dispose(); is the canonical way to release everything.
I didn't quite understand what "controls" you are talking about. A socket is not a control. UI controls are single-threaded. Only access them on the UI thread.
Do I need more TCP clients?
You need one for each connection.
Probably, you should use await for all blocking operations. There are wrapper libraries that make the socket APIs usable with await.
I have a problem with the SocketAsyncEventArgs class..the problem is when I try to send 8K of data
for example over internet, the socket sometimes only sends 1K or 2K, I know that this is normal for
TCP socket and that one send doesn't guarantee one receive.
now for this to work for me I modified my code to resend the remaining data, for example
when I the SocketAsyncEventArgs.SendAsync completes, in the callback i check whether it sent all the 8K or not if it's not, I call the SocketAsyncEventArgs.SendAsync again with the remaining data untill
I send it all.
Now, when I looked at some SocketAsyncEventArgs code.. I saw that most people don't do so!
and they just clean up when the send complete without checking if it sent all the data or not!
also when I looked at Microsoft's example, they were saying the ONE call to SocketAsyncEventArgs.SendAsync guarantees that all the data will be sent.
I mean I tested it myself and NO all data will not be sent in one call to SocketAsyncEventArgs.SendAsync.
What I'm doing wrong ?
thanks in advance.
Edit:
Here is the code which doesn't send all data(exactly like microsoft's)
the SendAsyncComplete will be called when the socket sends for example 1Kb of data
not all 8K!
public virtual void Send(byte[] packet, int offset, int length)
{
if (_tcpSock != null && _tcpSock.Connected)
{
var args = SocketHelpers.AcquireSocketArg();
if (args != null)
{
args.Completed += SendAsyncComplete;
args.SetBuffer(packet, offset, length);
args.UserToken = this;
var willRaiseEvent = _tcpSock.SendAsync(args);
if (!willRaiseEvent)
{
ProcessSend(args);
}
unchecked
{
_bytesSent += (uint)length;
}
Interlocked.Add(ref _totalBytesSent, length);
}
else
{
log.Error("Client {0}'s SocketArgs are null", this);
}
}
}
private static void ProcessSend(SocketAsyncEventArgs args)
{
args.Completed -= SendAsyncComplete;
SocketHelpers.ReleaseSocketArg(args);
}
private static void SendAsyncComplete(object sender, SocketAsyncEventArgs args)
{
ProcessSend(args);
}
There are many things I would change there. As a preamble, read this.
First of all, whenever you sent any data on the socket, you must process that event: either you stop the whole send process, or you issue another socket send operation to send the remaining data.
So it makes sense to have 3 methods, like this:
// This is the Send() to be used by your class' clients
1) public void Send(byte[] buffer);
This method will take care to apply any data formatting that you need, create (retrieve) a SocketAsyncEventArgs object, set the token to hold your buffer, and call the next method bellow:
2) private void Send(SocketAsyncEventArgs e);
This one actually calls
Socket.SendAsync(SocketAsyncEventArgs e)
and copies the contents from the token (the buffer, remember?) to the SAEA object. Now that is why because method number (2) might be called several times to send the remaining data that couldn't be sent in one operation by the socket. So here you copy the remaining data from the token to the SAEA buffer.
3) private void ProcessSent(SocketAsyncEventArgs e);
This last method will examine the data that has been sent by the socket. If all the data has been sent, the SAEA object will be released. If not, method (2) will be called again for the rest of the data. In order to keep track of sent data, you use SAEA.BytesTransferred. You should add this value to a value stored in the custom token I advise you to create (so do not use "this" as a token).
This is where you also check for SocketError on the SAEA parameter.
This last method will be called in two places:
in the 2nd method, like this:
// Attempt to send data in an asynchronous fashion
bool isAsync = this.Socket.SendAsync(e);
// Something went wrong and we didn't send the data async
if (!isAsync)
this.ProcessSent(e);
This bit is important any many people missed it even when using the more traditional Begin/EndXXX pattern (in that case, via IAsyncResult). If you don't place it, once in a while (quite rare), a StackOverflow exception will pop out of nowhere and will keep you puzzled for long time.
in the Completed event handler:
private void Completed(object sender, SocketAsyncEventArgs e)
{
// What type of operation did just completed?
switch (e.LastOperation)
{
case SocketAsyncOperation.Send:
{
ProcessSent(e);
break;
}
}
}
The tricky thing is to use one SocketAsyncEventArgs object per 1st Send(byte[]) operation, and release it in 3rd operation, if all data has been sent.
For that, you must create a custom token (class or immutable struct) to place in SocketAsyncEventArgs.UserToken inside the 1st method, and then keep track of how much data you have transferred on each Socket.SendAsync() operation.
When you are reading the article provided in the beginning, notice how the writer reuses the same SAEA object when at the end of Send() operation proceeds with a Receive() operation, if all the data has been sent. That is because his protocol is: each one of the parties (server and client) talk to each other in turns.
Now, should multiple calls to the 1st Send() method occur at the same time, there is no rule in which order they will be handled by the OS. If that is likely to happen and message order is important, and since any call to Send(byte[]) from an "outside entity" result in a Socket.SendAsync(), I suggest that the 1st method actually writes down the received bytes in an internal buffer. As long as this buffer is not empty, you keep sending this data internally. Think of it like a producer-consumer scenario, where the "outside entity" is the producer and the internal send op is the consumer. I prefer an optimistic concurrency scenario here.
The documentation on the matter is rather shallow, with the exception of this article, and even in this case, when you start implementing your own application, some things turn out to be different. This SocketAsyncEventArgs model is arguably a bit counter-intuitive.
Let me know if you need more help, I had my times of struggle with this a while ago when I developed my own library.
Edit:
If I were you, I would move
unchecked
{
_bytesSent += (uint)length;
}
Interlocked.Add(ref _totalBytesSent, length);
to your ProcessSend(SAEA), and use args.BytesTransferred instead of "length".
I'm pretty new to serialization so please bear with me.
I want two instances of my application to communicate with each other over the internet. I have successfully rigged up a TCP client/server relationship and used a binary formatter to get the two sides to swap a single pair of messages. Here's the client side...
using (TcpClient clientSocket = new TcpClient(ipAddress, currentPort))
{
using (NetworkStream stream = clientSocket.GetStream())
{
// send
bformatter.Serialize(stream, new Message());
// recv
return (Message)bformatter.Deserialize(stream);
}
}
It's cool, but not very useful for an application that needs to send messages in response to user events. So I need to be able to send and receive asynchronously.
I basically want an interface that behaves like this:
class BidirectionalObjectStream
{
public BidirectionalObjectStream(TcpClient client)
{
//...
}
// objects go in here
public void SendObject(object o)
{
//...
}
// objects come out here
public event Action<object> ObjectReceived;
}
Is there a class like this that's part of .NET? If not, how should I implement the receive event? Maybe a dedicated thread calling bformatter.Deserialize() repeatedly...?
Any help appreciated.
The question is a little broad.
I can think of two options:
Use asynchronous socket. Using an Asynchronous Client Socket
Create separate threads for receiving and sending. There many ways to achieve it, raw Thread, ThreadPool, delegate.Invoke, new TPL features like Task and Parallel.
With respect to C# and .NET's System.Net.Sockets.Socket.AcceptAsync method, one would be required to handle a return value of "false" in order to handle the immediately available SocketAsyncEventArgs state from the synchronously processed connection. Microsoft provides examples (found on the System.Net.Sockets.SocketAsyncEventArgs class page) which will cause a stack overflow if there are a large amount of pending connections, which can be exploited on any system that implements their handling model.
Other ideas for getting around this issue are to make a loop that calls the handler method, with the condition being that the value Socket.AcceptAsync returns is equal to false, and to break the loop (to allow deferred processing) if the value is indicating that the operation is being completed asynchronously (true). However, this solution also causes a stack overflow vulnerability because of the fact that the callback associated with the SocketAsyncEventArgs passed to Socket.AcceptAsync has at the end of the method, a call to Socket.AcceptAsync, which also has a loop for immediately available, synchronously accepted, connections.
As you can see, this is a pretty solid problem, and I've yet to find a good solution that does not involve System.Threading.ThreadPool and creating tons of other methods and scheduling processing. As far as I can see, the asynchronous socket model relating to Socket.AcceptAsync requires more than what is demonstrated in the examples on MSDN.
Does anyone have a clean and efficient solution to handling immediately pending connections that are accepted synchronously from Socket.AcceptAsync without going into creating separate threads to handle the connections and without utilizing recursion?
I wouldn't use AcceptAsync, but rather BeginAccept/EndAccept, and implement the common async pattern correctly, that is, checking for CompletedSynchronously to avoid callbacks in the callback thread on operations which completed .
See also AsyncCallBack CompletedSynchronously
Edit regarding the requirement to use AcceptAsync:
The MSDN documentation explicitly says that the callback will NOT be invoked for operations which completed synchronously. This is different to the common async pattern where the callback is always invoked.
Returns true if the I/O operation is
pending. The
SocketAsyncEventArgs.Completed event
on the e parameter will be raised upon
completion of the operation. Returns
false if the I/O operation completed
synchronously. The
SocketAsyncEventArgs.Completed event
on the e parameter will not be raised
and the e object passed as a parameter
may be examined immediately after the
method call returns to retrieve the
result of the operation.
I currently don't see how a loop would not solve the stack overflow issue. Maybe you can be more specific on the code that causes the problem?
Edit 2: I'm thinking of code like this (only in regard to AcceptAsync, the rest was just to get a working app to try it out with):
static void Main(string[] args) {
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 4444));
listenSocket.Listen(100);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += AcceptCallback;
if (!listenSocket.AcceptAsync(e)) {
AcceptCallback(listenSocket, e);
}
Console.ReadKey(true);
}
private static void AcceptCallback(object sender, SocketAsyncEventArgs e) {
Socket listenSocket = (Socket)sender;
do {
try {
Socket newSocket = e.AcceptSocket;
Debug.Assert(newSocket != null);
// do your magic here with the new socket
newSocket.Send(Encoding.ASCII.GetBytes("Hello socket!"));
newSocket.Disconnect(false);
newSocket.Close();
} catch {
// handle any exceptions here;
} finally {
e.AcceptSocket = null; // to enable reuse
}
} while (!listenSocket.AcceptAsync(e));
}
I have resolved this problem by simply changing the placement of the loop. Instead of recursively calling the accept handler from within itself, wrapping the code in a do-while loop with the condition being "!Socket.AcceptAsync(args)" prevents a stack overflow.
The reasoning behind this is that you utilize the callback thread for processing the connections which are immediately available, before bothering to asynchronously wait for other connections to come across. It's re-using a pooled thread, effectively.
I appreciate the responses but for some reason none of them clicked with me and didn't really resolve the issue. However, it seems something in there triggered my mind into coming up with that idea. It avoids manually working with the ThreadPool class and doesn't use recursion.
Of course, if someone has a better solution or even an alternative, I'd be happy to hear it.
I haven't looked carefully, but it smells like this might be helpful (see the section called "stack dive"):
http://blogs.msdn.com/b/mjm/archive/2005/05/04/414793.aspx
newSocket.Send(Encoding.ASCII.GetBytes("Hello socket!"));
newSocket.Disconnect(false);
newSocket.Close();
The problem with this snippet above is that this will block your next accept operation.
A better way is like this:
while (true)
{
if (e.SocketError == SocketError.Success)
{
//ReadEventArg object user token
SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
Socket socket = ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;
if (!socket.ReceiveAsync(readEventArgs))
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessReceiveEx), readEventArgs); .
}
else
{
HadleBadAccept(e);
}
e.AcceptSocket = null;
m_maxNumberAcceptedClients.WaitOne();
if (listenSocket.AcceptAsync(e))
break;
}
The SocketTaskExtensions contains useful method overloads for the Socket class. Rather than using the AsyncCallback pattern, the AcceptAsync extension method can be called with ease. It is also compatible with the task asynchronous programming (TAP) model.
There is two basic operation to consider:
Start the listening: As usual socket needs to Bind to a specific IP address and port. Then place the socket in listening state (Listen method). After that it is ready to handle the incoming communication.
Stop the listening: It stops accepting the incoming requests.
bool _isListening = false;
public Task<bool> StartListening()
{
Socket listeningSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
listeningSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
listeningSocket.Listen(10);
return HandleRequests(listeningSocket);
}
public void StopListening()
{
_isListening = false;
}
In order to handle incoming requests, the listening socket accepts (AcceptAsync) the incoming client connection. Then Send or Receive message from the accepted socket. It accepts incoming connection until StopListening was called.
internal async Task<bool> HandleRequests(Socket listeningSocket)
{
try
{
_isListening = true;
while (_isListening)
{
byte[] message = Encoding.UTF8.GetBytes("Message");
byte[] receivedMessage = new byte[1024];
using (Socket acceptedSocket = await listeningSocket.AcceptAsync())
{
// Send messages
acceptedSocket.Send(message);
// Receive messagges
acceptedSocket.Receive(receivedMessage);
}
}
}
catch (SocketException)
{
// Handle error during communication.
return false;
}
return true;
}
Note:
Messages could be exceed the buffer size. In that case try continuously receive until end of the data. Stephen Clearly message framing blog post is good starting point.
Sending and receiving also could be asynchronous. NetworkStream can be created from the accepted socket then we can await to the ReadAsnyc and WriteAsync operations.