Hi i have a server socket that listens for requests from a client socket and my code doesnt seem to retrieve the data from its inputstream on data sent from the client socket.
below is the server socket code that listens for connections and handles the requests
public void startlistener() {
serverSocket = new ServerSocket(PORT);
listening = true;
thread.start();
Log.print(TAG, "startlistener");
}
public void stopListener() {
thread.stop();
listening = false;
Log.print(TAG, "stopListener");
}
public void run() {
while (listening) {
try {
Log.d(TAG, "inside server listener loop");
Socket accept = serverSocket.accept();
String data = getData(accept);
httpHandler.handleRequest(data, accept);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getData(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
Log.print(TAG, "getData");
int c = 0;
StringBuffer buffer = new StringBuffer();
//goes as far as here and then freezes/doesnt retrieve anything from the input stream
while ((c = in.read()) != -1) {
buffer.append((char) c);
}
return buffer.toString();
}
Here is my testcase
private static final String HTTP_REQUEST = "HTTP/1.0 408 Request Time-out"
+ newLine + "Cache-Control: no-cache" + newLine
+ "Connection: close" + newLine + "Content-Type: text/html";
public void testSocketConnection() {
try {
httpProxy = new HttpProxy(testHttpHandler);
httpProxy.startlistener();
testSocket = new Socket("localhost", HttpProxy.PORT);
OutputStream outputStream = testSocket.getOutputStream();
InputStream inputStream = testSocket.getInputStream();
outputStream.write(HTTP_REQUEST.getBytes());
} catch (UnknownHostException e) {
httpProxy.stopListener();
e.printStackTrace();
fail(e.toString());
} catch (IOException e) {
httpProxy.stopListener();
e.printStackTrace();
fail(e.toString());
}
}
Your client doesn't close the socket. Your server reads the socket until EOS, which will never arrive as your client doesn't close the socket.
NB don't handle client I/O in the accepting thread. Start a separate thread.
Related
I am developing a proxy server based on java. For simple http request, proxy server is working. But for HTTPS Connection, connection gets timed out. Here are the steps I did. I first read one line from input stream and created a socket connecting Server. After that I gave 200 Status to client. After that I asynchronously read and write between Client Socket and Server socket. But currently this isn't working and connection gets timedout and I couldn't debug the problem.
public class ProxyServer extends Thread {
private String host;
private int port;
private ServerSocket serverSocket;
private InputStream proxyToClientIP;
private OutputStream proxyToClientOP;
private InputStream proxyToServerIP;
private OutputStream proxyToServerOP;
private Socket socket;
private Socket socketFromProxyServer;
ProxyServer(ServerSocket serverSocket, Socket socket) {
this.serverSocket = serverSocket;
this.socket = socket;
this.start();
}
public void run() {
processInputRequest();
}
public void processInputRequest() {
try {
proxyToClientIP = socket.getInputStream();
proxyToClientOP = socket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(proxyToClientIP));
String hostDetails = reader.readLine();
System.out.println(hostDetails);
boolean isConnect = false;
//Need to parse request and find req type as GET or CONNECT
//As of now we assume it to be Connect request
if (!isConnect) {
processGetRequest();
} else {
processConnectRequest();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void processConnectRequest() {
//Need to get host name from request. Currently Hardcoded for developing purpose
host = "harish-4072";
port = 8383;
try {
socketFromProxyServer = new Socket(host, port);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(proxyToClientOP));
writer.write("HTTP/1.1 200 Connection established\r\n" + "\r\n");
writer.flush();
proxyToServerOP = socketFromProxyServer.getOutputStream();
proxyToServerIP = socketFromProxyServer.getInputStream();
proxyRequest();
} catch (IOException ex) {
System.out.println(ex);
}
}
public void proxyRequest() {
try {
new Thread() {
#Override
public void run() {
try {
byte[] read = new byte[1024];
int in;
System.out.println("Reading");
while ((in = proxyToClientIP.read(read)) != -1) {
proxyToServerOP.write(read, 0, in);
proxyToServerOP.flush();
}
} catch (SocketException e) {
System.out.println(e);
} catch (IOException ex) {
}
}
}.start();
byte[] reply = new byte[1024];
int out;
System.out.println("Writing");
while ((out = proxyToServerIP.read(reply)) != -1) {
proxyToClientOP.write(reply, 0, out);
proxyToClientOP.flush();
}
} catch (IOException ex) {
}
public void processGetRequest() {
//
}
}
I first read one line from input stream and created a socket connecting Server. ... After that I asynchronously read and write between Client Socket and Server socket.
The problem is that you are reading only a single line while you would need to read the full HTTP request header from the client, i.e. everything up to the end of the request header (\r\n\r\n).
Because you fail to do so the unread parts of the HTTP request are forwarded to the server. But the server is expecting the start of the TLS handshake and these data confuse the server. This might result in hanging or aborting, depending on the content of the data and one the kind of server.
I need a Java Proxy Server that let me connect to [localhost:9318] through [localhost:9418], like:
[my browser] -> [localhost:9418] -> [localhost:9318]
for that I tried this code:
http://www.java2s.com/Code/Java/Network-Protocol/Asimpleproxyserver.htm
package com.example.proxyserver;
import java.io.*;
import java.net.*;
public class App {
public static void main(String[] args) throws IOException {
try {
String host = "localhost";
int remoteport = 9318;
int localport = 9418;
// Print a start-up message
System.out.println("Starting proxy for " + host + ":" + remoteport + " on port " + localport);
// And start running the server
runServer(host, remoteport, localport); // never returns
} catch (Exception e) {
System.err.println(e);
}
}
/**
* runs a single-threaded proxy server on the specified local port. It never
* returns.
*/
public static void runServer(String host, int remoteport, int localport) throws IOException {
// Create a ServerSocket to listen for connections with
ServerSocket ss = new ServerSocket(localport);
final byte[] request = new byte[1024];
byte[] reply = new byte[4096];
while (true) {
Socket client = null, server = null;
try {
// Wait for a connection on the local port
client = ss.accept();
final InputStream streamFromClient = client.getInputStream();
final OutputStream streamToClient = client.getOutputStream();
// Make a connection to the real server.
// If we cannot connect to the server, send an error to the
// client, disconnect, and continue waiting for connections.
try {
server = new Socket(host, remoteport);
} catch (IOException e) {
PrintWriter out = new PrintWriter(streamToClient);
out.print("Proxy server cannot connect to " + host + ":" + remoteport + ":\n" + e + "\n");
out.flush();
client.close();
continue;
}
// Get server streams.
final InputStream streamFromServer = server.getInputStream();
final OutputStream streamToServer = server.getOutputStream();
// a thread to read the client's requests and pass them
// to the server. A separate thread for asynchronous.
Thread t = new Thread() {
public void run() {
int bytesRead;
try {
while ((bytesRead = streamFromClient.read(request)) != -1) {
streamToServer.write(request, 0, bytesRead);
streamToServer.flush();
}
} catch (IOException e) {
}
// the client closed the connection to us, so close our
// connection to the server.
try {
streamToServer.close();
} catch (IOException e) {
}
}
};
// Start the client-to-server request thread running
t.start();
// Read the server's responses
// and pass them back to the client.
int bytesRead;
try {
while ((bytesRead = streamFromServer.read(reply)) != -1) {
streamToClient.write(reply, 0, bytesRead);
streamToClient.flush();
}
} catch (IOException e) {
}
// The server closed its connection to us, so we close our
// connection to our client.
streamToClient.close();
} catch (IOException e) {
System.err.println(e);
} finally {
try {
if (server != null)
server.close();
if (client != null)
client.close();
}
catch (IOException e) {
}
}
}
}
}
This code works but it is very slow.
Do you know what do I need to do in order to increase the speed?
Or maybe do you know about another Java Proxy Server code that be fast?
Thanks!
there is a server that is considered to server multiple clients at the same time.
So when clients connects, he is added to clients array. And when server gets the message, it is sent to all the clients.
It works perfectly when one client is connected, but when I have 2 clients at the same time, the message is sent only once, it doesn't work anymore after that. What's the problem?
Server
static DataInputStream inputStream;
static DataOutputStream outputStream;
static ServerSocket serverSocket;
static final int PORT = 3003;
static Socket someClient;
static List<Socket> clients = new ArrayList<>();
public Server()
{
start();
}
public static void main(String[] args) throws IOException
{
try{
serverSocket = new ServerSocket(PORT);
print("Server started on " + serverSocket.getInetAddress().getHostAddress());
while (true)
{
someClient = serverSocket.accept();
new Server();
}
} catch (Exception e){
e.printStackTrace();
}
}
#Override
public void run()
{
try{
clients.add(someClient);
print("Connected from " + someClient.getInetAddress().getHostAddress());
InputStream sin = someClient.getInputStream();
OutputStream sout = someClient.getOutputStream();
inputStream = new DataInputStream(sin);
outputStream = new DataOutputStream(sout);
String message;
while (true)
{
message = inputStream.readUTF();
print(message);
for (int i = 0; i < clients.size(); i++)
{
Socket client = clients.get(i);
OutputStream os = client.getOutputStream();
DataOutputStream oss = new DataOutputStream(os);
oss.writeUTF(message);
}
}
} catch (Exception e){
e.printStackTrace();
}
}
Client
socket = new Socket("0.0.0.0", 3003);
InputStream sin = socket.getInputStream();
OutputStream sout = socket.getOutputStream();
inputStream = new DataInputStream(sin);
outputStream = new DataOutputStream(sout);
sendButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(key != null && key.length() == 16)
{
Date date = new Date();
String msg = ">> " + nickname + ": " + messageField.getText()+" | " + date.getHours()+":"+date.getMinutes()+"\n";
try {
outputStream.writeUTF(Encrypt.AESEncrypt(key, msg));
} catch (IOException e1) {
e1.printStackTrace();
}
messageField.setText("");
}
else if(key == null)
JOptionPane.showMessageDialog(J_Frame, "Your key field is empty");
else if(key.length() != 16)
JOptionPane.showMessageDialog(J_Frame, "Key's length should be 16 symbols");
}
});
while (true)
{
String message;
message = inputStream.readUTF();
append("\n" + Encrypt.AESDecrypt(key, message));
}
} catch (Exception e1) {
clear();
append(">> Unable to connect to the server.");
hideButtons();
}
Every time a client connects to your server, it replaces the previous connection:
while (true)
{
someClient = serverSocket.accept();
...
}
someClient is static:
static Socket someClient;
which means it is shared by all threads.
Also, access to it is not synchronized in any way, which means changes to its value are not guaranteed to be visible to other threads.
As Peter Lawrey pointed out in the comments, the streams also need to be non-static:
static DataInputStream inputStream;
static DataOutputStream outputStream;
actually, the fact that you are always reading from the "latest" inputStream may be the main cause of the behavior you are describing.
outputStream seems to be unused, so it might be best to remove it.
In addition to that, OutputStreams may need to be flushed in order to actually send data.
The client send a message, then the server receives the message and response the message. I don't know why the client can not read the response. If I remove the read part in client, the server can get the message. However for the following code, nothing work. Also I tried the flush(), it still doesn't work.
For client
public void run() {
try (Socket echoSocket = new Socket(HOSTNAME, Integer.parseInt(PORTNUMBER));
DataOutputStream dOut = new DataOutputStream(echoSocket.getOutputStream());
DataInputStream dIn = new DataInputStream(echoSocket.getInputStream());
) {
while (true) {
command = UI.commandQueue.take()
dOut.writeInt(Message.toByteArray(command).length);
dOut.write(Message.toByteArray(command));
int length;
while((length = dIn.readInt()) != 0) {
if (length > 0){
byte[] messagebyte = new byte[length];
dIn.readFully(messagebyte, 0, messagebyte.length);
try {
msg = Message.fromByteArray(messagebyte);
testDisplay(msg);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
testDisplay(msg);
}
}
}
}catch (UnknownHostException e) {
UI.display("Don't know about host " + HOSTNAME);
} catch (IOException e) {
UI.display("Couldn't get I/O for the connection to " + HOSTNAME);
}
}
For server
public void run() {
try (ServerSocket serverSocket = new ServerSocket(Integer.parseInt(PORT_NUMBER));
Socket clientSocket = serverSocket.accept();
DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream dIn = new DataInputStream(clientSocket.getInputStream());) {
int length;
while ((length = dIn.readInt()) != 0) {
if (length > 0) {
byte[] messagebyte = new byte[length];
dIn.readFully(messagebyte, 0, messagebyte.length); // read the
// message
Message msg;
try {
msg = Message.fromByteArray(messagebyte);
testDisplay(msg);
dOut.writeInt(Message.toByteArray(msg).length);
dOut.write(Message.toByteArray(msg));
UI.display("ack sent");
} catch (Exception e) {
// TODO Auto-generated catch block
UI.display(e.getMessage());
}
}
}
} catch (IOException e) {
UI.display(
"Exception caught when trying to listen on port " + PORT_NUMBER + " or listening for a connection");
UI.display(e.getMessage());
}
}
Your server is echoing one response per request, but your client is trying to read more than one response per request, which it will never get, so it blocks.
I'm creating an update client via Sockets and I'm getting a Broken Pipe on the server side. The server accepts a client socket and responds to the same socket with either a message or a large byte array (~180MB). The error does not happen when testing locally (both client and server on the same machine) and it seems that it happens while sending the byte array. I'm not specifying a time out on the client socket and don't know why it is closing before reading the full response. Its my first time working with sockets and any help would be appreciated.
My Client Socket Code:
public static Response makeRequest(Request req) throws IOException {
Response response = null;
Socket echoSocket = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
echoSocket = new Socket(serverHost, 10008);
out = new ObjectOutputStream(echoSocket.getOutputStream());
in = new ObjectInputStream(
echoSocket.getInputStream());
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
out.writeObject(req);
try {
response = (Response)in.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
return response;
}
Response is just a POJO holding the response (string/byte[] and other data)
My Server Code (copied an example of Sun/Oracle site and added my code to it)
public class Server extends Thread {
private Socket clientSocket;
public Server(Socket clientSocket) {
this.clientSocket = clientSocket;
start();
}
public void run()
{
{
System.out.println ("New Communication Thread Started");
try {
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
Request request = null;
try {
request = (Request)in.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UpdateDAO dao = new UpdateDAO();
ClientDAO cdao = new ClientDAO();
Update update = null;
Client client = null;
Session s = HibernateUtil.currentSession();
Transaction t = s.beginTransaction();
if (request != null) {
client = cdao.getClient(request.getClientId());
LogItem log = new LogItem();
log.setClient(client);
log.setTimestamp(new Date());
log.setAction(request.getAction());
if (request.getResponse() != null) {
update = dao.getUpdate(request.getResponse().getUpdateId());
}
TaskContext ctx = new TaskContext(request, client, update, log);
System.out.println("Action: " + request.getAction().getDescription());
Task task = TaskFactory.getTask(request.getAction());
System.out.println(task.getClass().getName());
Response response = task.perform(ctx);
out.writeObject(response);
log.setClientTaskDescription(request.getMessage());
log.setUpdate(ctx.getUpdate());
dao.save(ctx.getLog());
if (ctx.getUpdate() != null) {
dao.update(ctx.getUpdate());
}
} else {
out.writeObject(new Response("what"));
}
t.commit();
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
System.exit(1);
}
}
}
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(10008);
System.out.println ("Connection Socket Created");
try {
while (true)
{
System.out.println ("Waiting for Connection");
new Server (serverSocket.accept());
}
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
}
catch (IOException e)
{
System.err.println("Could not listen on port: 10008.");
System.exit(1);
}
finally
{
try {
serverSocket.close();
}
catch (IOException e)
{
System.err.println("Could not close port: 10008.");
System.exit(1);
}
}
}
}
If the client is, in fact, running out of memory:
java -Xmx512m -jar <the jar>
or
java -Xmx512m com.foo.blah.YourClass
would increase the maximum heap for the client/server. Keep in mind you may have to increase the heap for both sides of the pipe since both sides would be reading all ~180mb into memory at runtime.