Java, local TCP server accepting HTTP requests from a browser - java

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

Related

A socket with c server over java socket

My assignment requiers me to write an server in c but client in java. I need to send some integer to my client as instructions. They can connected smoothly but my java client cannot Receive the integer send from c server. there is only two possibilities: my c server did not send the Number out OR my client does not Receive the integer correctly. The c server is able to loop as I type in since the printf and scanf is executed while nothing happends on the client side.
I am stuck here, any help will be appreciate!
=========================================================================
UPDATE:
I correct the main class in java where the class name of the client into dotClient, and my client was able to conncected and read the inputs from the server.
I have try to send an 'int' directly in the server side, but When the client(java) use DataInputStream.ReadInt(), it returns a randomly big number as if the size of int in c and size of int in java is not matched.When I use a c client to do the same job, it works normal. So there is Hidden Problem for using dataInputStream directly with a c server, as I tried readShort() and ReadLong() as well.
As suggested, I use bufferReader.
And send string in server side, and perse it into int in client.
it works.
hère is my updated c code
#define PORT 55555
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024];
int returnSend = 0;
// Creating socket file descriptor
if (
(server_fd = socket(AF_INET, SOCK_STREAM, 0))
== 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
printf("%s\n", "Socket created!");
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET,
SO_REUSEPORT, &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
printf("Socket attached!\n");
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd,
(struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("socket binded!\n");
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("socket listened!\n");
if ((new_socket = accept(server_fd,
(struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}// Socket formulated !
do{
fgets(buffer, sizeof(buffer), stdin);
returnSend = write(new_socket , buffer , strlen(buffer));
printf("Sending: %sReturn returnSend: %d.\n", buffer,returnSend);
} while (1);
return 0;
}
hère is my updated java client
import java.net.*;
import java.io.*;
public class dotClient
{
// initialize socket and input output streams
private Socket echoSocket= null;
private BufferedReader input = null;
// constructor to put ip address and port
public dotClient(String address, int port)
{
// establish a connection
try
{
echoSocket = new Socket(address, port);
System.out.println("Connected");
input =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
}
catch(UnknownHostException u)
{
System.out.println("exception 1: "+u);
}
catch(IOException i)
{
System.out.println("exception 2: "+i);
}
int number = 0;
String line = "";
// keep reading until read neagaive integer
try
{
while ((line = input.readLine()) != null)
{
number = Integer.parseInt(line);
System.out.println("String is :"+line);
System.out.println("number is :"+number);
}
}
catch(IOException i)
{
System.out.println("Exception 3: "+i);
}
// close the connection
try
{
input.close();
out.close();
echoSocket.close();
System.out.println("Connection closed!");
}
catch(IOException i)
{
System.out.println("Exception 4: "+i);
}
}
public static void main(String args[])
{
dotClient client = new dotClient("192.168.0.3", 55555);
}
}
In your main method you are creating a Client instance but your class is called dotClient. You might want to ensure you are creating an instance of your class dotClient. Otherwise I agree with the previous comments and would suggest BufferedReader and BufferedWriter/PrintWriter for the IO.
Do any of your try blocks catch an exception on the client? Check the return value of send(new_socket , &number , size(number) , 0 ); on the server to make sure the data was actually sent for more info checkout http://man7.org/linux/man-pages/man2/send.2.html.

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.

Proxy input/output stream issues in 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)

Categories

Resources