Proxy input/output stream issues in Java - java

I've been trying for a while a few different methods to get my custom proxy to work, and the only way I've been able to so far is through use of Apache's HttpClient. However, for the sake of knowing, I was wondering why I'm having trouble with my own proxy handle implementation below:
public void processProxyRequest (Socket client, String request) throws Exception {
if ( !request.equals("") ) {
String[] requestHeaders = request.split("\\r\\n");
Pattern p = Pattern.compile("([A-Z]*)\\s*([^:\\/]*):\\/\\/([^\\s]*)\\s*(?:HTTP.*)");
Matcher m = p.matcher(requestHeaders[0]);
if ( m.matches() ) {
String method = m.group(1).toUpperCase();
String proto = m.group(2).toLowerCase();
String[] requestInfo = m.group(3).split("\\/", 2);
String host = requestInfo[0];
host = ( host.split("\\.").length < 3 ) ? "www." + host : host;
String page = "/";
if ( requestInfo.length == 2 && !requestInfo[1].equals("") ) {
page += requestInfo[1];
}
int remotePort = 80;
if ( proto.equals("https") ) {
remotePort = 443;
}
else if ( proto.equals("ftp") ) {
remotePort = 21;
}
this.sendAndReceive(client, request, host, remotePort);
}
}
}
public void sendAndReceive (Socket client, String request, String host, int port) throws Exception {
Socket target = new Socket(host, port);
System.out.println("Connected to server");
ByteArrayInputStream inStream = new ByteArrayInputStream(request.getBytes());
this.inToOut(inStream, target.getOutputStream());
System.out.println("Sent");
this.inToOut(target.getInputStream(), client.getOutputStream());
System.out.println("Received");
target.close();
}
public void inToOut (InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
System.out.println("reading");
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
In a nutshell (and disregarding my request header parsing flaws), the above code compiles and runs, however, the inToOut() method seems to struggle a bit and lock up during the input.read(), and I'm not too sure why. I do know as a fact that the original socket I'm passing in is valid and opened without errors. Additionally, the System.out in the inToOut() function does print "reading" but never gets past the read() portion.
Thank you for any suggestions!

This is no way to write a proxy. In the case of HTTP you only have to process the first line, that tells you the target host. Everything else is just copying bytes back and forth, subject to a couple of minor refinements such as reporting upstream connect errors correctly snd handling shutdowns properly. The FTP case is trickier and should be handled completely separately, but again once you get past the connect phase it's just copying bytes around. The less effortmyou make to understand the protocol the simpler and better it gets.

In your sendAndReceive function, perhaps try using DataInputStream and DataOutputStream
public void sendAndReceive (Socket client, String request, String host, int port) throws Exception {
Socket target = new Socket(host, port);
System.out.println("Connected to server");
this.inToOut(new DataInputStream(client.getInputStream()), new DataOutputStream(target.getOutputStream()));
System.out.println("Sent");
this.inToOut(new DataInputStream(target.getInputStream()), new DataOutputStream(client.getOutputStream()));
System.out.println("Received");
target.close();
}
The problem doesn't seem to be in the inToOut function - I've tried using inToOut() and it works fine (it actually helped me fix a problem I was having with something similar - Thanks)

Related

Java C# socket communication

I am working on a Java-C# socket communication and I would like to send the coordinates of a C# object to java periodically. The problem is that the java client Stream only reads the coordinates (20 mile long buffer) when I close the connection. I would like the connection to remain open and the coordinates to update without having to open and close this connection all the time.
P.S. This was working but I somehow deleted the previous C# script I was using now I cannot figure it out.
The Java LocationRequester, will connect to the server and then periodically call getline() and pass it to coordinates. The connect part works and getline() only completes if I close the connection, otherwise it hangs. When I close the connection I get a super long row of coordinates.
public Socket clientSocket;
BufferedReader inputBuff;
String hostName;
int hostPort;
public LocationListener(String host, int port) {
hostName = host;
hostPort = port;
}
public void connect()
{
try {
clientSocket = new Socket(hostName, hostPort);
System.out.println("Connected to"+clientSocket.toString());
InputStream input = clientSocket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
inputBuff = new BufferedReader(reader);
String str;
}
catch(IOException e)
{
e.printStackTrace();
}
}
public String getLine() {
String rstring = "";
try {
rstring = inputBuff.readLine();
System.out.println(rstring);
}
catch(IOException e) {
e.printStackTrace();
}
return rstring;
}
C# code seems to be where the problem is.
private void Start()
{
IPAddress address = IPAddress.Any;
server = new TcpListener(address, 9999);
server.Start();
client = server.AcceptTcpClient();
StartCoroutine(SendCords());
}
private IEnumerator SendCords()
{
while (true)
{
yield return new WaitForSeconds(0.5f);
NetworkStream stream = client.GetStream();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(transform.position.ToString());
stream.Write(msg, 0, msg.Length);
stream.Flush();
// client.Close();
Debug.Log("Sending "+transform.position);
}
}
The java code is reading a line. That means it will block until it gets a line feed character '\n'. And I guess your C# code is not adding a line feed. In my opinion, if you add a line feed character in the end, to your C# message payload, the java code should get the information and come out of the wait. Give a try.
#ferosekhanj has already said very well. I add that the function ofBufferedReader.readLine() will stop reading at'\n' and also at EOF. This is why when your C# program close the Socket, and your java program will receive a super long row of coordinates.

Java's equivalence to the Python's recv() network function

I have a client implemented in Java, and a server implemented in client.
The client sends a message (string) such as "nesting:1:2" to the server, the server decodes the meaning of the input to create and send back binary data to the client.
This is the Python server code.
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.data has the data
(name, index, n) = self.data.split(":")
m = int(n)
i = int(index)
size = sizes.sizes[name][i]
# creates the binary data
bf = [0x41] * size * m
key = ''.join(chr(x) for x in bf)
self.request.send(key) #
if __name__ == "__main__":
HOST = socket.gethostbyname(socket.gethostname())
PORT = 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
The client Python code is as follows:
af, socktype, proto. canonname, sa = res
s = socket(af, socktype, proto)
s.connect(sa)
s.sendall('nostring:1:5')
data = s.recv(1024)
s.close()
I tried to find the equivalent to the s.recv() method, I found read() method. So, I tried this method where byte[] buffer = new byte[157*10]; is declared outside the method.
public byte[] receive() throws IOException {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVER_PORT);
in = socket.getInputStream();
in.read(buffer);
in.close();
socket.close();
return this.buffer;
}
The issue is that the in.read(buffer) never returns until the server disconnects.
What might be wrong? This is the full source code for the client.
I didn't try, but to my mind, the socket should not be closed between the send and receive action, one socket means one connection to the server.
The python server will most likely try to answer on the given socket, which will be closed, and the java client will wait on another.
Try something like that: creating the socket in the constructor and closing it at the end of the receive (if you are sure you might call the send/receive pair only one time)
import java.net.*;
import java.io.*;
class GpcSocket {
private Socket socket;
// default value
private int SERVER_PORT = 9999;
private String SERVER_IP = "192.168.3.100";
OutputStream out = null;
InputStream in = null;
byte[] buffer = new byte[157*10];
public GpcSocket(String serverIP, int serverPort) {
this.SERVER_PORT = serverPort;
this.SERVER_IP = serverIP;
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVER_PORT);
}
public int send(byte[] str) throws IOException {
out = socket.getOutputStream();
out.write(str);
out.flush();
// out.close();
return str.length;
}
public byte[] receive() throws IOException {
in = socket.getInputStream();
in.read(buffer);
in.close();
socket.close()
return this.buffer;
}
}

performance issue. The Speed is too slow while reading bytes from socket using java

these days I'm confused about the Tcp performance while using java socket. In fact the java code is very simple. details as below:
server open a port and begin to listen.
client request and after connect to server, client begin to write to socket.
after server got the request, it will open a new thread to handle this connection. (this connection is a long connection which will not time out).
the server will keep reading until it got the end separator, then give a response to the client and continue to keep reading again.
after client get the response, it will send another request again.
I find if the client write the whole message (including the end separator) one time, the communication speed is good satisfactorily, the speed can reach to 50000 messages per minute. How ever, if the client write the bytes to socket in separated times, the speed cut down quickly, just almost 1400 messages per minute, it is 1/40 times compared with the original speed. I'm quite confused about it. Any one could give me a hand? Any comments is appreciated!
my simulated server side is as below:
public class ServerForHelp {
final static int BUFSIZE = 10240;
Socket socket;
String delimiter = "" + (char) 28 + (char) 13;
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9200);
System.out.println("begin to accept...");
while (true) {
Socket s = ss.accept();
Thread t = new Thread(new SocketThread1(s));
t.start();
}
}
public String readUntilDelimiter() throws Exception {
StringBuffer stringBuf = new StringBuffer();
InputStream stream = socket.getInputStream();
InputStreamReader reader = null;
reader = new InputStreamReader(stream);
char[] buf = new char[BUFSIZE];
while (true) {
int n = -1;
n = reader.read(buf, 0, BUFSIZE);
if (n == -1) {
return null; // it means the client has closed the connection, so return null.
} else if (n == 0) {
continue; // continue to read the data until got the delimiter from the socket.
}
stringBuf.append(buf, 0, n);
String s = stringBuf.toString();
int delimPos = s.indexOf(delimiter);
if (delimPos >= 0) {
// found the delimiter; return prefix of s up to separator and
// To make the thing simple, I have discarded the content after the delimiter.
String result = s.substring(0, delimPos);
sendTheResponse(socket);
return result;
}
}
}
private void sendTheResponse(Socket socket) throws IOException {
Writer writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Hi, From server response");
writer.flush();
}
}
class SocketThread1 implements Runnable {
Socket socket;
public SocketThread1(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
ServerForHelp server = new ServerForHelp();
server.socket = socket;
while (true) {
try {
if (server.readUntilDelimiter() == null) // it means that the client has closed the connection, exist
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
It is a normal socket programming.
and the following is my client side:
public void execute() throws Exception{
int msgCnt = 0;
Socket socket = null;
byte[] bufBytes = new byte[512];
long start = 0;
final char START_MESSAGE = 0x0B;
final char END_MESSAGE = 0x1C;
final char END_OF_RECORD = 0x0D;//\r
String MESSAGE = "HELLO, TEST";
socket = new Socket("192.168.81.39", 9200);
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
while (System.currentTimeMillis() - start < 60000)
{
// If you send the total message at one time, the speed will be improved significantly
// FORMAT 1
StringBuffer buf = new StringBuffer();
buf.append(START_MESSAGE);
buf.append(MESSAGE);
buf.append(END_MESSAGE);
buf.append(END_OF_RECORD);
os.write(buf.toString().getBytes());
// FORMAT 1 END
//FORMAT 2
// os.write(START_MESSAGE);
// os.write(MESSAGES[port].getBytes());
// os.write(END_MESSAGE);
// os.write(END_OF_RECORD);
//FORMAT 2 END
os.flush();
is.read(bufBytes);
msgCnt++;
System.out.println(msgCnt);
}
System.out.println( msgCnt + " messages per minute");
}
If I use the "FORMAT 1", to send the message, the speed could reach to 50000 messages per minute, but If use "FORMAT 2", the speed is down to 1400 messages per minute. Who is clear about the reason?
I'm trying to describe as detail as I can and any help will be appreciated very much.
Multiple very short writes to a socket in rapid succession followed by a read can trigger a bad interaction between Nagle's algorithm and TCP delayed acknowledgment; even if you disable Nagle's algorithm, you'll cause an entire packet to be sent per individual write call (with 40+ bytes of overhead, whether the write is one byte or a thousand).
Wrapping a BufferedOutputStream around the socket's output stream should give you performance similar to "FORMAT 1" (precisely because it holds things in a byte array until it fills or is flushed).
As John Nagle explained on Slashdot:
The user-level solution is to avoid write-write-read sequences on sockets. write-read-write-read is fine. write-write-write is fine. But write-write-read is a killer. So, if you can, buffer up your little writes to TCP and send them all at once.

How to save a file sent from a http response without including the header

I am trying to write a program in java which is able to download a file from a URL. I want to do this without using an URLConnection, instead i am just using TCP sockets. I have succeeded in sending the GET request and picking up the server's response, but i can't seem to get my head around saving the file from the response without the http-header(just the file).
import java.net.*;
import java.io.*;
public class DownloadClient {
public static void main(String[] args) {
try {
if (args.length != 3) {
System.out.println(
"Use: java DownloadClient <host> <port> <filename/path>"
);
} else {
// Sorting out arguments from the args array
String host;
int port;
String filename;
if (args[0].charAt(args[0].length()-1) == '/') {
host = args[0].substring(0,args[0].length()-1);
} else {
host = args[0];
}
port = Integer.parseInt(args[1]);
if (args[2].charAt(0) == '/') {
filename = args[2];
} else {
filename = "/"+args[2];
}
Socket con = new Socket(args[0], Integer.parseInt(args[1]));
// GET request
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(con.getOutputStream(), "UTF8")
);
out.write("GET "+filename+" HTTP/1.1\r\n");
out.write("Host: "+host+"\r\n");
out.write("User-Agent: Java DownloadClient\r\n\r\n");
out.flush();
InputStream in = con.getInputStream();
BufferedReader =
OutputStream outputFile = new FileOutputStream(
filename.substring(filename.lastIndexOf('/')+1)
);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while((bytesRead = in.read(buffer)) > 0) {
outputFile.write(buffer, 0, bytesRead);
buffer = new byte[1024];
}
outputFile.close();
in.close();
con.close();
}
} catch (IOException e) {
System.err.println(e);
}
}
}
I guess that i should somehow look for \r\n\r\n as it indicates the empty line just before the content begins. So far this program creates a file which contains all of the http-response.
The recommended way to do this is to NOT try to talk to a web server using a plain Socket. Use one of the existing client-side HTTP stack; e.g. the standard HttpUrlConnection stack or the Apache HttpClient stack.
If you insist on talking using a plain socket, then it is up to you to process / deal with the "Header" lines in any response ... and everything else ... in accordance with the HTTP specification.
I guess that I should somehow look for \r\n\r\n as it indicates the empty line just before the content begins.
Yup ...
And you also potentially need to deal with the server sending a compressed response, an response using an unexpected character set, a 3xx redirect, and so on.

Java, local TCP server accepting HTTP requests from a browser

I am trying to "Write a Java program that is a TCP server that returns a HTTP response to a browser that displays the client’s IP address and the number of times it has connected to the server"
Currently what I think is happening. I am creating a server and listening to the port (input as a argument) for a request, then filling a byte array and converting that array to a string. I wish then to just see the request at this point.
My problem is if I do try to connect to this server by going to my web-browser and typing "localhost:1235" my browser just keeps saying "connecting to ..." and my program does nothing it just sits and waits.
How might I go about fixing/and implemented the rest of this? What could my current problem be?
So far here is my code
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPHTTP
{
private static final int MAXFILELEN = 4096000;
static byte[] request = new byte[MAXFILELEN];
static String[] log;
public static void main (String args[])
{
if (args.length != 1)
throw new IllegalArgumentException( "Parameter(s): <Port>");
int port = Integer.parseInt(args[0]);
ServerSocket socket = null;
Socket sock = null;
try
{
socket = new ServerSocket(port);
}
catch (IOException e)
{
return;
}
for (;;)
{
try
{
sock = socket.accept();
InputStream is = sock.getInputStream();
int offset = 0;
int len = 0;
while ((len = is.read(request, offset, MAXFILELEN - offset)) >= 0)
{
offset += len;
}
String s = new String(request);
System.out.println(s);
// Add the users IP to the log
String from = "From: ";
int loglen = log.length;
int indexOfSenderIP = s.indexOf(from, 0);
indexOfSenderIP += from.length();
int indexOfNewline = s.indexOf("\n", indexOfSenderIP);
String sendersIP = s.substring(indexOfSenderIP, indexOfNewline);
log[loglen] = sendersIP;
//Find out how many times the sender IP appears in the log
int timesVisited = 0;
for(int i = 0; i < log.length; i++)
if(log[i].endsWith(sendersIP))
timesVisited++;
// Construct the HTTP response message
String httpResponse = "";
OutputStream os = sock.getOutputStream();
os.write(httpResponse.getBytes());
os.close();
is.close();
sock.close();
}
catch (IOException e)
{
break;
}
}
}
}
Consider adding a Content-Length header to specify the size of your response so the browser knows how much to read.
the reason why your program freezes is that it waits for the client to close connection (read returns a value that's <0 after an eof).
you should read until you receive a double [cr][lf] from the client, that's what marks the ending of the http header
String httpResponse = "";
That's not a valid HTTP response. Your browser is waiting for a proper response. Send one.
from what i see, you closed the socket before answering the client's request
also, i tested your code, and that while cycle never ends

Categories

Resources