Spring Integration TCP. Get connection ID of the connected clients - tcp

I have a problem here with the dynamic TCP connection approach (Spring-IP Dynamic FTP Sample). When a message is received, I want to get the TCP connection details for the received message. this way I can keep track in my application of the sender sending that message. But in Service activator I am not able to get this detail.
Also need the connection details when my TCP client is connected to the server. This way if the server wants to initiate the communication, it will have the connection details.
For info my application has more than one TCP clients and servers.

Got an answer reply in another post from Mr. Gary Russell.
Answer
For normal request/reply processing, using an inbound gateway, the framework will take care of routing the service activator reply to the correct socket. It does this by using the connection id header.
If you need to provide arbitrary replies (e.g. more than one reply for a message, you have to use inbound and outbound channel adapters and your application is responsible for setting up the connection id header.
There are two ways to access the required header in a POJO invoked by a service activator:
public void foo(byte[] payload, #Header(IpHeaders.CONNECTION_ID) String connectionId) {
...
}
public void foo(Message<byte[]> message) {
String connectionId = message.getHeaders().get(...);
}
Then, when you send your replies, you need to set that header somehow.
EDIT
Below Is My Implementation
To get all the connected clients simply get the ServerConnectionFactory from the context and access the method .getConnectedClients(). It returns the list connectionIds for each connected client.
AbstractServerConnectionFactory connFactory = (AbstractServerConnectionFactory) appContext.getBean("server");
List<String> openConns = connFactory.getOpenConnectionIds();
As mentioned above in Gary's response, use this connectionId and set it in conneciton header while sending the message to a client. Sample code as follows.
MessageChannel serverOutAdapter = null;
try{
serverOutAdapter = (MessageChannel) appContext.getBean("toObAdapter");
}catch(Exception ex){
LOGGER.error(ex.getMessage());
throw ex;
}
if(null == serverOutAdapter){
throw new Exception("output channel not available");
}
AbstractServerConnectionFactory connFactory = (AbstractServerConnectionFactory) appContext.getBean("serverConnFactoryBeanId");
List<String> openConns = connFactory.getOpenConnectionIds();
if(null == openConns || openConns.size() == 0){
throw new Exception("No Client connection registered");
}
for (String connId: openConns) {
MessageBuilder<String> mb = MessageBuilder.withPayload(message).setHeader(IpHeaders.CONNECTION_ID, connId);
serverOutAdapter.send(mb.build());
}
Note 1: If u want to send messages from the server then be cautious to configure the server and client connection factories in a way that they do not time-out. i.e put so-keep-alive = true in client connection factory.
Note 2: If the server has to communicate with the client then make sure that the client connects to the server as soon as the context is loaded. Because Spring-IP client connection factory connects only when the first message is sent out. In order to connect client after context load, put client-mode="true" in tcp client context for the "tcp-outbound-channel-adapter".

Related

akka io tcp server

I am using the new Akka IO and followed this tutorial(which is a simple server-client application). My server actor system code looks like this:
// create the sever system
ActorSystem tcpServerSystem = ActorSystem.create("tcp-server-system");
// create the tcp actor
final ActorRef tcpServer = Tcp.get(tcpServerSystem).manager();
// create the server actor;
ActorRef serverActor = tcpServerSystem.actorOf(new Props(ServerActor.class).withRouter(new RoundRobinRouter(5)), "server");
// tell the tcp server to use an actor for listen connection on;
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
options.add(TcpSO.reuseAddress(true));
tcpServer.tell(TcpMessage.bind(serverActor, new InetSocketAddress("127.0.0.1", 12345), 10, options),
serverActor);
The ServerActor class it's just a plain actor that on it's onReceive does the followings:
logger.info("Received: " + o);
if (o instanceof Tcp.Connected){
connectionActor = getSender();
connectionActor.tell(TcpMessage.register(getSelf()), getSelf());
ByteStringBuilder byteStringBuilder = new ByteStringBuilder();
byteStringBuilder.putBytes("Hello Worlds".getBytes());
connectionActor.tell(TcpMessage.write(byteStringBuilder.result()), getSelf());
}
I am trying to test the server actor using netcat and have this "strange" behaviour: only the first client that connect tot the server is receiving the message send from the server. The nexts clients could connect to the server but does not receive the message. Also in debug mode the server actor doesn't get the Tcp.Connected message(except for the first connected client), so a registration message could not be sent to the client, althought the next clients could connect.
this is a known issue in the 2.2-M1 milestone, where the problem was that the TcpListener didn't register AcceptInterest on the selector unless it reached the configured BatchAcceptLimit, leading to it not being notified of new accepts if there where only a few connections pending.
It has been fixed and will be part of the next milestone release.

How SignalR works internally: client side

I'm writing my own SignalR Client on Java and I'm facing some troubles.
At first I want to implement PersistentConnection logic. My server code is taken from example:
public class Battle : PersistentConnection
{
protected override Task OnConnectedAsync(IRequest request, string connectionId)
{
return Connection.Broadcast("Connection " + connectionId + " connected");
}
protected override Task OnReconnectedAsync(IRequest request, IEnumerable<string> groups, string clientId)
{
return Connection.Broadcast("Client " + clientId + " re-connected");
}
protected override Task OnReceivedAsync(IRequest request, string connectionId, string data)
{
// return Connection.Broadcast("Connection " + connectionId + " sent ");
return Connection.Send(connectionId, "Connection " + connectionId + " sent ");
}
protected override Task OnDisconnectAsync(string connectionId)
{
return Connection.Broadcast("Connection " + connectionId + " disconncted");
}
protected override Task OnErrorAsync(Exception error)
{
return Connection.Broadcast("Error occured " + error);
}
}
Judging by .NET client code, I understood that in order to connect to server client should:
1) Send request to http://myserver/battle/negotiate and get ConnectionId from response
2) Send request to http://myserver/battle/connect?transport=longPolling&connectionId=<received_connection_id>
My question is waht should client do to maintain connection? How should it listen to server broadcasting messages?
Another issue is that I receive no response when I'm trying to send message from client to server after connection has been established. I send request to http://myserver/battle/send?transport=longPolling&connectionId=<received_connection_id>. Method OnReceivedAsync is always called, but I get no response (independently of data sent).
I'd be grateful for any explanations on my questions and on internal principles of SignalR work.
Thanks in advance.
I've tried to do the same thing that you are doing! I've implemented a SignalR-client for Android and I called it SignalA. :) Have a look at it on github.
There are several methods of communication used in SignalR. My understanding is that SignalR will use the best one it determines will work with the given connection.
The general idea behind long polling is this: The client sends a request to the server with a long timeout period. Say 2 minutes or 5 minutes. If the server has a message to send to the client, it then responds to the client request with the message. Otherwise the request will eventually timeout, at which point the client initiates a new request. So, basically, the client is nearly always in a call to the server. The server only ever answers when it has a message for the client. So the client could send the request to the server and say, 90 seconds later, the server gets a message for the client.
For more information, read the Long Polling section of this Wikipedia article: http://en.wikipedia.org/wiki/Push_technology
But for the specifics, you really need to examine the .NET code closely. Hopefully this overview will give you enough to understand what's going on there, though.

Communicating a GPS/GPRS/GSM tracker with the server

I am developing a vehicle tracking system which uses GPS/GPRS/GSM. The tracking device I am currently using is GV100, a GPS/GPRS/GSM tracker from Quectel ([www.quectel.com][1].)
I am not able to establish connection between the device and the backend server. My question particularly is:
How do I send commands (AT Commands) to the device from the server?
How do I accept the response (reports and acknowledgement messages) from the device to save it in the database?
I sent command to the device with the MGV100 Manage Tool (Software provided by Quectel) via serial port. And I got acknowledgement SMS message on GSM enabled mobile telephone. Now, I want to send message from the server and accept reply on the server (not by SMS). I don’t know how to send command and receive the reply. I have no previous experience in developing such systems.
It would be great if I can get a sample code and setup procedures if it requires.
Where can I get a relevant tutorial for the case I mentioned?
Thanks jhonkola
To understand how server receives and send data to the device, I decided to first implement the communication between the client (currently my PC) and server. Though my ultimate goal is communicating with the device, currently I am trying to establish connection from my PC to the server. If I succeed in this, I will strive to communicate to server from the device which needs IP address and port number of server to send and receive data.
This is my assumption how to do it:
I can open a port on the server from .cs code so as to communicate
using TCP/UDP.
Client then can send and receive data via this
port.
I can save the data sent from the client on server's file
system and review it any time. (Am not storing the data in relational database because I don't want to bother about database issues now.)
This is how I tried to implement:
Server a C# Web Application:
When a button is clicked it opens a port and listens to client
protected void btnConnect_Click(object sender, EventArgs e)
{
try
{
continueListening = true;
while (continueListening)
{
int port=Int32.Parse(txtPort.Text);
lblOutput.Text = "Port is now " + port +". Waiting for connection";
TcpListener myList = new TcpListener(IPAddress.Parse(txtIpAddress.Text), port);
myList.Start();
Socket s = myList.AcceptSocket();
lblOutput.Text="Connection accepted from " + s.RemoteEndPoint;
byte[] b = new byte[100];
int k = s.Receive(b);
lblOutput.Text = ("Recieved...");
String obtainedText = "";
for (int i = 0; i < k; i++)
{
obtainedText = obtainedText + " " + (Convert.ToChar(b[i]));
}
writeToTextFile("C:/Users/MekAtIbex/Desktop/TESTED/RECIEVED.txt", obtainedText);
lblOutput.Text = obtainedText;
ASCIIEncoding asen = new ASCIIEncoding();
lblOutput.Text = lblOutput.Text +" "+ ("The string was recieved by the server.");
lblOutput.Text = lblOutput.Text +" "+ ("\r\nSent Acknowledgement");
}
Client: C# Windows application
private void btnSend_Click(object sender, EventArgs e)
{
try
{
TcpClient tcpClient = new TcpClient();
int port=Int32.Parse(txtPort.Text.Trim());
tcpClient.Connect(txtIpAddress.Text, port);
lblStatus.Text = ("Connected");
Stream stm = tcpClient.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] bytesToSend = asen.GetBytes(txtData.Text);
lblStatus.Text = ("Transmitting.....");
stm.Write(bytesToSend, 0, bytesToSend.Length);
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
{
txtaResponse.Text = txtaResponse.Text + "\n" + "Res... " + new DateTime() + " " + Convert.ToChar(bb[i]);
Console.Write(Convert.ToChar(bb[i]));
}
tcpClient.Close();
}
catch (Exception ex)
{
lblStatus.Text = ("Connected");
txtaRequest.Text = txtaRequest.Text + "\n" + "Err... " + new DateTime() + " " + ex.StackTrace;
}
}
My current questions are:
Is my assumption correct? If not how should I do it?
I have tried to save it using the above code but I didn't got the file.
What is the advantage and disadvantage of using UDP in comparison TCP for tracking applications?
I have browsed well, but I couldn't find a place for a good start. And, as I have no experience in such applications, I couldn't debug my application.
My current questions are:
Is my assumption correct? If not how should I do it?
Yes, your basic assumptions are correct. The server would open a listening port and then the client could connect to this port and drop off data as needed. You can have the server log this to a file for later review too.
I have tried to save it using the above code but I didn't got the
file.
Is the file already created? The method you have will fail if the file is not existent on the system.
What is the advantage and disadvantage of using UDP in comparison TCP
for tracking applications?
UPD is less expensive in terms of network setup. It is the "fast and dirty" method of communication. The downside is that you may not get every message properly delivered. In some applications, this just doesn't matter and the benefits are worth this cost.
Now a few things I'd change:
Change IPAddress.Parse(txtIpAddress.Text) to IPAddress.Any
This will allow your listener the broadest ability to catch incoming messages and will most likely not effect other systems (since this is essentially your first networking program).
You'll also want to make your listener spawn a thread to handle the file writing and then go back to listening. This is a very standard practice and allows for servers to handle multiple connections.
It is difficult to comprehensively answer this, as a good answer would require detailed knowledge about the product. I suggest that you contact the manufacturer / reseller for support.
A few general points:
Sending commands over network to the device requires that you are able to connect to the device from internet. This is not always easy over GSM network, as the operators may block all incoming traffic. The manufacturer may have provided solutions for this.
If you can connect to the device, the protocol that is used to give commands (assuming that such protocol is built-in) will also contain a mechanism to receive any responses.

Policy File Check closes socket

I have created a flex app that uses sockets. I published the flex app in a web application that runs on glassfish server.
Now from that flex app i create a socket connection to a C# server and start sending/receiving data.
The problem is that after i create the socket connection to C# server the flex app first checks the policy file, and after it get's it, it closes the socket, without keep the connection alive.
This is my C# server:
TcpListener tcpListener = new TcpListener(IPAddress.Parse("172.17.41.211"), 12345);
TcpClient tcpclient = tcpListener.AcceptTcpClient();
Socket client = tcpclient.Client;
while (client.Available > 0)
{
int bytes = 0;
byte[] m_aBuffer = new byte[1024];
bytes = client.Receive(m_aBuffer, m_aBuffer.Length, SocketFlags.None);
String str = Encoding.ASCII.GetString(m_aBuffer, 0, bytes);
if (str.StartsWith("<policy-file-request/>"))
{
sendBytes = Encoding.ASCII.GetBytes("<cross-domain-policy><allow-access-from domain=\"172.17.41.211\" to-ports=\"12345\"/></cross-domain-policy>\0");
client.Send(sendBytes);
}
}
while (client.Connected)
{
Thread.Sleep(200);
sendBytes = Encoding.ASCII.GetBytes("message to client");
client.Send(sendBytes, sendBytes.Length, SocketFlags.None);
}
Now the flex client looks like:
private var socket:Socket = new Socket();
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
socket.addEventListener(ErrorEvent.ERROR, errorHandler);
socket.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
...
socket.connect("172.17.41.211", 12345);
...
Now after i create the connection and it gets the policy from server it closes this socket, so to be able to use this connection i have to call again
socket.connect("172.17.41.211", 12345));
After i do this, i can use normally the connection.
Can someone suggest why this happens and maybe is possible to not have closed the connection ?
You don't send the policy file through the socket itself. It needs to be on a different channel. For instance, if you connect to some ip/port, by default flash will try to connect to the same ip but on port 843 and look for the master policy file.
You can also set it manually using Security.loadPolicyFile(someURL). More information can be found here.

HTTP Connection Parameters

I am using the HTTP Connection in the following way:
HttpConnection _httpConnection = null;
try {
_httpConnection = (HttpConnection)Connector.open(_url);
} catch(Exception e) { }
byte [] postDataBytes = _postData.getBytes();
_httpConnection.setRequestMethod(HttpConnection.POST);
_httpConnection.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
_httpConnection.setRequestProperty("Content-Language", "en-US");
_httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
_httpConnection.setRequestProperty("Connection", "close");
_httpConnection.setRequestProperty("Content-Length", Integer.toString(_postData.getBytes().length));
os = _httpConnection.openOutputStream();
os.write(postDataBytes);
os.flush();
This HTTP Connection requires parameters to successfully open. For example on a WIFI network, it requires the ";deviceside=true;interface=wifi" to be added to the URL.
The problem is for the EDGE connection. Each country requires different parameters to be added. For example in lebanon it requires ";deviceside=false" but in KSA if i add this parameter the connection will not open. In USA it needs different types of parametes. The question is how to establish an HTTP connection for all the countries with the same parameters. So that the application will successfully have an internet connection no matter where it is downloaded.
Welcome to the confusing world of network transports on BlackBerry! You will want to start with the article Connecting your BlackBerry - http and socket connections to the world.
Here is a simple example for "just give me a connection" (note, you will need to add appropriate error handling; also, myURL in the code below should have no connection descriptor info appended to it):
ConnectionFactory factory = new ConnectionFactory();
ConnectionDescriptor descriptor = factory.getConnection(myURL);
if (descriptor != null) {
_httpConnection = (HttpConnection) descriptor.getConnection();
...
}
Try using to use the method reffered in this link melick-rajee.blogspot.com and use it like
_url = "http://www.example.com";
_httpConnection = (HttpConnection)Connector.open(_url + getConnectionString());
You will have to sign the application to use this else the application will show exception.
To sign your application just go here Code Signing Keys
To use the connectionFactory, seems you need to set BisBOptions.
Try this:
connFact = new ConnectionFactory();
connFact.setTransportTypeOptions(TransportInfo.TRANSPORT_BIS_B,
new BisBOptions("mds-public"));

Resources