I have written a simple NIO Server and Inner-Client (Inside the same program)in a single program such that Server receives data from outside and the Inner-Client sends the data received by the server to out side Server. I am running both the processes continuously in two parallel threads using While() loops. Now the problem is, I will be receiving data at a very high speed to the Inside server and everything I receive, I will send them to the outer server using the Inside client. Some times, the retrieval of the data from the Buffer resulting in half the size of the total string. That means I am receiving "HELLO", but the total string is "HELLO SERVER". This is just an example. I will receive very long strings. Similarly, after sending the data to Outer-server through Inner client I will be listening for data and I am receiving the same half-strings.Is there any way I can eliminate these Half-strings and get the full-length string. I have to get the full string without any fail.
I am using while loops for the process. This is making the CPU utilization go high like 50%. Is there any way I can reduce the CPU utilization without using Thread.sleep method? Because I need to continuously listen to data from the Outer parties. They may send 2-4 strings for one single request. I tried using Executor service thread for running the processes continuously but it requires some sleep to be included. If I include some sleep I am not able to get the String and if I don't include the sleep my CPU-Utilization is going very high (50-60%). Can anyone help me with these two issues?
Here is my code:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
static SocketChannel channel;
public static void main(String[] args) throws IOException {
System.out.println("Listening for connections on : 8888"); //8888
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
channel = serverChannel.accept();
System.out.println("Connected...");
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.configureBlocking(false);
ReceiveFromOMS receivefromOMS;
SendToExchange sendExchange;
receivefromOMS = new ReceiveFromOMS();
sendExchange = new SendToExchange();
Thread t1 = new Thread(receivefromOMS);
Thread t2 = new Thread(sendExchange);
t1.start();
t2.start();
}
}
class ReceiveFromOMS extends Thread{
public static SocketChannel channel;
static ByteBuffer buffer = ByteBuffer.allocate(1024);
static ServerSocketChannel serverChannel ;
public static int ReceiveFromOMSPort;
BlockingQueue<String> fromOMSqueue = new LinkedBlockingQueue<>(30);
#Override
public void run(){
while(true){
try {
receiveFromOMS();
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex1) { }
}
}
}
public void receiveFromOMS() throws InterruptedException{
try {
int numRead = -1;
numRead = channel.read(buffer);
while(numRead==0){
numRead = channel.read(buffer);
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by client: " + remoteAddr);
channel.close();
return;
}
byte[] data = new byte[numRead];
System.arraycopy(buffer.array(), 0, data, 0, numRead);
fromOMSqueue.add(new String(data));
String msg = fromOMSqueue.poll();
System.out.println("OutGoing To Exchange>> " + msg);
SendToExchange.sendToEchange(msg);
buffer.flip();
buffer.clear();
} catch (IOException ex) {
System.err.println(ex.getMessage());
Thread.sleep(5000);
}
}
}
class SendToExchange extends Thread{
static SocketChannel channel;
static ByteBuffer bb = ByteBuffer.allocateDirect(1024);
static Charset charset = Charset.forName("UTF-8");
public byte[] data;
public static String message;
#Override
public void run(){
try {
while(true){
receive();
Thread.sleep(100);
}
} catch (IOException | InterruptedException ex) {
System.err.println(ex.getMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex1) {}
}
}
public static void sendToEchange(String msg){
try {
bb = stringToByteBuffer(msg, charset);
channel.write(bb);
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
public void receive() throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int numRead = -1;
numRead = channel.read(buffer);
while (numRead == 0) {
numRead = channel.read(buffer);
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by Exchange: " + remoteAddr);
channel.close();
return;
}
buffer.flip();
data = new byte[numRead];
buffer.get(data);
message = new String(data);
System.out.println("Incoming from Exchange>> " + message);
buffer.clear();
}
public static ByteBuffer stringToByteBuffer(String msg, Charset charset){
return ByteBuffer.wrap(msg.getBytes(charset));
}
}
Lets assume that your server is appending to each string an End of message marker string, e.g. "<EOM>", then the following modification of your code (treat it as a sketch since I did not verified it completely) can be used to wait for the full string:
String end = "<EOM>";
StringBuilder curStr = new StringBuilder();
int numRead = 0;
while(-1 != (numRead = channel.read(buffer))){
curStr.append(new String(buffer.array(), 0, numRead, Charset.forName("UTF-8")));
int endIdx = curStr.indexOf(end);
if (endIdx != -1) {
fromOMSqueue.add(curStr.substring(0, endIdx + end.length()));
break;
}
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by client: " + remoteAddr);
channel.close();
return;
}
String msg = fromOMSqueue.poll();
Related
I have some simple client and server code, where the client sends some bytes to the server, and the server responds with some bytes. The client prints the received bytes, and then closes the socket.
This works fine the first time the client runs, but subsequent calls get no response.
package sockets.com;
// Client Side
import java.io.*;
import java.net.*;
public class ClientSideTCPSocket {
public void run() {
try {
int serverPort = 4023;
InetAddress host = InetAddress.getByName("localhost");
System.out.println("Connecting to server on port " + serverPort);
Socket socket = new Socket(host, serverPort);
System.out.println("Just connected to " + socket.getRemoteSocketAddress());
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
String s = "HELLO SERVER";
byte[] bytes = s.getBytes("US-ASCII");
for (byte b : bytes) {
out.write(b);
}
int ch = 0;
while ((ch = in.read()) >= 0) {
System.out.println("Got byte " + ch);
}
out.flush();
out.close();
socket.close();
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ClientSideTCPSocket client = new ClientSideTCPSocket();
client.run();
}
}
Server code
package sockets.com;
//Server Side
import java.net.*;
import java.io.*;
public class ServerSideTCPSocket {
public void run() {
try {
int serverPort = 4023;
ServerSocket serverSocket = new ServerSocket(serverPort);
serverSocket.setSoTimeout(900000);
while (true) {
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
//
int ch = 0;
while ((ch = server.getInputStream().read()) >= 0) {
System.out.println("Got byte " + ch);
}
// Write to output stream
OutputStream out = server.getOutputStream();
String s = "HELLO CLIENT";
byte[] bytes = s.getBytes("US-ASCII");
for (byte b : bytes) {
System.out.println(b);
out.write(b);
}
}
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerSideTCPSocket srv = new ServerSideTCPSocket();
srv.run();
}
}
Would be grateful for any comments regarding why this is the case. Thank you.
A few things:
This block of code will loop forever until after the client closes his connection:
while ((ch = server.getInputStream().read()) >= 0) {
System.out.println("Got byte " + ch);
}
Then after the client closes his connection, the subsequent attempt to send "HELLO CLIENT" to the socket will generate an IO exception. That will trigger your server loop to exit.
The easy fix is to adjust your protocol such that the "message" is completed on some sentinel char. In my easy fix, I just adjusted it to break out when a ! was received.
Better to have each client session terminate on an ioexception instead of the entire server block. My refactor of your code:
public class ServerSideTCPSocket {
public void tryCloseSocketConnection(Socket socket) {
try {
socket.close();
}
catch(java.io.IOException ex) {
}
}
public void processClientConnection (Socket clientConnection) throws java.io.IOException {
int ch = 0;
while ((ch = clientConnection.getInputStream().read()) >= 0) {
System.out.println("Got byte " + ch);
if (ch == '!') {
break;
}
}
// Write to output stream
OutputStream out = clientConnection.getOutputStream();
String s = "HELLO CLIENT!";
byte[] bytes = s.getBytes("US-ASCII");
for (byte b : bytes) {
System.out.println(b);
out.write(b);
}
}
public void run() {
try {
int serverPort = 4023;
ServerSocket serverSocket = new ServerSocket(serverPort);
serverSocket.setSoTimeout(900000);
while (true) {
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket clientConnection = serverSocket.accept();
try {
System.out.println("Just connected to " + clientConnection.getRemoteSocketAddress());
processClientConnection(clientConnection);
}
catch (java.io.IOException ex) {
System.out.println("Socket connection error - terminating connection");
}
finally {
tryCloseSocketConnection(clientConnection);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerSideTCPSocket srv = new ServerSideTCPSocket();
srv.run();
}
}
Then adjust your client code's message to be:
String s = "HELLO SERVER!"; // the exclamation point indicates "end of message".
I have a socket client that hangs whenever I try to read the input stream from the socket.
DataInputStream dis = new DataInputStream(socket.getInputStream());
int singleByte;
while((singleByte = dis.read()) != -1) { //<-- hangs here
char c = (char)singleByte;
// append character
message_string += c;
}
Hangs on while((singleByte = dis.read()) != -1) {
I have confirmed that the server is echoing back what I send it in raw ASCII.
What am I not understanding? Why is it hanging when trying to read the server response?
Server side (handles the request):
class HandleInputBuffer implements Runnable {
private String msg = "";
private String response = "8";
public HandleInputBuffer(String str) {
this.msg = str;
}
#Override
public void run() {
String exception_msg = "";
// process incoming message
try {
if(msg!=null){
if(msg.length()>0){
// create and send reply
String response = "8";
// ****************************
// create and send response
// ****************************
try {
response = msg;
output_stream = new DataOutputStream(client_socket.getOutputStream());
output_stream.writeInt(response.getBytes("US-ASCII").length);
output_stream.write(response.getBytes("US-ASCII"));
output_stream.flush();
output_stream.close();
//client_socket.shutdownOutput();
client_socket.close();
} catch (IOException e) {
e.printStackTrace();
try{output_stream.flush();} catch (IOException e1) {}
try {client_socket.close();} catch (IOException e1) {}
try {updateConversationHandler = new Handler();} catch (Exception e1) {}
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client side refactor - This code hangs int length = dis.readInt();
InetAddress serverAddr = InetAddress.getByName(edit_ip_address.getText().toString());
if(socket == null){
socket = new Socket(serverAddr, Integer.parseInt(edit_port.getText().toString()));
}
// send bytes
output_stream = new DataOutputStream(socket.getOutputStream());
output_stream.write(command.getBytes("US-ASCII"));
DataInputStream dis = new DataInputStream(socket.getInputStream());
int length = dis.readInt();
byte[] buffer = new byte[length]; //<-- OutOfMemoryException
dis.readFully(buffer);
for (byte b:buffer){
char c = (char)b;
message_string += c;
}
This loop will block until the peer closes the connection.
Ergo the peer is not closing the connection.
EDIT The correct way to read what you're sending is as follows:
You need to read the integer length word that you're writing. It doesn't magically appear via available():
int length = dis.readInt();
byte[] buffer = new byte[length];
dis.readFully(buffer);
But I would throw the sending and receiving code away and use readUTF()/writeUTF(), assuming the data is character data. If it isn't, you shouldn't be assembling it as a String.
EDIT 2 Proof that this works:
Client.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Client
{
public static void main(String[] args) throws IOException
{
try (Socket s = new Socket("localhost", 9999))
{
DataOutputStream out = new DataOutputStream(s.getOutputStream());
out.writeInt(1);
out.writeBytes("8");
DataInputStream in = new DataInputStream(s.getInputStream());
int count = in.readInt();
System.out.println("Reading "+count+" bytes");
byte[] buffer = new byte[count];
in.readFully(buffer);
System.out.write(buffer, 0, count);
System.out.println();
}
}
}
Server.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
{
public static void main(String[] args) throws IOException
{
try (ServerSocket ss = new ServerSocket(9999))
{
try (Socket s = ss.accept())
{
DataInputStream in = new DataInputStream(s.getInputStream());
int count = in.readInt();
System.out.println("Reading "+count+" bytes");
byte[] buffer = new byte[count];
in.readFully(buffer);
System.out.write(buffer, 0, count);
System.out.println();
DataOutputStream out = new DataOutputStream(s.getOutputStream());
out.writeInt(count);
out.write(buffer, 0, count);
}
}
}
}
If yours doesn't, you are reading something else from the socket, or writing something else to it, or not running the code you think you're running.
I know this question has been asked before, and I've tried the different solutions, but I got stuck in the implementation part.. :(
Currently multiple clients can connect to the server, I used the multithreaded KnockKnock server/client example from javadocs, and edited it slightly so that you can just send messages to the server, and it will echo them back to you, but I want to be able to make it so that if client 1 sends a message, then the server will broadcast them back to all the clients connected to the server.
I've tried looking around and saw people in the same position as I am in now, and they were told to make a list to keep track of all the connections, and then iterate through the list and send the message, but I really don't know in which class to put it or how to handle it.
If someone could show me or just give me hints to where I should start, it would be greatly appreciated, as I'm really just stuck at the moment :(
Here's where I'm at so far:
Server:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Server {
public static void main(String[] args) throws IOException {
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(4444)) {
while (listening) {
ServerThread thread = new ServerThread(serverSocket.accept());
thread.start();
}
} catch (IOException e) {
System.err.println("Could not listen on port " );
System.exit(-1);
}
}
}
ServerThread
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerThread extends Thread{
private Socket socket = null;
public ServerThread(Socket socket) {
super("MultiServerThread");
this.socket = socket;
}
public void run() {
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
) {
while (true) {
String input = in.readLine();
System.out.println(input);
out.println("ecco " + input);
if (input.equals("Bye"))
break;
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client (not sure if necessary, but here is it anyways)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws IOException {
try (
Socket kkSocket = new Socket("172.30.242.51", 4444);
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(kkSocket.getInputStream()));
) {
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
while (true) {
if(in != null) {
String input = stdIn.readLine();
out.println("Client: " + input);
System.out.println(in.readLine());
out.flush();
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " );
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " );
System.exit(1);
}
}
}
Have a nice weekend =)
Operation 'write' is blocking in your example. So iterating by all connections can lead to delays and blocking your push thread. Also always set SO_TIMEOUT for socket if you do not want to have memory leaks.
I suggest using netty server
It has very nice functionality for pushing data to all connected clients - look for ChannelGroup
Why don't you use NIO to solve this problem?
A simple example:
public class EchoServer {
public static void main(String[] args) throws Exception {
//Create TCP server channel
ServerSocketChannel serv = ServerSocketChannel.open();
ServerSocket sock = serv.socket();
//Create a socket on your IP and port (i.e: localhost:12345)
SocketAddress addr = new InetSocketAddress(12345);
//Bind server socket and socket address
sock.bind(addr);
//Configure socket so all its methods won't be blocking
serv.configureBlocking(false);
//Create a selector to attend all the incoming requests
Selector selector = Selector.open();
//Register into the selector the accept request type
serv.register(selector,SelectionKey.OP_ACCEPT);
//Create a common buffer
ByteBuffer commonBuffer = ByteBuffer.allocate(10000);
commonBuffer.clear();
Iterator<SelectionKey> it = null;
ByteBuffer channelBuffer = null;
for (;;){ //Infinite loop
System.out.println("Waiting for events......");
selector.select(); // This call do is blocking
System.out.println("New event received");
it = selector.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
System.out.println(String.format("Processing %s", key));
it.remove(); // Remove it to avoid duplications
try{
if (key.isAcceptable()) {
System.out.println("Received new connection request");
processConnectionRequest(serv, selector);
}else if (key.isReadable()) {
System.out.println("Received new reading request");
processReadingRequest(selector, commonBuffer, key);
}else if (key.isWritable()) {
System.out.println("Received new writing request");
processWritingRequest(key);
}
}catch(Exception e){
key.cancel();
try {
key.channel().close();
} catch (Exception ce) {}
}//end catch
}//end while
}//end for
}//end main
private static void processWritingRequest(SelectionKey key) throws IOException {
SocketChannel cli = (SocketChannel) key.channel();
ByteBuffer buf = (ByteBuffer) key.attachment();
System.out.println(String.format("Wrinting into the channel %s", cli));
buf.flip();//prepare the buffer
buf.rewind();
cli.write(buf);
if (buf.hasRemaining()) {
//If there is more content remaining, compact the buffer
buf.compact();
} else {
buf.clear();
key.interestOps(SelectionKey.OP_READ);
}
}
private static void processReadingRequest(Selector selector, ByteBuffer commonBuffer, SelectionKey key)
throws IOException {
SocketChannel cli = (SocketChannel) key.channel();
if (cli.read(commonBuffer) == -1) {
System.out.println(String.format("Closing channel %s", cli));
cli.close(); // internally calls key.cancel()
}
else {//Send the data to all the channels
commonBuffer.flip();//prepare the buffer
Iterator<SelectionKey> it2 = selector.keys().iterator();
System.out.println("Writing data to all the channels");
SelectionKey keys = null;
while(it2.hasNext()) {
keys = it2.next();
System.out.println(String.format("Writing in %s", keys));
ByteBuffer buf = (ByteBuffer) keys.attachment();
if(buf!=null)
{
buf.put(commonBuffer);
keys.interestOps(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
commonBuffer.rewind();
}
}
commonBuffer.clear();
}
}
private static void processConnectionRequest(ServerSocketChannel serv, Selector selector)
throws IOException, ClosedChannelException {
ByteBuffer channelBuffer;
SocketChannel cli = serv.accept();
cli.configureBlocking(false);
channelBuffer = ByteBuffer.allocate(10000);
System.out.println(String.format("Registering new reading channel: %s", cli));
cli.register(selector, SelectionKey.OP_READ, channelBuffer);
}
}
I am sending data from my system to third party systems using a persistent TCP Socket. It works fine but sometimes due to some bug in the third party system the connection slows down and it slows down my application.
How to catch this state? Should i just set a connection timeout? Because when this happens i need to close the existing socket and reestablish a new one after some period of time.
The code is as follows:
public static void initializeCongServer() throws Exception {
try{
Calendar currentTime = Calendar.getInstance();
if(congestionDownStartTime!=null){
long timeInSecs = (currentTime.getTimeInMillis() - congestionDownStartTime.getTimeInMillis())/1000;
if(timeInSecs < config.getCongestionReconnectTimeInSecs()){
logWrapper1.log(Level.DEBUG, "Packet not sent to Congestion as it was down when last checked. Connection to congestion will be retried again in: "+ (config.getCongestionReconnectTimeInSecs() - timeInSecs)+" seconds");
return;
}
}
if(congConnector!=null){
congConnector.close();
if(congConnector.sock!=null){
congConnector.sock.close();
}
congConnector = null;
}
logWrapper1.log(Level.DEBUG, "Reconnecting with congestion server.");
congConnector = new Connector(config.getCongServerIP(), config.getCongServerPort(), 1, 2);
congConnector.connect();
congestionDownStartTime = null;
} catch(Exception e){
congestionDownStartTime = Calendar.getInstance();
logWrapper1.log(Level.DEBUG, e.getMessage());
e.printStackTrace();
}
}
public static void sendDataToCongServer(String data){
try {
System.out.println("CONGESTION: "+data);
synchronized(Main.class){
if(congConnector!=null && congConnector.connected==true){
congConnector.send(data, false, false, 1);
}else{
initializeCongServer();
}
}
} catch (Exception ex) {
congestionDownStartTime = Calendar.getInstance();
logWrapper1.log(Level.DEBUG, "CONGESTION DOWN: "+data);
logWrapper1.log(Level.DEBUG, ex.getMessage());
}
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class Connector {
String host = null;
int port = 0;
int index = 0;
long reconnectTime = 0;
Socket sock = null;
boolean connected = false;
InputStream inputStream = null;
OutputStream outputStream = null;
BufferedReader bufferedReader = null;
DataOutputStream dataOutputStream = null;
public Connector(String host, int port, int index, long reconnectTime) throws Exception {
this.host = host;
this.port = port;
this.index = index;
this.reconnectTime = reconnectTime;
}
public synchronized Socket reconnect() throws Exception {
sock = new Socket(host, port);
inputStream = sock.getInputStream();
outputStream = sock.getOutputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
dataOutputStream = new DataOutputStream(outputStream);
connected = true;
return sock;
}
public void close() {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ex) {
//Logger.getLogger(Connector.class.getName()).log(Level.SEVERE, null, ex);
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException ex) {
//Logger.getLogger(Connector.class.getName()).log(Level.SEVERE, null, ex);
}
}
private synchronized void notifyWait() {
connected = false;
}
public synchronized void connect() throws Exception {
reconnect();
}
public void send(String str, boolean appendLine, boolean bindResult, int MedReadTimeOut) throws Exception {
String result = null;
if (connected == true) {
try {
byte[] b = null;
if (appendLine == true) {
b = (str + "\r\n").getBytes();
} else {
b = str.getBytes();
}
dataOutputStream.write(b, 0, b.length);
dataOutputStream.flush();
} catch (IOException ex) {
notifyWait();
connected = false;
throw new Exception(ex);
}
if (bindResult == true) {
try {
sock.setSoTimeout(MedReadTimeOut);
result = bufferedReader.readLine();
}
catch (SocketTimeoutException sockEx) {
String debugInfo = "TIMEOUT= "+MedReadTimeOut+".MEDIATION PORT CLOSED " + sock.getPort();
System.out.println(debugInfo);
}
catch (IOException ex) {
//Logger.getLogger(Connector.class.getName()).log(Level.SEVERE, null, ex);
notifyWait();
throw new Exception(ex);
}
}
} else {
throw new Exception("Congestion Socket Closed.");
}
}
}
A connection timeout won't help since it defines the maximum allowable time to initiate a connection. If anything, you might want to try setSoTimeout() instead.
But generally speaking, catching such a situation using socket timeouts isn't optimal, as the socket won't time out for as long as some information arrives once in a while, even it's a single byte at a time.
For a more robust solution, I suggest solving the problem at the application level, not the socket level. Maybe use a moving average to check the amount of data received/sent through the troublesome socket within a given timeframe (e.g. last 5 minutes), then reconnect if the average drops below a predefined threshold.
I'm writing a HTTP proxy server using sockets, now the program is receiving the request successfully but I'm not able to get it back again to the browser...
import java.io.*;
import java.net.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
public class Server {
public void startServer() {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
#SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(80);
while (true) {
Socket clientSocket = serverSocket.accept();
clientProcessingPool.submit(new ClientTask(clientSocket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private Socket clientSocket;
private ClientTask(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
// Read request
InputStream incommingIS = clientSocket.getInputStream();
byte[] b = new byte[8196];
int len = incommingIS.read(b);
if (len > 0) {
System.out.println("REQUEST"
+ System.getProperty("line.separator") + "-------");
System.out.println(new String(b, 0, len));
// Write request
Socket socket = new Socket("localhost", 80);
OutputStream outgoingOS = socket.getOutputStream();
outgoingOS.write(b, 0, len);
// Copy response
OutputStream incommingOS = clientSocket.getOutputStream();
InputStream outgoingIS = socket.getInputStream();
for (int length; (length = outgoingIS.read(b)) != -1;) {
incommingOS.write(b, 0, length);
}
incommingOS.close();
outgoingIS.close();
outgoingOS.close();
incommingIS.close();
socket.close();
} else {
incommingIS.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
What I'm doing wrong? Anyone could help me on this?
Thanks!
You're assuming you got the entire request in a single read, instead of using a loop like your response loop.
You're also assuming that it is terminated by an end of stream, which means the client must have done a shutdownOutput(), which doesn't happen in most protocols.
In general this isn't the correct technique for writing a proxy. You need to start two threads per client, to copy data in both directions simultaneously, and defer closing the socket until you've read EOS from both directions.