C# Establish client-client connection in server-client model - c#

I'm writing a client-server application using C# TcpListener and TcpClient. Here's what i have right now:
//Server
class Listener
{
List<Client> clients; //list of clients
TcpListener listener;
//client accepting method
async void Listen()
{
while (Listening)
{
Client client = new Client(await listener.AcceptTcpClientAsync());
clients.Add(client).
client.Exchange(); //wait for client's messages
}
//...
}
}
class Client //client handling class
{
TcpClient conn;
public Client(TcpClient conn)
{
this.conn = conn;
}
}
and a simple client code that just connects to server, awaits messages from it and sends message on button click, which server broadcasts to all other users. Now i want to have an ability to establish a straight connection between two clients (for private messaging and further features).
I know there's a Socket property in TcpClient and Local/RemoteEndPoint property in Socket, so server already has some information about both client hosts. I even tried to create a Socket with another clients RemoteEndPoint, but this, obviously, shouldn't work because port is in use by server. It is possible to notify both clients with required information through Server (Client class allows to play with clients individually), but how to establish TCP connection silently for both clients (i.e. no firewall messages), even for usual clients hidden under firewall and NAT-router?

Related

UDP NAT Hole Punching on separate UdpClient objects

I believe I am having an issue with NAT hole punching via UdpClient objects. I have a simple class that looks like:
class UdpConnection
{
UdpClient udpSend { get; set; }
UdpClient udpRecv { get; set; }
IpEndPoint TargetEndPoint { get; set; }
UdpConnection(IPEndPoint targetEndPoint)
{
TargetEndPoint = targetEndPoint;
}
void SendTo(byte[] bytes)
{
udpSend.Client.SendTo(bytes, TargetEndPoint);
}
void TryToConnect () { // ... // }
void WaitForConnect () { // ... // }
}
A client will use one of these objects and call TryToConnect(). The client will then use UdpConnection.udpRecv.Client.SendTo() to send a Hello packet to the server and then sleep for a second waiting for a response. When the Hello is acknowledge it then uses UdpConnection.udpRecv only for listening, updates the UdpConnection.udpSend object to use the target port given by the server to send further data and is then considered connected.
A server uses a dedicated UdpClient object to listen on for new connections. When it receives a new remote address it creates a new UdpConnection object with the new address, creates an Acknowledgement packet providing the specific port for this new connection to send data to and then listen on that port and send the Acknowledgement packet.
This all works when ran locally but the client will fail to receive the Acknowledgement packet when ran remotely. What makes me think this is a NAT Hole punching issues is that if I send the acknowledgement back on the server's listening port, the one that received the new connection, the client receives it. This makes me feel like I am missing something.
Where have I gone wrong? Is it that I am attempting to hand off the response to a new UdpClient instead of the one the client connected to? Do I have to handle the whole handshake on the Listening Port until the client uses its new dedicated port on the server?

C# .Net Socket Server Client

I've got a little problem with the .Net Sockets in C#.
I programmed a client and a server working with TCP.
As the client is opened it sends a handshake to the server. The server answers with it's state (clientexists, clientaccepted,...). After that the application sends a getdata-request, abandons the connection and listens for the server's 'response'. Now, the server builds a connection to the client and sends all the data the client needs.
The code and everything else works, but the problem:
On our company testserver it works fine, on the live server only the handshake works. After it the client doesn't receive any more data. Serverapplication is the same on both servers.
I thought the problem was caused by some firewall (server wants to build a tcp connection to the client -> not good), but the system administrator said there is no firewall that could block that.
Now I'm searching for a ('cheap') solution that doesn't take too much time and changes in code. If anyone knows how to theoretically solve that, that would be great.
BTW: I am not allowed to do anything on the live server other than run the serverapplication. I don't have the possibility to debug on this server.
I can't publish all of my code, but if you need to see specific parts of it, ask for it please.
---EDIT---
Client-Server communication
1) Client startup
Client send handshake (new tcp connection)
2) Server validates handshake and saves IP
Server responds with it's client state (same tcp connection)
3) Client acknowledges this response and abandons this connection
Client sends getdata-request (new tcp connection)
Client abandons this tcp connection, too
4) Server receives getdata-request and collects the needed data in the main database
Server sends all the collected data to the client (multiple tcp connections)
5) Client receives all data and displays it in it's GUI (multiple tcp connections and the order of the data is kept by working with AutoResetEvents and Counts of sockets to send)
This is the main part my code does. It's by far not the best but it was for me as I wrote it I guess. Step one, two and three work as intended. The processing of the data works fine, too.
Another thing i forgot to mention is that the solution uses two Ports '16777' and '16778'. One to receive/listen and one to send.
My code is based on the MSDN example of the asynchronous server and client.
Sending a handshake (and getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
Server listener
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
Socket send
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket send all data part (answer to getdata-request | socToHandle should be the socket of the previous connection of the getdata-request)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
Looking through my old code I have one idea =>
Could I send everything over the same connection by changing:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(which creates a new connection) to something that uses the same connection?
If that would work, how can I do that?
And would the listener part of the client still receive single packets?
Servers and their environment are configured to handle incoming requests properly. Clients are usually behind a router, which by default make them unable to receive incoming connections from outside their network (a good thing).
To enable incoming connections, you could configure your router to forward all requests for a certain port number to your machine. No one else on your network would be able to run the client then, though.
This is why in a typical multiple clients-single server environment, the client makes all the connections, and only the server requires any changes to the network landscape.
I don't know why you chose to connect to the clients from the server side, but I would strongly advise against this - any cheap solution that uses this mechanism may turn out to be very expensive in the end.

C# TCP Socket Communicator - handle special messages between client and server

I want to learn about socket communication so I decided to try to write WP 8.1 text communicator. It is based on TCP sockets. I almost managed to finish it, but I am searching for improvemenets.
What is worth mentioning I use a socket server between phones (console application), to avoid problems with private ip addresses. It contains information about all connected users and forwards messages to clients (for instance user A sends message to user B, so firstly message goes to server and server forward it to destination address).
The problem appeared when i realized that I need to send special messages from server to client and vice versa (for example when two clients want to have conversation, they send request to server, so it knows where to forward messages).
This is my connection listener method from server application
private void ConnectionListener()
{
IPEndPoint localDataEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 1234);
IPEndPoint localMessageEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 4321);
Socket dataConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket messageConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
dataConnectionListener.Bind(localDataEndPoint);
dataConnectionListener.Listen(100);
messageConnectionListener.Bind(localMessageEndPoint);
messageConnectionListener.Listen(100);
while (true)
{
TcpSocket.clientDone.Reset();
IAsyncResult tmp1 = dataConnectionListener.BeginAccept(ConnectionCallback, null);
IAsyncResult tmp2 = messageConnectionListener.BeginAccept(ConnectionCallback, null);
TcpSocket.clientDone.WaitOne();
Socket dataSocket = dataConnectionListener.EndAccept(tmp1);
Socket messageSocket = messageConnectionListener.EndAccept(tmp2);
TcpSocket tmpTcpSocket = new TcpSocket(dataSocket, messageSocket);
tmpTcpSocket.Start();
connectedUsersSockets.Add(tmpTcpSocket);
UpdateConnectedUserList();
}
}
catch (Exception ex)
{
Log.E("Connection listener ran into an exception", ex);
}
}
As you can see I have created two TCP sockets to liesten on different ports. dataSocket is for normal messages and messageSocket is for special messages (sorry for confusing names, I have to refractor code).
On client side it works the same way: there are two different socket to communicate with and through the server.
I wanted to avoid managing two sockets rather then one. But the only way I can imagine is that on every received message server would have to check if it's special (and handle it in special way) or just send to client.
The question: Is there a better way to manage these special messages?
Thanks to all in advance!
P.S.
Sorry for my poor english, it's not my native language

Start listening again with Socket after a disconnect

I'm writing a small C# Sockets application. Actually I have two, a server and a client.
The user runs the client, enters the IP and port for the server, presses 'connect', and then once connected they can enter text into a textbox and send it to the server.
The server simply displays either "No connection" or "Connection from [ip]:[port]", and the most recent received message underneath.
The server successfully receives messages, and even handles the client disconnect fine.
Now I'm trying to make it listen again after the client has disconnected but for some reason nothing I try will allow it to start listening again.
Here is part of my code:
Socket socket;
private void listen()
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, 12345));
socket.Listen(10);
socket.BeginAccept(new AsyncCallback(acceptAsync), socket);
}
and
private void receiveAsync(IAsyncResult res)
{
Socket socket = (Socket)res.AsyncState;
try
{
int nBytes = socket.EndReceive(res);
if (nBytes > 0)
{
Invoke(new MethodInvoker(delegate()
{
lMessage.Text = encoder.GetString(buffer);
}));
setupReceiveAsync(socket);
}
else
{
Invoke(new MethodInvoker(delegate()
{
lConnections.Text = "No Connections.";
lMessage.Text = "No Messages.";
socket.Shutdown(SocketShutdown.Both);
socket.Close();
listen();
}));
}
}
catch { }
}
The last line: listen(); is what throws the error.
I have tried simply calling socket.BeginAccept() again, but that also throws an exception.
The message I'm getting is:
Only one usage of each socket address (protocol/network address/port) is normally permitted
If I don't call my listen() function and instead just call socket.BeginAccept(), then I get "You must first call socket.listen()"
If I call the socket.listen() function, then it tells me it's already connected and cart start listening.
Once I have made an asynchronous connection, and received several asynchronous messages, how then do I begin receiving again?
Your socket variable already has an listening socket assigned to it the second time you call listen(), which is why it tells you only one usage is permitted. All you need to repeat is the socket.BeginAccept(new AsyncCallback(acceptAsync), socket) call. So try replacing the call to listen() inside your receiveAsync(...) method with socket.BeginAccept(new AsyncCallback(acceptAsync), socket).
In async Begin* is always followed by End*. See Using an Asynchronous Server Socket. Your accept method should be something like:
try {
listener.Bind(localEP);
listener.Listen(10);
while (true) {
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(SocketListener.acceptCallback),
listener );
allDone.WaitOne();
}
} catch (Exception e) {
Server, means that an app that listens on specified port/ip. Is usually, always in a listening mode - that's why it is called a server. It can connect and disconnect a client, but is always in listening mode.
This means, when a server disconnects a client - even then - it is in listening mode; meaning it can accept the incoming connections as well.
Though, disconnection request can come from client or can be forcefully applied by server.
The process for a server is:
Bind to socket
Listen
Accept connections
The process for client is:
Connect to the server
Send/receive messages
There are several ways for server to handle the incoming clients, couple, as follows:
Incoming connections are maintained in a list, for instance within a List<TcpClient>.
One way of handling the incoming clients is through threads. For instance, for each incoming client, spawn a thread that would handle the communication between server and client. For instance, checkout this example.
_
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
Use single thread and use context switching to manage client communications (TX/RX).

TCPIP server single connection

i am using c# sockets Asynchronous mode.
i need to serve only one connection in my application from a server point of view. once one is connected then i would like to refuse any more connection requests.
also the server only serves to connect to a single client. when the communication is done the server has to be restarted.
but from what i have read on the topic, it is not possible to close beginaccept.
i would like some ideas regarding how get around this situation.
Normally, in the BeginAccept async callback you would call BeginAccept again so that another connection can be accepted. However, you can omit this step if you do not want to allow another connection. So that the connection is refused in a timely manner, consider also closing the listening socket in the callback. The accepted Socket will remain open in this case for you to use even though the listening socket is closed.
class SocketTest
{
private Socket m_Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Test()
{
m_Listener.Bind(new IPEndPoint(IPAddress.Loopback, 8888));
m_Listener.Listen(16);
m_Listener.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
Socket s = m_Listener.EndAccept(ar);
m_Listener.Close();
/* Use s here. */
}
}

Categories

Resources