I created a system to connect a series of TcpClient to a TcpListener and exchange data in a chat-like system. Once the connection is established, the server adds the client to a List, and starts reading the stream waiting for messages.
Once the server has received a message, is there a build-in method to know which client sent it?
Alternative: I thought of attaching the client's RemoteEndPoint (Ip + port) to the message to use it as an identifier, which should be the same between the two versions of the TcpClient on the client and on the server, and unique compared to the other clients. Am I right?
Once the server has received a message, is there a build-in method to know which client sent it?
Anything there is for you to add; typically you would maintain some nominal per-connection state alongside each Socket / TcpClient / TcpListener / NetworkStream / Pipe (your choice of API) instance, so that when receiving a message you can trivially look up whatever you need. In some cases, it may be succifient to just use the Socket / TcpClient / etc instance as a key, but more often you'll have some kind of user-state/context information. This is basically entire up to you to implement.
Related
I have a separate thread on both client and server that are reading/writing data to/from a socket.
I am using synchronous TcpClient im (as suggested in documention):
https://msdn.microsoft.com/cs-cz/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
When connection is closed .Read()/.Write() throws an exception. Does it mean that when .Write() method does not throw the data were delivered correctly to the other party or do I need to implement custom ACK logic?
I read documentation for both Socket and TcpClient class and none of them describe this case.
All that a returning send() call means (or any wrapper you use, like Socket or TcpClient) on a streaming, blocking internet socket is that the bytes are placed in the sending machine's buffer.
MSDN Socket.Send():
A successful completion of the Send method means that the underlying system has had room to buffer your data for a network send.
And:
The successful completion of a send does not indicate that the data was successfully delivered.
For .NET, the underlying implementation is WinSock2, documentation: send():
The successful completion of a send function does not indicate that the data was successfully delivered and received to the recipient. This function only indicates the data was successfully sent.
A call to send() returning does not mean the data was successfully delivered to the other side and read by the consuming application.
When data is not acknowledged in time, or when the other party sends a RST, the Socket (or whichever wrapper) will become in a faulted state, making the next send() or recv() fail.
So in order to answer your question:
Does it mean that when .Write() method does not throw the data were delivered
correctly to the other party or do I need to implement custom ACK logic?
No, it doesn't, and yes, you should - if it's important to your application that it knows another party has read that particular message.
This would for example be the case if a server-sent message indicates a state change of some sort on the client, which the client must apply to remain in sync. If the client doesn't acknowledge that message, the server cannot know for certain that the client has an up-to-date state.
In that case you could alter your protocol so that certain messages have a required response which the receiver must return. Do note that implementing an application protocol is surprisingly easy to do wrong. If you're inclined, you could implement having various protocol-dictated message flows using a state machine,
for both the server and the client.
Of course there are other solutions to that problem, such as giving each state a unique identifier, which is verified with the server before attempting any operation involving that state, triggering the retry of the earlier failed synchronization.
See also How to check the capacity of a TCP send buffer to ensure data delivery, Finding out if a message over tcp was delivered, C socket: does send wait for recv to end?
#CodeCaster's answer is correct and highlights the .NET documentation specifying the behavior of .Write(). Here is some complete test code to prove that he is right and the other answers saying things like "TCP guarantees message delivery" are unambiguously wrong:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace TestEvents
{
class Program
{
static void Main(string[] args)
{
// Server: Start listening for incoming connections
const int PORT = 4411;
var listener = new TcpListener(IPAddress.Any, PORT);
listener.Start();
// Client: Connect to listener
var client = new TcpClient();
client.Connect(IPAddress.Loopback, PORT);
// Server: Accept incoming connection from client
TcpClient server = listener.AcceptTcpClient();
// Server: Send a message back to client to prove we're connected
const string msg = "We are now connected";
NetworkStream serverStream = server.GetStream();
serverStream.Write(ASCIIEncoding.ASCII.GetBytes(msg), 0, msg.Length);
// Client: Receive message from server to prove we're connected
var buffer = new byte[1024];
NetworkStream clientStream = client.GetStream();
int n = clientStream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Received message from server: " + ASCIIEncoding.ASCII.GetString(buffer, 0, n));
// Client: Close connection and wait a little to make sure we won't ACK any more of server's messages
Console.WriteLine("Client is closing connection");
clientStream.Dispose();
client.Close();
Thread.Sleep(5000);
Console.WriteLine("Client has closed his end of the connection");
// Server: Send a message to client that client could not possibly receive
serverStream.Write(ASCIIEncoding.ASCII.GetBytes(msg), 0, msg.Length);
Console.WriteLine(".Write has completed on the server side even though the client will never receive the message. server.Client.Connected=" + server.Client.Connected);
// Let the user see the results
Console.ReadKey();
}
}
}
The thing to note is that execution proceeds normally all the way through the program and serverStream has no indication that the second .Write was not successful. This is despite the fact there is no way that second message can ever be delivered to its recipient. For a more detailed look at what's going on, you can replace IPAddress.Loopback with a longer route to your computer (like, have your router route port 4411 to your development computer and use the externally-visible IP address of your modem) and monitor that port in Wireshark. Here's what the output looks like:
Port 51380 is a randomly-chosen port representing the client TcpClient in the code above. There are double packets because this setup uses NAT on my router. So, the first SYN packet is my computer -> my external IP. The second SYN packet is my router -> my computer. The first PSH packet is the first serverStream.Write. The second PSH packet is the second serverStream.Write.
One might claim that the client does ACK at the TCP level with the RST packet, but 1) this is irrelevant to the use of TcpClient since that would mean TcpClient is ACKing with a closed connection and 2) consider what happens when the connection is completely disabled in the next paragraph.
If I comment out the lines that dispose the stream and close the client, and instead disconnect from my wireless network during the Thread.Sleep, the console prints the same output and I get this from Wireshark:
Basically, .Write returns without Exception even though no PSH packet was even dispatched, let alone had received an ACK.
If I repeat the process above but disable my wireless card instead of just disconnecting, THEN the second .Write throws an Exception.
Bottom line, #CodeCaster's answer is unambiguously correct on all levels and more than one of the other answers here are incorrect.
TcpClient uses TCP protocol which itself guarantees data delivery. If the data is not delivered, you will get an exception. If no exception is thrown - the data has been delivered.
Please see the description of the TCP protocol here: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
Every time the data is sent, the sending computer waits for the acknowledgement packet to arrive, and if it has not arrived, it will re-try the send until it is either successful, timed out, or permanent network failure has been detected (for example, cable disconnect). In the latter two cases an exception will be thrown
Therefore, TCP offeres guaranteed data delivery in the sense that you always know whether the destination received your data or not
So, to answer your question, you do NOT need to implement custom ACK logic when using TcpClient, as it will be redundant
Guarantee is never possible. What you can know is that data has left your computer for delivery to other side in the order of data was sent.
If you want a very reliable system, you should implement acknowledgement logic by yourself based on your needs.
I agree with Denis.
From the documentation (and my experience): this method will block until all bytes were written or throw an exception on error (such as disconnect). If the method returns you are guaranteed that the bytes were delivered and read by the other side on the TCP level.
Vojtech - I think you missed the documentation since you need to look at the Stream you're using.
See: MSDN NetworkStream.Write method, in the remarks section:
The Write method blocks until the requested number of bytes is sent or a SocketException is thrown.
Notes
Assuring that the message was actually read properly by the listening application is another issue and the framework cannot guarantee this.
In async methods (such as BeginWrite or WriteAsync) it's a different ballgame since the method returns immediately and the mechanism to assure completion is different (EndWrite or task completion paired with a code).
I have achieved sending message client -> server and actually connecting many clients simultaneously. But what I want to do is i.e. connect 2 clients and make them chat between themselves. And if 3rd client connects - then so he starts chatting with both other clients.
By now I am on the stage of chatting client->server->client separately from another c->s->c. What happens is - I run client1 and everything is OK. Then I run client2 and with it everything is OK, but the 1st client stops working and then the first message I acquire on the 2nd client is the last message that I sent from client1 (but that didn't actually receive back to it from server).
So I suppose there's problem with the streams - that the 2 clients somehow acquire each-other's streams.
Here is the some parts of the server (relevant ones): TheServer
HandleClientComm(object client) is handling the receive-send operations.
And here is the client side code part, that handles the receive-send operations:TheClient
And I get
An unhandled exception of type 'System.OutOfMemoryException' occurred... in
in the Server at
Byte[] bData = new Byte[BitConverter.ToInt32(bSize, 0)];
sooo... yeah, there's something wrong with the streams (on my opinion). But I don't really know how make the server distinguish between the clients' threads correctly.
I am open for any suggestions.
P.S. I am not posting the code directly here because it will get too long.
This is the first part of HandleClientComm():
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream stm = clientList[n].GetStream();
msg = new TheMessage();
You have the tcpClient, which is the client you sent as a parameter, but the NetworkStream is not for that client, but for clientList[n], and n is a class-wide variable. Later in that method, within the while loop, you use:
stm = clientList[n].GetStream();
As soon as you increase n, all threads running HandleClientComm() will receive and send messages from/to the last client.
The NetworkStream you use in HandleClientComm() should be created from the tpcClient instead, so each thread running HandleClientComm() serves its own client:
stm = theClient.GetStream();
So ideally, I am looking for a way to unite TCP and UDP on the server and manage both these connections under individual client threads. Currently, I am wondering if it is possible to accept a TCP connection and set up UDP communication from that.
Here is my ideal setup:
Client connects on TCP to server via TCPClient.connect()
Server accepts TCP connection via TCPListener
when server accepts TCP connection, it also gets the IPEndpoint from the TCP connection
and uses that to begin UDP communcation with:
serverUDPSocket.BeginReceiveFrom (byteData, 0, 1024,
SocketFlags.None, ref (Endpoint)ThatIPEndpointThatIJustMentioned,
new AsyncCallback(client.receiveUDP),
(Endpoint)ThatIPEndpointThatIJustMentioned);
^so this is where I am running into a little bit of a theoretical issue. From my understanding, the endpoints for TCP and UDP would be formatted differently. How can I resolve this issue? I would like to avoid having the client connect to UDP on a separate thread and then uniting these threads under a single managing class.
EDIT:
Here is the code that I am trying to implement:
//Listening for TCP
TcpClient newclient = listenTCP.AcceptTcpClient(); //Accept the client
Client clientr = new Client(newclient); //Create a new Client class to manage the connection
clientr.actionThread = new Thread(clientr.action); //This thread manages the data flow from the client via the TCP stream
clientr.actionThread.Start(clientr);
EndPoint endPoint = newclient.Client.RemoteEndPoint; //so this is the sketchy part. I am trying to get the endpoint from the TCP connection to set up a UDP "connection". I am unsure about the compatibility as UDP and TCP sockets are different.
UDPSocket.BeginReceiveFrom(new byte[1024],0,1024, SocketFlags.None,ref endPoint, new AsyncCallback(clientr.receiveUDP), null); //the AsyncCallBack is like the manager thread for UDP (same as in TCP)
clients.Add(clientr);
There is no problem in creating two listeners in one application, even if they use different protocol. I suppose you are not asking if you can do it on the same port (there is no point to do it anyway).
However listener is consuming thread so it need different thread if there is gui or some process to do in application (for example calculations meanwhile).
If you want to do everything in one thread you must first receive message from first listener, then setup second one. There is no possibility to setup 2 listeners in one thread at the same time because if you setup first listener it will consome whole thread waiting for message.
This was due to a lack of understanding of UDP on my part from the code level.
I ended up setting up the other method I described where it would accept initial UDP packets individually and then direct the communication (EndPoint + Message) towards a managing client class by comparing IP addresses.
I've got a strange problem. I have a client sending packets to my server, but my servers UDP socket never receives them. Same thing happens the other way around, if I send and he tries to receive.
Check this image, captured from wireshark:
http://img263.imageshack.us/img263/2636/bokus.png
I hav bound my UDP socket to EndPoint 192.168.2.3, which is the internal IP of the server, and port 9998.
The client sends data to my IP, which should then be forwarded to the local server machine..
As you can see wireshark clearly detects incomming packets for 192.168.2.3 with destination port 9998 but nothing gets delivered!
(...why does it say distinct32 btw in destination port?)
Something else to watch for is make sure any firewall you might running has a rule setup to allow communications on your port 9998.
If I had to guess (would need to see your recieving C# code to know), It looks like you might be trying to receive UDP packets but using TCP protocol on the client side. (Or i might just be misunderstanding some of the text of your screenshot.)
Theres no need to 'listen' for a connection when using UDP. UDP packets don't have a connect/disconnect protocol. Nor do they guarantee that packets are received in the same order they're sent.
try using something along these lines in your C# client and see if you get data.
var udpClient = new System.Net.Sockets.UdpClient(9998);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
I am doing projects in sockets.usually the server listens in a particular port,and the client has to connect to the port then the send and receives will happen.but we don't specify any port number in the client side,but i am in a situation to use a port in a client side, through this port only the messages will delivered to the server.how to do this?
In my client side they are restricting the ports ,so if want use to a valid free port i have to set it in the client program,instead of OS Choosing it.This is my problem.
Bind the client socket to local address (ip and port number) before connecting to server. Be ready to handle errors e.g. when the port is not available (choose next port, retry).
I guess you're using the System.Net.Sockets namespace?
If so, classes like NetworkStream take the Socket as a constructor parameter:
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx
Similarly, the TcpClient takes Port and Server as constructor arguments, Port is the same as socket in this context:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Finally. you can control the number of this socket in a few ways:
Command Line Parameter
Setting in an Application.Config file
Read it from the Registry
There are a few methods for this type of thing.