I want to make a TCP/IP communication in Java but i want to open the TCP/IP port, send commands and then close that port.
I know i can open connection, send command, and then close connection in one method but the problem is: the machine i'm connecting to can't accept more that 5 connections and when the connection closes machine won't accept any other connection for about 6 seconds.
My goal is to open connection in one thread, send commands for some time and then after i'm finished i want to close connection.
This is how i'm doing it now:
void sendCommand(String command) throws IOException {
String ipaddress = "192.168.0.2";
Socket commandSocket = null;
PrintWriter out = null;
BufferedWriter out = null;
BufferedReader in = null;
BufferedWriter outToDetailFile = null;
FileWriter fstream = null;
commandSocket = new Socket(ipaddress, 7420);
out = new PrintWriter(commandSocket.getOutputStream(), true);
out = new BufferedWriter(new OutputStreamWriter(commandSocket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(commandSocket.getInputStream()));
out.write("c");out.flush();
out.write(command);out.flush();
String message = in.readLine();
//System.out.println(message);
out.close();
in.close();
commandSocket.close();
}
I basicaly need to split this method in 3 parts, one part which I call to open the connection, 2nd part to send commands (i need to send commands from my swing form) and then when i'm finished with sending commands i need to close connection on button click (or any other event).
The question is: How to send commands in already opened connection and then close that connection when i'm finished with sending commands.
I'm trying to achieve something like this
-Method openConnection should open connection.
-Method sendCommand should send (multiple commands at random time intervals (every 5-10 seconds)) connection to already opened socket (opened with method opneConnection)
-Method closeConnection should close connection that has ben opened by openConnection.
why not create a ServerSocket on the receiving end, put it on an endless loop so its always listening, and open a thread for each new incoming connection.
you can now have endless connections.
if you need a code example just say so...
that's how I built my server/client application
If you're asking how to refactor your code to have 3 methods here is how to do it :
Socket openConnection(String ipaddress) throws IOException {
return new Socket(ipaddress, 7420);
}
void sendCommand(Socket commandSocket, String command) throws IOException {
PrintWriter out = null;
BufferedWriter out = null;
BufferedReader in = null;
BufferedWriter outToDetailFile = null;
FileWriter fstream = null;
out = new PrintWriter(commandSocket.getOutputStream(), true);
out = new BufferedWriter(new OutputStreamWriter(commandSocket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(commandSocket.getInputStream()));
out.write("c");out.flush();
out.write(command);out.flush();
String message = in.readLine();
//System.out.println(message);
}
void closeConnection(Socket commandSocket) throws IOException {
commandSocket.close();
}
Now you have to call the first method (openConnection) once when you load your form or when you want to send your first command.
Then for each command, call the second method (sendCommand), it will only send commands without closing the connection.
Finally, call the third method (closeConnection) when all the commands are sent (or when you close your form).
One important thing is not to close the input/output streams/writers as it could close the socket.
I just used your code without trying to correct or improve it, I think there will be some compilation failures (ex: declare the out variable twice).
If you're asking how to use efficiently your server with its limits (5 connections max, wait 6 minutes between additional connections) you can do this :
Use a connection pool (Object pool pattern, Connection pool).
The principle of a connection pool is that instead of asking a connection directly, you ask it to the pool that will create it (connect) for you and give it to you.
When you have finished with your connection (not anymore commands to send), you return it to the pool instead of closing it directly to make it available to other treads/consumers.
You may have to hand code the connection pool class by yourself with the limits you specified :
5 connection maximum
if you close a connection, wait for 6 mins before reopening it
To optimize it and avoid the 6 min waiting limit, you could also try to reuse connections in a reasonable way.
Related
Suppose that I have a multi-threaded web server that only allow clients to perform GET requests for a couple of HTML files. I want to maintain a persistent connection (i.e HTTP Connection: keep-alive) while "dynamically" displaying the content for each request the client makes. Like if they first request index.html then foo.html etc. The problem right now is when I don't close the streams and socket, the program will hang until it happens.
Simply put, the multi-threaded web server consist of a thread pool (Java's ExecutorService) with a ServerSocket that listens to a specific port (e.g 9000) and selects a thread from the threadpool to handle the opening of a client socket to the server. It is basically the same setup as showed in http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html.
My modified setup looks like this:
WorkerRunnable.java:
public void run() {
try {
InputStream input = this.clientSocket.getInputStream();
OutputStream output = this.clientSocket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
List<String> headers = readInputStream(input)
Request request = new Request(headers);
Response response = new Response(request);
// response.raw() returns correctly formatted HTTP
output.write(response.raw().getBytes(StandardCharsets.UTF_8));
// close the socket if the client specifies Connection: close
if (!request.keepAlive()) {
output.close();
input.close();
} else {
this.clientSocket.setKeepAlive(true);
}
} catch (IOException e) {
e.printStackTrace();
}
private List<String> readInputStream(InputStream input) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
List<String> headers = new ArrayList<>();
while ((line = reader.readLine()) != null && !line.isEmpty()) {
headers.add(line);
}
return headers;
}
My problem is that the HTML only will be displayed when the input/output stream (and thus also the socket) are closed. As far as I understand, the Socket.InputStream will basically hang until it receives an EOF token - which it receives when the stream closes. But if I want to maintain a persistent connection, it doesn't really make sense to close the streams and client socket. So I was wondering how to maintain a persistent connection while also displaying the content of multiple GET requests from clients (assuming this is the correct approach)? If not, please let me know if I've approached this task wrongly.
I have tried to flush the output stream as suggested here, but the problem still persists.
I have a software driver which communicates with a third-party controller; I have an API for using the latter but no visibility of its source code, and the supplier is not co-operative in trying to improve things!
The situation is as follows.
To send a request to the controller, I send an XML packet as the content of an HTTP POST to a servlet, which then sends me the response. The original code, implemented by a previous developer, works stably using java.net.Socket. However, our driver is implemented such that a new socket is created for EVERY request sent and, if the driver gets busy, the third-party controller struggles to keep up in terms of socket handling. In fact, their support guy said to me: "You really need to leave 5 seconds between each request...". This simply isn't commercially acceptable.
To improve performance, I wanted to try leaving our end of the socket open and reusing the socket pretty much indefinitely (given that connections can drop unexpectedly of course, but that's the least of my concerns and is manageable). However, whatever I seem to do, the effect is that if I use Comms.getSocket(false), a new socket is created for each request and everything works OK but bottlenecks when busy. If I use Comms.getSocket(true), the following happens:
Controller is sent first request
Controller responds to first request
Controller is sent second request (maybe 5 seconds later)
Controller never responds to second request or anything after it
postRequest() keeps getting called: for the first 12 seconds, the console outputs "Input shut down ? false" but, after that, the code no longer reaches there and doesn't get past the bw.write() and bw.flush() calls.
The controller allows both HTTP 1.0 and 1.1 but their docs say zilch about keep-alive. I've tried both and the code below shows that I've added Keep-Alive headers as well but the controller, as server, I'm guessing is ignoring them -- I don't think I have any way of knowing, do I ? When in HTTP 1.0 mode, the controller certainly returns a "Connection: close" but doesn't do that in HTTP 1.1 mode.
The likelihood is then that the server side is insisting on a "one socket per request" approach.
However, I wondered if I might be doing anything wrong (or missing something) in the following code to achieve what I want:
private String postRequest() throws IOException {
String resp = null;
String logMsg;
StringBuilder sb = new StringBuilder();
StringBuilder sbWrite = new StringBuilder();
Comms comms = getComms();
Socket socket = comms.getSocket(true);
BufferedReader br = comms.getReader();
BufferedWriter bw = comms.getWriter();
if (null != socket) {
System.out.println("Socket closed ? " + socket.isClosed());
System.out.println("Socket bound ? " + socket.isBound());
System.out.println("Socket connected ? " + socket.isConnected());
// Write the request
sbWrite
.append("POST /servlet/receiverServlet HTTP/1.1\r\n")
.append("Host: 192.168.200.100\r\n")
.append("Connection: Keep-Alive\r\n")
.append("Keep-Alive: timeout=10\r\n")
.append("Content-Type: text/xml\r\n")
.append("Content-Length: " + requestString.length() + "\r\n\r\n")
.append(requestString);
System.out.println("Writing:\n" + sbWrite.toString());
bw.write(sbWrite.toString());
bw.flush();
// Read the response
System.out.println("Input shut down ? " + socket.isInputShutdown());
String line;
boolean flag = false;
while ((line = br.readLine()) != null) {
System.out.println("Line: <" + line + ">");
if (flag) sb.append(line);
if (line.isEmpty()) flag = true;
}
resp = sb.toString();
}
else {
System.out.println("Socket not available");
}
return resp; // Another method will parse the response
}
To ease testing, I provide the socket using an extra Comms helper class and a method called getSocket(boolean reuse) where I can choose to always create a new socket or reuse the one that Comms creates for me, as follows:
public Comms(String ip, int port) {
this.ip = ip;
this.port = port;
initSocket();
}
private void initSocket() {
try {
socket = new Socket(ip, port);
socket.setKeepAlive(true);
socket.setPerformancePreferences(1, 0, 0);
socket.setReuseAddress(true);
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
System.out.println("### CREATED NEW SOCKET");
}
catch (UnknownHostException uhe) {
System.out.println("### UNKNOWN HOST FOR SOCKET");
}
catch (IOException ioe) {
System.out.println("### SOCKET I/O EXCEPTION");
}
}
public BufferedReader getReader() { return br; }
public BufferedWriter getWriter() { return bw; }
public Socket getSocket(boolean reuse) {
if (! reuse) initSocket();
return socket;
}
Can anyone help ?
If we assume that keep-alive thing is working as expected, I think the line while ((line = br.readLine()) != null) is a faulty one, as this is kind of infinity loop.
readline() returns null when there is no more data to read, e.g. a EOF, or when server/client closes the connection, that will break-down your reusing socket solution, since an open stream will never cause a null to a readLine() call, but blocking.
You need to fix the alg about reading a response (why not using implemented http client?), checking content-length, and when read the amount of required data from body, go for next loop by keeping the socket alive.
After that setting flag to true, you have to know what kind of data should be read(considering mime/content-type), besides that, the length of data, so reading data using readLine() may not be a good practice here.
Also make sure server allow for persistence connection, by checking if it respects it by responsing the same connection:keep-alive header.
I have a TCP client application in Java, through this application i can communicate with a server application.
I have a simple method sendCommand which sends the message to the server:
void sendCommand(String command) throws IOException {
String ipaddress = "192.168.0.2";
Socket commandSocket = null;
PrintWriter out = null;
BufferedWriter out = null;
BufferedReader in = null;
BufferedWriter outToDetailFile = null;
FileWriter fstream = null;
String version = "";
int numberOfBallsInGame;
int ledCycleState = 1;
commandSocket = new Socket(ipaddress, 7420);
out = new BufferedWriter(new OutputStreamWriter(commandSocket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(commandSocket.getInputStream()));
out.write("c");out.flush();
out.write(command);out.flush();
String message = in.readLine();
//System.out.println(message);
out.close();
in.close();
commandSocket.close();
}
Now, because the server application is on the machine which does not accept more than 2 connections in 20 seconds i need to modify my method and "split" it in 3 different methods (i think).
My plan is the following:
I would like to call the connection to the server in one thread, keep it opened untill i want to close it, but i should be able to send the commands between opening the connection and closing it.
I'm pretty new to Java and i'll try to explain here exactly what i want to do:
1) I want to open the connection to TCP server.
2) After opening the connection i want to be able to send commands to an already opened connection by calling this method:
void sendCommand(String command) throws IOException {
out.write("c");out.flush();
out.write(command);out.flush();
}
And after i'm finished with sending commands i want to call some method to close my running connection.
Because i'm pretty new to java it would be very nice if someone could show me how to achieve this or modify my method.
Thank you in advance,
I am writing a proxy server in Java.
Initially, I do (simplified)
server = new ServerSocket(5568);
incoming = server.accept();
input = incoming.getInputStream();
...
outgoing = new Socket(host, 80);
output = outgoing.getOutputStream();
output.write(inputbuffer, 0, i);
where inputbuffer is some collection of bytes received so far (I read the incoming data up until the part where I know the host header, and then open a connection to the server and send what I have so far). So server is my welcome socket, input is the data coming to my proxy from the client, and output is the data to the serve from my proxy.
Next, I want the output from the server to be written to the client in parallel with the client still possibly writing stuff to the server. So I create a separate thread to read from the client:
final InputStream finalInput = input;
final OutputStream finalOutput = output;
Thread sendingStuff = new Thread(){
public void run(){
int c;
while ((c = finalInput.read()) != -1){
finalOutput.write((byte)c);
finalOutput.flush();
}
finalInput.close();
finalOutput.close();
}
}
sendingStuff.start();
Finally, I have a different section in the main thread to read from the server and write that to the client.
InputStream reverseInput = outgoing.getInputStream();
OutputStream reverseOutput = incoming.getOutputStream();
int c;
while ((c = reverseInput.read()) != -1){
reverseOutput.write((byte)c);
reverseOutput.flush();
}
reverseInput.close();
reverseOutput.close();
What happens is I get input, and send output, but the browser spins forever and the line in the thread that's reading from the client never gets a -1 signal.
A lot of the time I get errors that say things like "invalid header name" or "your browser sent a request that the server could not understand" and I think it has to do with this problem I'm having. One time I even got an IOException: Socket Closed on the line that reads from the client.
So why isn't the client sending an EOF? And is this the right way to go about doing this?
"I think it's because my HTTP request has Connection: keep-alive. How do I handle this?"
I think maybe you can just open your socket once for one connection.
Try to have flag like isNewConnection. set it to true at first and after the connection is initiated, set it to false.
I have a client socket connected to the server socket, the server will send data to the client from time to time while its connected. currently my client uses a while loop to keep receiving data from the server even the server is not sending anything.
my question is, is there any more efficient way to listen for input?
i am thinking maybe create a thread for the socket connection, and put it to sleep when there is no incoming data, and sends an interrupt when there is data coming in. would that work? if putting the thread to sleep, would it break the socket connection?
i cannot modify the server socket and it doesnt initiate a connection.
import java.io.*;
import java.net.Socket;
public class core_socket {
public static void main(String[] args) {
String host = ("192.168.100.206");
int port = 4025;
try {
Socket socket = new Socket(host, port);
System.out.println("created socket\n");
OutputStream os = socket.getOutputStream();
boolean autoflush = true;
PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// read the response
boolean loop = true;
StringBuilder sb = new StringBuilder(8096);
while (loop) {
if (in.ready()) {
int i = 0;
while (i != -1) {
i = in.read();
sb.append((char) i);
}
loop = false;
}
}
// display the response to the out console
System.out.println(sb.toString());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
See multi-user chat application example at http://cs.lmu.edu/~ray/notes/javanetexamples/ - basically, you should consider spawning off a new worker thread for each incoming connection and then go back to listen for any new incoming requests.
A long time ago I wrote one of the first application servers (say in 1997 when most people didn't know what an app server is) - it was deployed at one of the largest higher-ed institutions and processed couple million requests per day during peak times - that's not the institution in the link by the way. The reason I mention this is... multi-threading gives you a tremendous scalability with very little effort - even if scalability is not what you are looking for, worker thread model is still a good practice.
Maybe what you want is to use asynchronous sockets. Basically, it spins off another thread that's job is to listen for any data on the socket. Once data does come in, a "callback" method is called, which can then begin to process your data.
I've never done sockets in Java before though, just C#, so I'm not sure how it compares, but the concept should remain the same.