reading messages from Device over gprs - c#

i have a GPS device that will be installed in many trucks.
i can configure the device to send data statement "gps data, device id" over gprs to IP and Port.
i'm using TcpListener class to read the data on the server side.
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.Write("Connected!");
data = null; int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
}
}
that method is listening to what is coming on server ip and port.
i want to know if i configured the devices to send to the server on the same port.am i able to listen to all the devices or the first device to connect will be the only one ?
is this method the the best way to read the coming data from the devices?
do i need to configure a different port for each device and create a new listen thread for each device port?
sometimes i'm facing exceptions "the request channel timed out while waiting for a reply"
many thanks in advance for your help.

In your code you are listening to the all devices but only after finish read all data from the first device so you are receiving "the request channel timed out while waiting for a reply".You should have a different threads each one handle a tcpClient.
so the code should be something like:
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("new client connected");
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleClient), client);//or use Task if 4.0 or new Thread...
}
}
private void HandleClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
Byte[] bytes = new Byte[256];
String data = null;
int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
Console.WriteLine(data);
}

1) Both. You should be able to listen for all devices, but you often cannot with your code because the listener thread is tied up waiting for the stream from a device that connected earlier.
2) Probably not. IIRC, NetworkStream.Read returns 0 when the connection is closed by the peer device. Is this your protocol - ie. the device connects, sends some data and disconnects? If so that will work, though slowly. Anyway, there is another problem. You should be concatenating the bytes received on your stream to data, not just replacing them - Read() my return multiple times for one communication, perhaps even with a single byte each time, (unlikely, but permitted with TCP streams). You could keep a count of bytes rx. so far and use the 'offset' parameter to do this.
3) You only need one listening thread, ie. the one that calls AcceptTcpClient(). This thread should not be making blocking calls to receive data from the socket returned by AcceptTcpClient(). Either create/allocate/depool/whatever a new client-server thread to run your Read() loop for each 'client' socket returned by AcceptTcpClient() or use asynchronous IO.
4) Your single listener/read thread will be non-responsive for new connections while it is waiting on the NetworkStream - other devices will be unable to connect. The listener should get back to AcceptTcpClient() quickly and not wait for slow networks/devices to send data.
Rgds,
Martin

Related

Why isn't TcpListener listening?

We have a C++ v100 application that is processing every event in our system, listening on port 1705, running off the Hostname. (it works perfectly for the C++ app, and we don't want to change anything in the c++ code) We are trying to intercept some of those events into a C# 4.5.2 solution, simply to display specific events in our new web system.
I have coded the following, in an attempt to listen to port 1705 traffic... but I never receive any data. (I can create events that get sent to 1705)
The following code runs, and it makes it to 'Waiting for a connection', but never makes it to 'Connected!'. If you see any reason in the following code as to why I wouldn't be receiving data, please let me know:
private void PortListener()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
var port = 1705;
var localAddr = IPAddress.Parse(Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
var bytes = new byte[256];
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
var data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
//TODO: Process the data
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server?.Stop();
}
}
Make sure that you are binding/listening to the right ip-address. If you bind/listen on localhost (127.0.0.1) you can only connect from the same host.
Check what
Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
really produces.
I'm doing this all wrong. In order to listen to an already opened Port, I need to use a TcpClient to connect and listen. Only a single TcpListener is allowed per port. Several TcpClients can connect at once. Sigh.

C# - Is it possible to send TCP IP Packet to my own external IP for server testing?

)
I am making a simple server application to send messages to all clients that connected at a certain time. Basically, I start a server, which grabs its internal IP and port and listens. Then on clients, they connect to my routers external IP and port, and send a tcp packet. The problem is this, my client application is never able to successfully send a packet out. It times out.
Here is the code for the server:
...
try
{
server_listener = new TcpListener(IPAddress.Parse(192.168.0.xxx), 5000);
server_listener.Start();
isRunning = true;
Console.WriteLine("[{0}] The server is now listening for all clients!", DateTime.Now);
Listen();
}
...
void Listen() // Listen to incoming connections.
{
while (isRunning)
{
TcpClient tcpClient = server_listener.AcceptTcpClient(); // Accept incoming connection.
(new Thread(() => SetupAndListen(tcpClient))).Start(); //handle in a new thread
}
}
And Client:
//attempt to connect once...
string textToSend = "CA";
try
{
//---create a TCPClient object at the IP and port no.---
TcpClient client = new TcpClient(EXTERNAL_SERVER_IP, 5000);
NetworkStream nwStream = client.GetStream();
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(textToSend);
//---and see if connected---
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
Debug.Log("Received : " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
client.Close();
}
catch { }
The server runs fine, no errors, and appears to be listening properly from what I see in the debugger, but none of my clients work. Moreover, if EXTERNAL_SERVER_IP is changed to localhost, or 192.168.0.xxx it does infact work. Any thoughts as to what is going on?
Just to note, the port 5000 has indeed been forwarded.
Are you trying to send a packet to your server from inside your network, by using your external IP? This will not work with many SoHo routers. The router feature you are asking for is called NAT Loopback.

Open two tcp connection using TcpListener class on both side

I want to open tcp connection between two machine.
I want to use the class TcpListener on the client side and on the server side and by this to have the option to make the two side 'talk' with the other by sending and receiving byte[].
That mean that each side is a server and a client.
I using the code from msdn to do it.
But on this code the server start and wait till the client will connect to him.
If i doing so on the both sides i will fail.
Is there any other way ?
The code:
public static void Main()
{
TcpListener server=null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch(SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
I assume there is some missunderstanding...
The TcpListener class is used to open a listener. This represents an endpoint to whom a client can connect (like e.g. a WebServer). To actually connect to such an endpoint you need to use an instance of the TcpClient class.
Following a simple example (written out of my head and NOT TESTED!), also be advised that there is no error handling included and this should just give you a hint where and how to start.
Serverside
// Create a local endpoint (all network interfaces at port 80)
// and create a listener that uses that endpoint.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 80);
TcpListener listener = new TcpListener(localEndPoint);
// Start the listener.
listener.Start();
// Wait (blocking) until a client connects.
TcpClient client = listener.AcceptTcpClient();
// Stop the listener (so no one else can connect).
listener.Stop();
// Fetch the underlying network stream which
// allows reading and writing data between us and
// the connected client.
NetworkStream ns = client.GetStream();
// Read data from the stream.
byte[] dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
// Write an answert to the client.
dataBuffer = Encoding.UTF8.GetBytes("Thank you for your message!");
ns.Write(dataBuffer, 0, dataBuffer.Length);
// Close everything.
ns.Flush();
ns.Close();
client.Close();
Clientside
// Create a remote endpoint (the ip you want to connect to at port 80)
// and create a client that uses that endpoint.
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse("the ip you want to connect to"), 80);
TcpClient client = new TcpClient();
// Try to connect to that endpoint.
client.Connect(remoteEndPoint);
// Fetch the underlying network stream which
// allows reading and writing data between us and
// the connected client.
NetworkStream ns = client.GetStream();
// Write something to the server.
byte[] dataBuffer = Encoding.UTF8.GetBytes("Hello, I am here.");
ns.Write(dataBuffer, 0, dataBuffer.Length);
// Read an answer back from the server.
dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received an answer with {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
// Close everything.
ns.Flush();
ns.Close();
client.Close();
The example above obviously does just send one message and closes the application afterwards. If you need to wait until data has arrived, you can use the DataAvailable property of the NetworkStream which indicates whether data is available or not. If not, just sleep and try again later.
Example
bool iWantToReceiveData = true;
while (iWantToReceiveData)
{
// If no data is available...
if (!ns.DataAvailable)
{
// ...wait some time and try again later.
Thread.Sleep(100);
continue;
}
// Read an answer back from the server.
dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received an answer with {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
}
Of course this is some kind of blocking beaviour so you will have to handle that in a separate thread.
I would suggest building an EnhancedNetworkStream class which has a thread running in the background that does the cyclic checking for new data and fires an event once new data has arrived.

socket time out in socket programming

i have a hardware than joins to a laptop(server) in ad hoc Network.
when server sends data alone, it works correctly. and client sends data alone , works correctly too.
but when server and client send data together , after a period of time , time out will occur.
after 35 and sometimes 33 packet time out will occur.
i changed transfer rate of hardware but it disconnects too.
although hard ware supports full duplex.
after time out , i ping hard ware and it is not on port.
and check port on server , and it is open.
how can i do?
byte[] bytes = new byte[512];
//try
//{
IPHostEntry ipHost = Dns.GetHostEntry("");
// Gets first IP address associated with a localhost
IPAddress add = ipHost.AddressList[3];
TcpListener tcpListener = new TcpListener(add, 6000);
tcpListener.Start();
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream stream = tcpClient.GetStream();
String data = null;
while (true)
{
int j = 0;
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
j = j + 1;
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
AddItem("j="+j+" Received:"+ data);
// Process the data sent by the client.
//data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes("thanks");
// Send back a response.
stream.Write(msg, 0, msg.Length);
AddItem("Sent:"+"thanks");
}
// Shutdown and end connection
tcpClient.Close();
The standard socket calls are all blocking, so if both participants are sending to each other, they each wait for their opposite to receive the message they send, causing a deadlock.
In .NET, there are three typical solutions:
Microsoft has a parallel API for asynchronous socket activity. It requires more overhead code than your example, but handles just about everything in a Windows-like manner.
You can handle the asynchronous activity yourself by testing for readable data before you write with Socket.Select(). This is a typical polling approach, but you're doing everything yourself and need to make sure there's no starvation or other bias.
Put your Read and Write code in different threads, so that blocking one doesn't block the entire program.

Check if TcpListener has any connected clients

I am currently working on a c# program where I am opening a connection on a socket and listening for clients.
How can I check if the TcpListener has any clients currently connected. I want to do this so when someone closes the console application instead of it just terminating anything that is connect it will instead wait for all connected clients to finish before exiting the console app.
Below is the code:
TcpClient client = listener.AcceptTcpClient();
if (client.Connected)
{
library.logging(classDetails + MethodInfo.GetCurrentMethod().Name,
string.Format("Client Connected: {0}",((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString()));
NetworkStream stream = client.GetStream();
byte[] data = new byte[client.ReceiveBufferSize];
int bytesRead = stream.Read(data, 0, Convert.ToInt32(client.ReceiveBufferSize));
string request = Encoding.ASCII.GetString(data, 0, bytesRead);
byte[] msg = System.Text.Encoding.ASCII.GetBytes("200 OK");
ProcessXML process = new ProcessXML(library, appSettings);
// Send back a response.
stream.Write(msg, 0, msg.Length);
process.processXML(request, ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
client.Close();
Is there a method within the TcpListener to get a count of connected clients or has this got to be managed by myself by adding the client to something like a list array and then remove it when the client closes.
To the best of my knowledge, TcpListener does not internally keep track of accepted connections - that must be done explicitly by the application as needed.

Categories