I've done some searching and it doesn't seem like there is much in the way of success in establishing a tcp/ip socket connection successfully via Coldfusion. I'm trying to act as a simple client and send a string over and get a response. Adobe's EventGateway requires server-side setup, which I can't touch, but also appears to be a listener only (according to Adobe's doc, "It can send outgoing messages to existing clients, but cannot establish a link itself.").
There is another example on SO/cflib.org that is the prevailing post over the web invoking Java objects, but I'm not succeeding with it and it seems pretty much everyone else has some degree of trouble with it. In my attempts, I can get it to init/connect a socket, but nothing else. If I try to send a string, the CF page loads fine but the server side seemingly never sees anything (but will log or note a connection/disconnection). If I try to read a response, the page will never load. If I close the server while it's trying, it will show a connection reset while trying readLine(). I have tried this with an in-house app as well as a simple Java socket listener that will send a message on connect and should echo anything sent.
Is this just not a job for CF? If not, any other simple suggestions/examples from the jQuery/Ajax realm?
Java listener app:
package blah;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
class SocketServer extends JFrame
implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton button;
JLabel label = new JLabel("Text received over socket:");
JPanel panel;
JTextArea textArea = new JTextArea();
ServerSocket server = null;
Socket client = null;
BufferedReader in = null;
PrintWriter out = null;
String line;
SocketServer(){ //Begin Constructor
button = new JButton("Click Me");
button.addActionListener(this);
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(Color.white);
getContentPane().add(panel);
panel.add("North", label);
panel.add("Center", textArea);
panel.add("South", button);
} //End Constructor
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if(source == button){
textArea.setText(line);
}
}
public void listenSocket(){
try{
server = new ServerSocket(4444);
} catch (IOException e) {
System.out.println("Could not listen on port 4444");
System.exit(-1);
}
try{
client = server.accept();
//Show connection status in text box, and send back to client
line = " Connected ";
out.println(line);
textArea.setText(line);
} catch (IOException e) {
System.out.println("Accept failed: 4444");
System.exit(-1);
}
try{
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.out.println("Accept failed: 4444");
System.exit(-1);
}
while(true){
try{
//Try to concatenate to see if line is being changed and we're just not seeing it, show in textbox
line = line + " " + in.readLine();
textArea.setText(line);
//Send data back to client
out.println(line);
} catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
protected void finalize(){
//Clean up
try{
in.close();
out.close();
server.close();
} catch (IOException e) {
System.out.println("Could not close.");
System.exit(-1);
}
}
public static void main(String[] args){
SocketServer frame = new SocketServer();
frame.setTitle("Server Program");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
frame.addWindowListener(l);
frame.pack();
frame.setVisible(true);
frame.listenSocket();
}
}
CF Simple Send (minus HTML header/footer, IP to be hard-coded, port on simple listener = 4444):
<cfset sock = createObject( "java", "java.net.Socket" )>
<cfset sock.init( "ip.ip.ip.ip", 4444)>
<cfset streamOut = sock.getOutputStream()>
<cfset output = createObject("java", "java.io.PrintWriter").init(streamOut)>
<cfset streamOut.flush()>
<cfset output.println("Test Me")>
<cfset output.println()>
<cfset streamOut.flush()>
<cfset sock.shutdownOutput()>
<cfset sock.close()>
Simple CF Read (again, minus header/footer template, IP of server to be hard-coded, port 4444)
<cfset sock = createObject( "java", "java.net.Socket" )>
<cfset sock.init( "ip.ip.ip.ip", 4444)>
<cfset streamInput = sock.getInputStream()>
<cfset inputStreamReader= createObject( "java", "java.io.InputStreamReader").init(streamInput)>
<cfset input = createObject( "java", "java.io.BufferedReader").init(InputStreamReader)>
<cfset result = input.readLine()>
<cfset sock.shutdownInput()>
<cfset sock.close()>
I've tried adding some sleeps here and there and also have tried a send not using PrintWriter/using just ObjectOutputStream and writeObject() , but same behavior. Any help would be greatly appreciated. Thanks!
This is going to be a very challenging process to implement in ColdFusion, even when taking advantage of Java, for the simple reason of:
Socket communication is real-time, while web requests have finite starting and stopping points.
For example, when you make a ColdFusion template request, everything (variables, shared memory, object instantiation, etc.) lives within the context of the page request--and (barring a few caveats) dies when the page request ends. So, let's assume for the moment that you had a CFML template that performed the following tasks when requested:
Opened a socket.
Established a connection to a remote ip:port.
Listened for a response.
Printed that response to the browser.
Let's assume further that your code is up-and-running, tested, and working. You are able to open the socket, connect to a remote ip and port (you actually see the incoming request on the remote server, and can confirm this) and for all intents and purposes...your connection is good.
Then, 10 minutes after you executed your CFML page, the remote server sent a string of text over the connection...
...there is nothing on your CFML end that is alive and awaiting that response, ready to print it to the browser. The objects that you instantiated, used to open a socket, and connect...have all gone away, when the CFML template request ended.
This is why (as stated above) when you tried to "read a response", you observed that the page never loaded. What's happening is that ColdFusion is being told "stand by please, we could actually maybe possibly get some data over this socket"...so it blocks the web request from ending and waits...which manifests to the user as what appears to be a "hung" web page.
The nature of real-time socket communication is that it is connected and listening, waiting for a response...and unfortunately, a running web-page cannot run (and 'wait') forever, it will eventually timeout.
The bottom line is that while Java will allow you to open / connect / send / receive / close raw sockets, doing so from within the context of a CFML page may not be the approach you are ultimately looking for.
Related
I am trying to get my server made on vb.net to send messages to my client made on android. I have a client and server made on vb.net, I can send and receive messages (text) between them without problem. But when I try to make the client work the same on Android, I can not receive messages to the client (android), but if I could get it to send a message to the server (vb.net) .. They are stuck with this, and I do not understand how to continue
SERVER VB.NET
Imports System.Net.Sockets
Imports System.Text
Public Class Servidor
Dim Tcp As TcpListener
Dim th As New Threading.Thread(AddressOf Rutina)
Dim ejecuto = False
Private Sub Servidor_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CheckForIllegalCrossThreadCalls = False
End Sub
Dim tcpservercliente As New TcpClient
Public Function Rutina()
Try
Do
If ejecuto = True Then
Exit Do
End If
If Tcp.Pending = True Then
tcpservercliente.Client = Tcp.AcceptSocket
End If
If tcpservercliente.Available > 0 Then
Dim databytes(1000) As Byte
Dim decode As New ASCIIEncoding
tcpservercliente.Client.Receive(databytes)
txtRecibido.Text += vbCrLf & "Cliente Android: " & decode.GetString(databytes)
End If
Loop
Catch ex As System.InvalidOperationException
MsgBox("Error: " & ex.Message)
End Try
End Function
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
Try
Tcp = New TcpListener(System.Net.IPAddress.Parse("192.168.1.8"), 1371)
Tcp.Start()
th.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub Servidor_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
th.Abort("Rutina")
Application.Exit()
End Sub
Private Sub btnEnviar_Click(sender As Object, e As EventArgs) Handles btnEnviar.Click
Try
Dim decode As New ASCIIEncoding
tcpservercliente.Client.Send(decode.GetBytes(txtMensajeEnviar.Text))
Catch ex As System.Net.Sockets.SocketException
MsgBox(ex.Message)
End Try
End Sub
CLIENT ANDROID
//CLASS RM
public class RM extends AsyncTask<Void, Void, Void> {
Socket socket;
BufferedReader input;
#Override
protected Void doInBackground(Void... voids) {
try {
socket = new Socket("192.168.1.8",1371);
InputStreamReader streamReader = new InputStreamReader(socket.getInputStream());
input = new BufferedReader(streamReader);
if(input.ready()){
Log.i("AsyncTask", "Ready ");
}else{
Log.i("AsyncTask", "No Ready");
}
input.close();
socket.close();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
}
//VOID MAIN ACTIVITY
RM mr = new RM();
mr.execute();
The times I've tried to see that it returns, it's always empty. The message that is being sent from the server is not arriving
Sorry my bad english
==========================================
EDIT:
This is the class I use to send messages from the client (android) to the server (vb.net)
package com.example.app_test_client;
import android.os.AsyncTask;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class MessageSender extends AsyncTask<String, Void, Void> {
Socket socket;
PrintWriter pw;
#Override
protected Void doInBackground(String... voids) {
String mensaje_enviar = voids[0];
try {
socket = new Socket("192.168.1.8",1371);
pw = new PrintWriter(socket.getOutputStream());
pw.write(mensaje_enviar);
pw.flush();
pw.close();
socket.close();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
}
CODE MAIN ACTIVITY (CLIENT ANDROID)
package com.example.app_test_client;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
EditText mensaje_enviar;
TextView mensaje_recibido;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mensaje_enviar = (EditText)findViewById(R.id.txtTexto);
mensaje_recibido = (TextView)findViewById(R.id.lblMensaje);
}
public void enviar(View v){
MessageSender MensajeRemitente = new MessageSender();
MensajeRemitente.execute(mensaje_enviar.getText().toString());
}
}
The void "enviar" I have it in the "onClick" button. All this to send messages from the client (android) to the server (vb.net) works for me.
Based on this class "MessageSender", I made another equal to receive messages on the client (android) but it has not worked
If you are trying to receive the message in the Android device, then you are missing reading the message itself with String messageReceived = input.readLine();. Your code would look like this:
...
socket = new Socket("192.168.1.8",1371);
InputStreamReader streamReader = new InputStreamReader(socket.getInputStream());
input = new BufferedReader(streamReader);
String messageReceived = input.readLine();
...
You will have the message sent from the server in messageReceived.
EDIT
Without getting into much details, when you read the data sent from the server, you need to know when the data sent "ends", and the easiest way you have with your current implementation is to print a "line end" (a vbCrLf character in VB) when you send the message. Thus, in your Sub btnEnviar_Click you need to add a vbCrLf as follows:
tcpservercliente.Client.Send(decode.GetBytes(txtMensajeEnviar.Text & vbCrLf))
Additional notes
When data is being read from the server the socket needs to know when the data ends. There are several ways of achieving this, but the easiest way is in your case is to read "a line ending" with String messageReceived = br.readLine();. If the server doesn't send any "line end" (as in your current implementation), it will keep waiting for it and hence it appears that the programs hungs. That is what is happening in your case when you note that you cannot do anything else after reading the message - it is just waiting for something that will never come.
It is not necessary that you check input.ready() when reading from the server. This will only be true when the data has been completely sent from the server, and there is a great chance that the data is still being sent when it is invoked.
If you want to know better how TCP sockets works, this SO question has good examples that you can try.
Im working on building my own GUI program that talks to my pc from a tablet. I have the server side done in java but my problem is on the client side.
I want to send data out the PrintWriter to the server from a separate method.
I have accomplished sending in the code below (it sends 'a') but i cant figure out how to send it from a separate method. i believe its a basic java scope problem that im not understanding. i would really appreciate the help.
I have tried moving the variables into other scopes.
import java.io.*;
import java.net.*;
public class TestClient {
public static void main(String[] args) {
String hostName = "192.168.0.3";
int portNumber = 6666;
try ( //Connect to server on chosen port.
Socket connectedSocket = new Socket(hostName, portNumber);
//Create a printWriter so send data to server.
PrintWriter dataOut = new PrintWriter(connectedSocket.getOutputStream(), true);
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))
) {
//Send data to server.
dataOut.println("a");
}catch (UnknownHostException e) {
System.err.println("Don't know about host " + hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " +
hostName);
System.exit(1);
}
}
public static void sendToServer() {
//I want to control the print writer from this method.
//I have failed i all the ways i have tried.
}
}
You could move the Printer-Code (try try block) into the sendToServer-method and call it via
TestClient client = new TestClient();
client.sendToServer("this is a test");
Of course the sendToServer method needs to accept a parameter then. Even better would probably be to put the main method into a Starter class and decouple it from the Client-Class that you use for sending the data.
I have a local network consisting one server and multiple client devices. The devices are configured in such a way that they are permanently trying to connect to a server listening to a well defined port, say port number 4000 (so on the client side everything is already set).
This is stepwise how the system works:
- At startup, the server accepts all the client devices trying to connect(one client socket is created for each connection).
- The server creates a thread in which further communication with the client will later take place when necessary.
- The server saves the created thread into mongodb database with the associated sockets.
-This will be done for all the connected client devices
Later on, when there will be a command to be sent to a chosen client device (through a GUI),
-The server side should first connect to the database and retrieve the thread created for that particular client, with the associated client socket.
-Then the server should start the retrieved thread.
-And finally, in the started thread an input/output stream should be created in order to write the command to the client socket and read the answer (which will be further processed).
This is how I implemented the multithreaded server class :
import java.net.*;
import java.util.Arrays;
import java.util.Set;
import com.mongodb.*;
import java.io.*;
public class MultiThreadedServer {
public static void main(String[] args) throws IOException {
// variables's declaration
int portNumber = 4000;
boolean listening = true;
QuoteServerThread thr = null;
Socket clientSocket = null;
MongoClient mongoClient = null;
try {
//Creates a server socket listening on port 4000
ServerSocket serverSocket = new ServerSocket(portNumber);
//set the socket timeout
serverSocket.setSoTimeout(1000);
while (listening ) {
//Accepts a client
clientSocket = serverSocket.accept();
// Creates thread
thr = new ClientServerThread(clientSocket);
//Access the database and saves the thread
mongoClient = new MongoClient();
DB db = mongoClient.getDB( "testingDB" );
DBCollection collection = db.getCollection("testData");
//This is how I though of saving the thread in the DB. I don't know if its the proper way though
// I would also like ot save it with the associate client socket for later use
BasicDBObject doc = new BasicDBObject();
doc.put("threadID", thr.getId());
collection.insert(doc);
}
//Here I would like to access the database and and get the thread with the associated client socket and start the thread
// I don't know how to do it !!!!
} catch (IOException e) {
System.out.println(e);
}
mongoClient.close();
serverSocket.close();
}
This is the thread class :
import java.net.*;
import java.io.*;
public class ClientServerThread extends Thread {
private Socket socket = null;
public ClientServerThread(Socket socket) {
super("ClientServerThread");
this.socket = socket;
}
#Override
public void run() {
try{
// Get the client socket, create input and output streams and send command to the client device.
.........
.........
}catch(Exception e){
e.printStackTrace();
}
}
}
My problem is that I don't know :
-The proper way to save a created thread into mongodb database with the associated client socket.
-How to retrieve the threads from database .
I am really stuck here and I would appreciate if anyone could help me on this.
Thanks in advance !!
You can't save threads or sockets into a database.
Even in the best case you would only be saving some kind of a representation of them (thread name, socket address and port). You wouldn't be able to load them and have them be "live" again.
What can cause this to happen?
I moved my laptop to a friends house to work on this project. I opened the same port on his xfinity router, and changed all areas of my code to his IP. However it appears that the client is sending a message and the server has never getting past this part of code
System.out.println("running server!");
int nreq = 1;
try{
//SET ME PORT
ServerSocket sock = new ServerSocket(7332);
for(;;){
Socket newsock = sock.accept();
System.out.println("Creating thread...");
//Broken Old Login crap, needs reworked for map n stuff anyhow now
// Thread t = new ThreadHandler(newsock, nreq);
Thread t = new RequestInterpreter(newsock, nreq);
//t.run();
t.start();
nreq++;
}
}
catch(Exception e)
{
e.printStackTrace();
}
It never gets to print "Creating thread". I'm not sure where to begin with what could be going wrong here?
The only thing that has changed is the house, IP, router, and internet. Works everywhere else. What about those changing could block the client from sending a
Here is a test client I wrote also.
import java.io.DataInputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class testClientConnection {
public static void main(String[] args) {
System.out.println("Starting testConnection");
try{
Socket s = new Socket("xx.xx.xx.xxx", 7332);
DataInputStream fromServer = new DataInputStream(s.getInputStream());
PrintWriter toServer = new PrintWriter(s.getOutputStream(), true);
toServer.println("account name");
toServer.println("password");
toServer.println("Login");
System.out.println("Sent message...");
String response = fromServer.readLine().toString();
//Toast the result here? //testing
System.out.println("response: " + response);
if (response.equals("Login Success")) {
System.out.println("Login Success!!!");
}
}
catch(Exception e){ /
}
}
}
HUGE UPDATE!
Ok so my client was an android phone and I turned the wifi off, so it fell onto 4g-LTE. Then it worked. So... Something is blocking the client side code. What might that be?
The firewall on your friend's router is the usual suspect.
Second suspect is the firewall on the target machine.
Try disabling those.
The problem will be NAT on the router.
Servers don't work behind NAT devices unless you set up port-forwarding so that the router knows where to send an incoming request from outside.
I have been trying to get a simple networking test program to run with no results.
Server:
import java.io.*;
import java.net.*;
public class ServerTest {
public static void main(String[] args) {
final int PORT_NUMBER = 44827;
while(true) {
try {
//Listen on port
ServerSocket serverSock = new ServerSocket(PORT_NUMBER);
System.out.println("Listening...");
//Get connection
Socket clientSock = serverSock.accept();
System.out.println("Connected client");
//Get input
BufferedReader br = new BufferedReader(new InputStreamReader(clientSock.getInputStream()));
System.out.println(br.readLine());
br.close();
serverSock.close();
clientSock.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
Client:
import java.io.*;
import java.net.*;
public class ClientTest {
public static void main(String[] args) throws IOException {
final int PORT_NUMBER = 44827;
final String HOSTNAME = "xx.xx.xx.xx";
//Attempt to connect
try {
Socket sock = new Socket(HOSTNAME, PORT_NUMBER);
PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
//Output
out.println("Test");
out.flush();
out.close();
sock.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
The program works just fine when I use 127.0.0.1 or my internal IP for the hostname. But whenever I switch to my external IP address, it throws a java.net.ConnectException: Connection refused: connect error.
I purposely picked such an uncommon port to see if that was the problem, with no luck.
I can connect with no problems using telnet, but when I try to access the port with canyouseeme.org, it tells me the connection timed out.
I even tried to disable all firewalls and antivirus including the Windows default ones and the router firewall, with all ports forwarded and DMZ enabled, and it still says that the connection timed out. I use Comcast as my ISP, and I doubt that they block such a random port.
When I use a packet tracer, it shows TCP traffic with my computer sending SYN and receiving RST/ACK, so it looks like a standard blocked port, and no other suspicious packet traffic was going on.
I have no idea what is going on at this point; I have pretty much tried every trick I know. If anyone know why the port might be blocked, or at least some way to make the program work, it would be very helpful.
These problem comes under the following situations:
Client and Server, either or both of them are not in network.
Server is not running.
Server is running but not listening on port, client is trying to connect.
Firewall is not permitted for host-port combination.
Host Port combination is incorrect.
Incorrect protocol in Connecting String.
How to solve the problem:
First you ping destination server. If that is pinging properly,
then the client and server are both in network.
Try connected to server host and port using telnet. If you are
able to connect with it, then you're making some mistakes in the client code.
For what it's worth, your code works fine on my system.
I hate to say it, but it sounds like a firewall issue (which I know you've already triple-checked) or a Comcast issue, which is more possible than you might think. I'd test your ISP.
Likely the server socket is only being bound to the localhost address. You can bind it to a specific IP address using the 3-argument form of the constructor.
I assume you are using a Router to connect to Internet. You should do Port Forwarding to let public access your internal network. Have a look at How do you get Java sockets working with public IPs?
I have also written a blog post about Port forwarding, you might wanna have a look :) http://happycoders.wordpress.com/2010/10/03/how-to-setup-a-web-server-by-yourself/
But I still couldn't get this accessed over public IP, working on it now...
I had the same problem because sometimes the client started before server and, when he tried to set up the connection, it couldn't find a running server.
My first (not so elegant) solution was to stop the client for a while using the sleep method:
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
I use this code just before the client connection, in your example, just before Socket sock = new Socket(HOSTNAME, PORT_NUMBER);
My second solution was based on this answer. Basically I created a method in the client class, this method tries to connect to the server and, if the connection fails, it waits two seconds before retry.
This is my method:
private Socket createClientSocket(String clientName, int port){
boolean scanning = true;
Socket socket = null;
int numberOfTry = 0;
while (scanning && numberOfTry < 10){
numberOfTry++;
try {
socket = new Socket(clientName, port);
scanning = false;
} catch (IOException e) {
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
return socket;
}
As you can see this method tries to create a socket for ten times, then returns a null value for socket, so be carefull and check the result.
Your code should become:
Socket sock = createClientSocket(HOSTNAME, PORT_NUMBER);
if(null == sock){ //log error... }
This solution helped me, I hope it helps you as well. ;-)