I have a larger block of Java code, but the important lines are these:
public static String tcp(String hostName, Number port, Number connectionTimeOutMs, Number readTimeOutMs, String message) {
String errmsg = "";
try (
Socket socket = new Socket();
) {
Inet4Address address = (Inet4Address) Inet4Address.getByName(hostName);
System.out.println("IP address:" + address.getHostAddress());
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue());
socket.setSoTimeout(readTimeOutMs.intValue());
When I supply an IP address in the form "45.79.112.203" or "tcpbin.com", the code gives a SocketTimeoutException.
In the latter case, the line
System.out.println("IP address:" + address.getHostAddress());
gives the correct IP address, so the hostname is resolved correctly; it matches what ping tcpbin.com returns.
I want to be able to call the function with either an IPv4 address (in String format) or a hostname.
What am I doing wrong? Why does the socket fail to establish a connection, even with a high timeout of 60,000 ms?
Notes:
tcpbin.com is an "echo" server to test socket connections. It is only used as an example and should not be the cause of the problem.
Try the following:
echo "Text to send to TCP" | nc tcpbin.com 4242
You should get back the string that was just sent.
In the tcp() function, I pass in numbers in the form of a Number object, since the Java code gets called from Karate test framework via Java inter-op and JavaScript. JavaScript has the type Number, but no int or double.
===
Update:
Here a simple tcp server TcpServer.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
System.out.println("Listening on port 4242");
ServerSocket listener = null;
try {
do {
listener = new ServerSocket(4242);
Socket other = listener.accept();
System.out.println(">>> got a new connection from "
+ other.getInetAddress().toString() + " <<<");
other.getOutputStream().write("Blah blah".getBytes());
other.close();
listener.close();
} while (true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
===
Here a test class to test the tcp() function. It is the connect() statement that times out in case host != localhost.
TestTcpFunction.java:
import java.io.*;
import java.net.*;
public class TestTcpFunction {
public static void main(String[] args) {
String sendMessage = "Blah blah";
String host = (args.length==0)
? "localhost"
: "tcpbin.com";
String result = tcp(host, 4242, 30000, 30000, sendMessage);
System.out.println("result = " + result);
System.out.println("matches = " + result.equals(sendMessage));
}
public static String tcp(String hostName, Number port, Number connectionTimeOutMs, Number readTimeOutMs, String message) {
String errmsg = "";
try (
Socket socket = new Socket();
) {
Inet4Address address = (Inet4Address) Inet4Address.getByName(hostName);
System.out.println("trying to connect to:" + address.getHostAddress());
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue()); // <<< times out if not localhost
socket.setSoTimeout(readTimeOutMs.intValue());
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // autoflush
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
) {
out.print(message);
StringBuilder sb = new StringBuilder();
String line;
boolean addNewline = false;
while ((line = in.readLine()) != null) {
if (addNewline)
sb.append('\n');
sb.append(line);
if (line.lastIndexOf("</response>") >= 0)
break;
addNewline = true;
}
return sb.toString(); // The xml may not be well formed, for instance missing </response>
} finally {}
} catch (UnknownHostException e) {
errmsg = "Unknown host " + hostName;
} catch (SocketTimeoutException e) {
errmsg = "Socket connection timeout (before connection got established)";
} catch (SocketException e) {
errmsg = "Socket error: " + e.getMessage();
} catch (IOException e) {
errmsg = "Couldn't get I/O for the connection to " + hostName;
} catch (Exception e) {
errmsg = "Unknown socket error " + e.getMessage();
}
System.err.println(errmsg);
return "<Error> function tcp (Utils.java): " + errmsg + "</Error>";
}
}
===
Compile both with javac. Then start the server with java TcpServer.
Next run java TestTcpFunction in a different shell, without parameters.
The first time (with local host) it should work correctly.
Then run again, but with any parameter(s), like java TestTcpFunction 1
This time I get a timeout while trying to connect.
The code has been build and tested on my machine.
The client does not time out in connect. A simple output after connect shows that the connection is actually successfully:
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue()); // <<< times out if not localhost
System.out.println("connected successfully");
Instead the program hangs while reading from the server. With the current code it will wait until the server closes the connection or has send a line with </response>. But the server tcpbin.com:4242 will not do anything like this. It will simply read anything and echo it back. To get a </response> string one actually has to send this string - which is not done.
Because of this the read will time out after a while based on the timeout set with socket.setSoTimeout. The resulting SocketTimeoutException is wrongly interpreted as connection timeout, but it is a read timeout.
Given that the code expects the echoed message to include the string </response> one must add it to the sent message:
String sendMessage = "Blah blah</response>";
This is still not enough though and a tcpdump shows that the message does not even get sent. This is because the expectation, that out.print(message); is affected by the autoflush is simply wrong - see I created a PrintWriter with autoflush on; why isn't it autoflushing?. Thus, one must explicitly flush the writer:
out.print(message);
out.flush();
tcpdump shows that the message is now actually send, but nothing is echoed back. This is because the echo server actually expects to read lines, but no line end was send yet. Adding it actually helps to send the message, get an echoed message back and break out of the loop:
String sendMessage = "Blah blah</response>\n";
And why did it work with localhost? Because the sample server did not actually behave like the echo server at tcpbin.com. It did not read anything but just sent a fixed message back and closed the connection.
Related
I have connection to TCP server (ip,port) to which meter is connected. I'd like to read the specified data from this port because when I'm using standard read method it sends me the whole data stream which takes about 15 minutes to read. So my question: is there any method I can use to get one specified register's value using his OBIS code (1.1.1.8.0.255 - active energy taken) in java via TCP server?
import java.net.*;
import java.io.*;
public class scratch {
public static void main(String[] args) {
String hostname = "ip (hidden)";
int port = port (hidden);
try (Socket socket = new Socket(hostname, port)) {
OutputStream out = socket.getOutputStream();
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
int character;
StringBuilder data = new StringBuilder();
String test = "/?!\r\n";
byte[] req = test.getBytes();
out.write(req);
while ((character = reader.read()) != '\n') {
data.append((char) character);
}
System.out.println(data);
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
The message "test" send initiation request to meter and his respond is correct but I dont' know how to put flags (ACK STX ETX) in my request, I've tried something like this:
String test2 = (char)0x6 + "051\r\n";
byte[] req2 = test2.getBytes("ASCII");
out.write(req2);
But meter doesn't recognize it.
I'm trying to implement a simple server using Java sockets. The server should echo back the HTTP Request message that the client sends. Thus if I enter http://localhost:8888 in to my browser, I expect to see the HTTP Request message that I sent as plain text in the web page. The code seems to do what I expect it to do, as the browser does display a http message which is the same as what is printed out in cmd when I run the program.
There are some parts of my code I wonder about though, like having:
out.writeBytes("HTTP/1.0 200 OK\r\n"); out.writeBytes("\r\n");
before my data. Is this enough to be a valid HTTP response?
Is there anything else in my code that doesn't seem to make sense, or could be improved?
Here is the full program which is executed in cmd by "java HTTPEcho 8888" for example, and checked by entering localhost:8888 in your browser, and whatever is printed in cmd should be the same as in the browser.
import java.net.*;
import java.io.*;
public class HTTPEcho {
public static void main( String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java HTTPEcho <port number>");
System.exit(1);
}
int port = Integer.parseInt(args[0]);
try (
ServerSocket welcomeSocket = new ServerSocket(port);
Socket connectionSocket = welcomeSocket.accept();
DataOutputStream out = new DataOutputStream(connectionSocket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
){
// echo back http request message as response to web browser client
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("\r\n");
String s;
while ((s = in.readLine()) != null){
System.out.println(s);
out.writeBytes(s + "\r\n");
if(s.isEmpty()){
break;
}
}
out.close();
in.close();
connectionSocket.close();
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ port + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
I am making a chat program. The problem occurs during the connection phase. Theoretically, the connection happens this way:
[Server] accept() incoming connection
[Client] attempt connection to the server
[Server & Client] initialize IO
[Client] send the username with a suffix indicating if there is or not a password following
[Server] receive username, check if there is an incoming password (if there is, read it too)
[Server] Check in database if client is already registered
[Server] ... (multiple checks of the client's account, etc...)
[Server] send an answer to the client if he is accepted or not
[Client] receive the answer and interpret it
Note that steps 6 and 7 are not yet implemented and the server skips to directly creating a new client account and accepting it in the network.
Now, something happens at either step 4 (if the error comes from the client not sending it's name) or at step 5 (if the error comes from the server not receiving the name), in either case, the server gets stuck waiting for the client's name and the client gets stuck waiting for the server's answer (step 9). I am asking your help in finding the cause of this bug and how to fix it.
Here is the code of the function used by the server to accept new connections:
public void establishConnection() {
Socket client = null;
BufferedReader input = null;
PrintWriter output = null;
String name = null;
String password = null;
try {
client = server.accept();
System.out.println("A connection is being established");
input = new BufferedReader(new InputStreamReader(client.getInputStream()));
output = new PrintWriter(client.getOutputStream());
//LOCATION OF THE BUG
//DESCRIPTION: If the name has been sent, the server seems not to receive it.
System.out.println("Waiting for the client's name...");
name = input.readLine();
if (name.charAt(name.length() - 1) == Keywords.PASSWORD) {
System.out.println("Waiting for the client's password...");
password = input.readLine();
} else
System.out.println("The client has no password");
name = name.substring(0, name.length() - 1);
System.out.println("Creation of the metaClient");
MetaClient metaClient = new MetaClient(name);
if (password != null)
metaClient.setPassword(password);
metaClient.setSocket(client);
System.out.println("Activating listening thread");
metaClient.activateCommunications(this, this);
/* If there is no already registered clients,
* the first to connect shall be the owner.
*/
if (clientsList.size() == 0)
metaClient.addRight(MetaClient.OWNER);
clientsList.add(metaClient);
output.write(Keywords.CONNECTION_ACCEPTED);
System.out.println("The connection process of user " + metaClient.getName()
+ " is complete.");
} catch (IOException e) {
System.out.println("Error when establishing a new connection");
e.printStackTrace();
} finally {
try {
if (input != null)
input.close();
if (output != null)
output.close();
} catch (IOException e) {
System.out.println("Error when closing the IO of the new connection.");
e.printStackTrace();
}
}
}
Here is the code of the builder of the client that tries to connect to the server:
public ChatClient(String ip, int port, String name, String password) throws ConnectException {
this.name = name;
boolean connectionRefused = false;
try {
System.out.println("Establishing connection to the server...");
server = new Socket(ip, port);
BufferedReader input = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter output = new PrintWriter(server.getOutputStream());
//LOCATION OF THE BUG:
//BUG DESCRIPTION: The name seems not to be sent to the server
System.out.println("Sending name to the server...");
if (password == null || password == "") {
name += Keywords.NO_PASSWORD;
output.println(name);
} else {
name += Keywords.PASSWORD;
output.println(name);
System.out.println("Sending password to the server...");
output.println(password);
}
System.out.println("Waiting for the server's response...");
//Wait for the server's response
String response = input.readLine();
if (response.equals(Keywords.CONNECTION_ACCEPTED))
System.out.println("The connection has been accepted");
else
connectionRefused = true;
} catch (IOException e) {
System.out.println("Error when connecting to the server");
e.printStackTrace();
System.exit(1);
}
if (connectionRefused)
throw new ConnectException("The connection was refused by the server");
else {
communication = new CommunicationProtocol(server, this, this);
communication.start();
}
}
Any help would be really much appreciated, it makes quite some time now that i'm trying to fix this to no avail.
Edit to answer Scary Wombat's comment:
Yes, one machine runs the server and another runs the client. But the error happens even when both are running as two separate programs on one machine.
The below program causes this issue
EDITED:
import java.io.*;
import java.net.*;
public class smtpClient {
public static void main(String[] args) {
// declaration section:
// smtpClient: our client socket
// os: output stream
// is: input stream
Socket smtpSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
// Initialization section:
// Try to open a socket on port 25 : step 1
// Try to open input and output streams: step 2
try {
smtpSocket = new Socket("192.168.1.2", 1024);
os = new DataOutputStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());
} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
// If everything has been initialized then we want to write some data
// to the socket we have opened a connection to on port 25
if (smtpSocket != null && os != null && is != null) {
try {
// The capital string before each colon has a special meaning to SMTP
// you may want to read the SMTP specification, RFC1822/3
os.writeBytes("HELO\n");
os.writeBytes("MAIL From: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("RCPT To: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("DATA\n");
os.writeBytes("From: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("Subject: testing\n");
os.writeBytes("Hi there\n"); // message body
os.writeBytes("\n.\n");
os.writeBytes("QUIT");
// keep on reading from/to the socket till we receive the "Ok" from SMTP,
// once we received that then we want to break.
String responseLine;
while ((responseLine = is.readLine()) != null) {
System.out.println("Server: " + responseLine);
if (responseLine.indexOf("Ok") != -1) {
break;
}
}
// clean up:
// close the output stream
// close the input stream
// close the socket
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
}
Console Log :
Couldn't get I/O for the connection to: hostname
The program I took is from :
http://www.javaworld.com/jw-12-1996/jw-12-sockets.html?page=4
I have already tried modifying the port from 25 to 1024
I am running it on my local PC, so I am admin on this system, but not sure if there is any default firewall issue(running this in eclipse on windows 7)
As per your comments below : DO I need to make a listner, which mean to say a Server Socket, which will listen to smtp client requests
Answer is: according to details what you have provided, there is no listener running or machine with specified IP and port number.
UPD: then you are trying to connect to somewhere you do have to be sure that there is something which listens on other side, either writing your own server code or by using a 3rd party server/code to provide certain service on a port number you are trying to reach.
Why would you expect that there is a mail server running on machine with an address you've provided?
It sounds like some other program is using port 1024.
Try a different port.
I'm developing an application, where users have the option to have sent an e-mail to a specified e-mail every x minutes.
I don't want to rely on JavaMail (i.e. rely on whether my users have added the JavaMail jar to their classpath).
I realize that I could go on and create a server for doing this and connect to it with the necessary details, but this is last option.
How would I go on sending an e-mail in this case?
Are there any online services etc (paid or free) that provides a solution for this? For example connecting to them and specifying recipient e-mail and message, they would handle the e-mail sending.
Are there any smart and/or reasonably easy ways of sending e-mails using the Java Core packages?
Thanks :)
Mike.
You can -- by opening a socket to the smtp server and then writing to that socket.
Socket socket=new Socket("your.smtp.server",25);
br= new BufferedReader(newInputStreamReader(socket.getInputStream()));
os = socket.getOutputStream();
smtp("HELLO " + toEmailAddress);
smtp("MAIL FROM: "+ fromEmailAddress);
smtp("DATA");
smtp(yourContent");
and your smtp method would just read from the bufferedreader and write to socket
public void smtp(String command) {
br.readLine();
os.write(command.getBytes());
}
Here is some old code I had lying around that might get you started:
import java.io.*;
import java.net.*;
class EMail2
{
public static void main(String args[])
{
if ( args.length != 5 )
{
System.out.print("usage: java EMail2 <smtp-host> <fromName> <toAddress>");
System.out.println(" <subject> <body>");
System.exit(-1);
}
try
{
send(args[0], args[1], args[2], args[3], args[4]);
}
catch(Exception e)
{
e.printStackTrace();
}
System.exit(0);
}
public static void send(String host, String from, String to, String subject, String message)
{
try
{
System.setProperty("mail.host", host);
// System.setProperty("mail.smtp.starttls.enable","true"); // not sure it this works or not
// open connection using java.net internal "mailto" protocol handler
URL url = new URL("mailto:" + to);
URLConnection conn = url.openConnection();
conn.connect();
// get writer into the stream
PrintWriter out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream() ) );
// write out mail headers
// From header in the form From: "alias" <email>
out.println("From: \"" + from + "\" <" + from + ">");
out.println("To: " + to);
out.println("Subject: " + subject);
out.println(); // blank line to end the list of headers
// write out the message
out.println(message);
// close the stream to terminate the message
out.close();
}
catch(Exception err)
{
System.err.println(err);
}
}
}