I'm creating my own server-software from scratch using this library.
Right now the client sends the server a Handshake packet, the server decodes it using a Handshake Codec and returns with a Response message encoded with a Response Codec, however I never get a Ping packet.
Here is my code for encoding the Response message to the server.
public class ResponseCodec implements Codec<ResponseMessage> {
#Override
public ResponseMessage decode(DataInputStream dataInputStream) {
String json = ByteUtilities.readUTF8(dataInputStream);
return new ResponseMessage(json);
}
#Override
public DataOutputStream encode(DataOutputStream dataOutputStream, ResponseMessage responseMessage) {
ByteArrayOutputStream packetArray = new ByteArrayOutputStream();
DataOutputStream packetStream = new DataOutputStream(packetArray);
ByteUtilities.writeVarInt(packetStream, 0x00);
ByteUtilities.writeUTF8(packetStream, responseMessage.getJson());
ByteUtilities.writeVarInt(dataOutputStream, packetArray.toByteArray().length);
try {
dataOutputStream.write(packetArray.toByteArray());
} catch (Exception e) {
e.printStackTrace();
}
return dataOutputStream;
}
}
And here is my connection listener:
server.setConnectionListener(new ConnectionListener() {
#Override
public void onConnect(Socket socket, DataInputStream dataInputStream) throws Exception {
//header
int packetSize = ByteUtilities.readVarInt(dataInputStream);
int packetId = ByteUtilities.readVarInt(dataInputStream);
// writing handlers
OutputStream outputStream = socket.getOutputStream();
DataOutputStream socketStream = new DataOutputStream(outputStream);
//identification
if(packetId == 0x00) {
// decode
HandshakeCodec codec = new HandshakeCodec();
HandshakeMessage message = codec.decode(dataInputStream);
if(!(message.getProtocolVersion() == 47)) {
System.out.println("Client " + message.getAddress() + ":" + message.getPort() + " seems to have a incompatible client.");
}
ResponseCodec responseCodec = new ResponseCodec();
StringBuilder text = new StringBuilder();
BufferedReader formatReader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("ResponseFormat.txt")));
String line = formatReader.readLine();
while (line != null) {
text.append(line);
text.append(System.lineSeparator());
line = formatReader.readLine();
}
String everything = text.toString();
String accountedWithVariables = everything
.replaceAll("MAX_PLAYERS", "" + maxPlayers)
.replaceAll("ONLINE_PLAYERS", "" + BasicServer.onlinePlayers)
.replaceAll("MOTD", motd);
ResponseMessage responseMessage = new ResponseMessage(accountedWithVariables);
responseCodec.encode(socketStream, responseMessage);
}
if(packetId == 0x01) {
long pingLong = dataInputStream.readLong();
PongCodec codec = new PongCodec();
PongMessage message = new PongMessage(pingLong);
codec.encode(socketStream, message);
}
}
#Override
public void onCaughtException(Exception e) {
System.out.println("Main thread has recieved a exception: " + e.getMessage());
e.printStackTrace();
}
});
Related
I am writing a web server from the scratch. There I need a Http codec which can decode a string request (buffer) to an Http object and encode http object into Sting (buffer).
I found three Codecs,
Apache Codecs (can't use this because this is tightly coupled with their server coding structure)
Netty Codes (can't use this because this is tightly coupled with their server coding structure)
JDrupes Codecs (Has some concurrency issues)
But non of these can be used for my purpose. Are there any other Codecs I can use?
class SimpleHttpsServer implements Runnable {
Thread process = new Thread(this);
private static int port = 3030;
private String returnMessage;
private ServerSocket ssocket;
/************************************************************************************/
SimpleHttpsServer() {
try {
ssocket = new ServerSocket(port);
System.out.println("port " + port + " Opend");
process.start();
} catch (IOException e) {
System.out.println("port " + port + " not opened due to " + e);
System.exit(1);
}
}
/**********************************************************************************/
public void run() {
if (ssocket == null)
return;
while (true) {
Socket csocket = null;
try {
csocket = ssocket.accept();
System.out.println("New Connection accepted");
} catch (IOException e) {
System.out.println("Accept failed: " + port + ", " + e);
System.exit(1);
}
try {
DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(csocket.getInputStream()));
PrintStream printStream = new PrintStream(new BufferedOutputStream(csocket.getOutputStream(), 1024),
false);
this.returnMessage = "";
InputStream inputStream = csocket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// code to read and print headers
String headerLine = null;
while ((headerLine = bufferedReader.readLine()).length() != 0) {
System.out.println(headerLine);
}
// code to read the post payload data
StringBuilder payload = new StringBuilder();
while (bufferedReader.ready()) {
payload.append((char) bufferedReader.read());
}
System.out.println("payload.toString().length() " + payload.toString().length());
if (payload.toString().length() != 1 || payload.toString().length() != 0) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(payload.toString());
// Handle here your string data and make responce
// returnMessage this can store your responce message
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + this.returnMessage;
printStream.write(httpResponse.getBytes("UTF-8"));
printStream.flush();
}else {
/*String httpResponse = "HTTP/1.1 200 OK\r\n\r\n";
outStream.write(httpResponse.getBytes("UTF-8"));
outStream.flush();*/
}
printStream.close();
dataInputStream.close();
// csocket.close();
System.out.println("client disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/************************************************************************************/
public static void main(String[] args) {
new SimpleHttpsServer();
}
}
may be this one is help you
This is the class containing the main() method:
public class MultithreadedProxyServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
int port = 10000; //default
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
//ignore me
System.out.println("gnore");
}
try {
serverSocket = new ServerSocket(port);
System.out.println("Started on: " + port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + args[0]);
System.exit(-1);
}
while (listening) {
new ProxyThread(serverSocket.accept()).start();
}
serverSocket.close();
}
}
And this is the ProxyThread class:
public class ProxyThread extends Thread {
private Socket socket = null;
private static final int BUFFER_SIZE = 32768;
public ProxyThread(Socket socket) {
super("ProxyThread");
this.socket = socket; //initialzed my parent before you initalize me
}
public void run() {
//get input from user
//send request to server
//get response from server
//send response to user
System.out.println("run");
try {
DataOutputStream out =
new DataOutputStream(socket.getOutputStream());
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String inputLine, outputLine;
int cnt = 0;
String urlToCall = "";
///////////////////////////////////
//begin get request from client
while ((inputLine = in.readLine()) != null) {
try {
StringTokenizer tok = new StringTokenizer(inputLine);
tok.nextToken();
} catch (Exception e) {
System.out.println("break");
break;
}
//parse the first line of the request to find the url
if (cnt == 0) {
String[] tokens = inputLine.split(" ");
urlToCall = tokens[1];
//can redirect this to output log
System.out.println("Request for : " + urlToCall);
}
cnt++;
}
//end get request from client
///////////////////////////////////
BufferedReader rd = null;
try {
//System.out.println("sending request
//to real server for url: "
// + urlToCall);
///////////////////////////////////
//begin send request to server, get response from server
URL url = new URL(urlToCall);
URLConnection conn = url.openConnection();
conn.setDoInput(true);
//not doing HTTP posts
conn.setDoOutput(false);
//System.out.println("Type is: "
//+ conn.getContentType());
//System.out.println("content length: "
//+ conn.getContentLength());
//System.out.println("allowed user interaction: "
//+ conn.getAllowUserInteraction());
//System.out.println("content encoding: "
//+ conn.getContentEncoding());
//System.out.println("content type: "
//+ conn.getContentType());
// Get the response
InputStream is = null;
HttpURLConnection huc = (HttpURLConnection)conn;
if (conn.getContentLength() > 0) {
is = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(is));
}
//end send request to server, get response from server
///////////////////////////////////
///////////////////////////////////
//begin send response to client
byte by[] = new byte[ BUFFER_SIZE ];
int index = is.read( by, 0, BUFFER_SIZE );
while ( index != -1 )
{
out.write( by, 0, index );
index = is.read( by, 0, BUFFER_SIZE );
}
out.flush();
//end send response to client
///////////////////////////////////
} catch (Exception e) {
//can redirect this to error log
System.err.println("Encountered exception: " + e);
//encountered error - just send nothing back, so
//processing can continue
out.writeBytes("");
}
//close out all resources
if (rd != null) {
rd.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have copy-pasted the above code from the internet, however I am having difficulties running it.
To answer the question from the post title, the run() method from ProxyThread class is called by JVM, after the thread has been started new ProxyThread(serverSocket.accept()).start(); and it usually contains the actual work that a thread should performed (in this case, it handles whatever the server socket receives and it accepts a connection from a client).
The moment when JVM calls run() method cannot be controlled by the programmer, but is after the thread has been started.
run() method is never called explicitly by the programmer.
I've got the following code for my server:
try
{
Socket = serverSocket.accept();
inputStreamReader = new InputStreamReader(Socket.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
message = bufferedReader.readLine();
switch(message)
{
case "GET / HTTP/1.1":
{
break;
}
default:
{
System.out.println(message);
}
}
inputStreamReader.close();
Socket.close();
}
catch(Exception e)
{
System.out.println("Problem while waiting for messages (" + e.toString() + ")");
}
and this code for my (Android) Client:
private String GetPC(String strToPC)
{
final String strToPCFinal = strToPC;
Thread SendingThread = new Thread()
{
public void run()
{
try
{
client = new Socket("192.168.178.22", 14510);
printwriter = new PrintWriter(client.getOutputStream());
printwriter.write(strToPCFinal);
printwriter.flush();
printwriter.close();
client.close();
}
catch(Exception e)
{
System.out.println("Problem while sending test message (" + e.toString() + ")");
}
}
};
SendingThread.start();
return "";
}
My question now is: How can I get an answer (if the text is successfully transmitted to my PC) back to my Android client?
private String readReply(SocketChannel socket) throws IOException {
final StringBuilder reply = new StringBuilder();
final ByteBuffer buffer = ByteBuffer.allocate(512);
int numBytesRead;
do {
numBytesRead = socket.read(buffer);
if (numBytesRead > 0) {
buffer.flip();
reply.append(decoder.decode(buffer).toString());
buffer.clear();
if (reply.indexOf(".") > -1) {
break;
}
}
} while (numBytesRead > -1);
socket.close();
return reply.toString();
}
Use the snippet below to send to server (if localhost)
private String send(String command) throws IOException {
final SocketAddress address = new InetSocketAddress("10.0.2.2", PORT);
final SocketChannel socket = SocketChannel.open(address);
final CharBuffer buffer = CharBuffer.wrap(command);
socket.write(encoder.encode(buffer));
final String reply = readReply(socket); // Get response
socket.close();
return reply;
}
I run my java webserver on port 6799
My directory has a txt.txt file and pdf.pdf file
When I give localhost:6799/txt.txt, it gives perfect output saying
GET /txt.txt HTTP/1.1HTTP/1.0 200 OK
Content-type: text/plain
This is a very simple text file
But when I give localhost:6799/pdf.pdf from browser, it gives java.lang.NullPointerException
This is my code
import java.net.*;
public final class WebServer {
public static void main(String args[]) throws Exception {
int port = 6799;
System.out.println("\nListening on port " + port);
ServerSocket listen = new ServerSocket(port);
while (true) {
Socket socket = listen.accept();
HttpRequest request = new HttpRequest(socket);
Thread thread = new Thread(request);
thread.start();
}
}
}
--
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
public final class HttpRequest implements Runnable {
final String CRLF = "\r\n";
Socket socket;
public HttpRequest(Socket socket) throws Exception {
this.socket = socket;
}
#Override
public void run() {
try {
processRequest();
} catch (Exception e) {
System.out.println(e);
}
}
private void processRequest() throws Exception {
BufferedReader br;
DataOutputStream dos;
try (InputStream is = socket.getInputStream()) {
br = new BufferedReader(new InputStreamReader(is));
String requestline = br.readLine();
System.out.println("\n" + requestline);
String headerLine = null;
while ((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
dos = new DataOutputStream(socket.getOutputStream());
dos.writeBytes(requestline);
StringTokenizer tokens = new StringTokenizer(requestline);
tokens.nextToken(); // skip over the method, which should be "GET"
String fileName = tokens.nextToken();
// Prepend a "." so that file request is within the current directory.
fileName = "." + fileName;
FileInputStream fis = null;
boolean fileExists = true;
try {
fis = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
fileExists = false;
}
String statusLine = null;
String contentTypeLine = null;
String entityBody = null;
if (fileExists) {
statusLine = "HTTP/1.0 200 OK" + CRLF;
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
} else {
statusLine = "HTTP/1.0 404 Not Found" + CRLF;
//contentTypeLine = "Content-type: " + "text/html" + CRLF;
entityBody = "<HTML>"
+ "<HEAD><TITLE>Not Found</TITLE></HEAD>"
+ "<BODY>Not Found</BODY></HTML>";
}
dos.writeBytes(statusLine);
dos.writeBytes(contentTypeLine);
dos.writeBytes(CRLF);
if (fileExists) {
sendBytes(fis, dos);
fis.close();
} else {
dos.writeBytes(entityBody);
}
}
br.close();
dos.close();
socket.close();
}
private void sendBytes(FileInputStream fis, DataOutputStream dos) throws IOException {
byte[] buffer = new byte[4096];
int bytes = 0;
while ((bytes = fis.read(buffer)) != -1) {
dos.write(buffer, 0, bytes);
}
}
private String contentType(String fileName) {
if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
return "text/html";
}
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
return "image/jpeg";
}
if (fileName.endsWith(".gif")) {
return "image/gif";
}
if (fileName.endsWith(".txt")) {
return "text/plain";
}
if (fileName.endsWith(".pdf")) {
return "application/pdf";
}
return "application/octet-stream";
}
}
STACK TRACE
java.lang.NullPointerException
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:274)
at HttpRequest.processRequest(HttpRequest.java:65)
at HttpRequest.run(HttpRequest.java:20)
at java.lang.Thread.run(Thread.java:724)
At least one issue is this code:
while ((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
BufferedReader will return null at the end of the stream, so calling .length() on a null object will yield a NullPointerException.
A more idiomatic way to write this is:
while ((headerLine = br.readLine()) != null && headerLine.length() != 0) {
System.out.println(headerLine);
}
...which takes advantage of short-circuit logic to not evaluate the second condition if the result of (headerLine = br.readLine()) is null.
It is happening because for some reason you have toggled comment on the following line:
//contentTypeLine = "Content-type: " + "text/html" + CRLF;
Untoggle it and you're good!
I'm creating a p2p application in Java for file sharing. Each peer node will be running on my machine on a different port and listen for a request. but the problem I'm running into is when an instance of PeerNode is created my code runs into an infinite loop. Following is my code for PeerNode. Is this how I should create each node and have them listen for incoming requests?
Following code represents one peer node:
public class PeerNode
{
private int port;
private ArrayList<PeerNode> contacts;
PeerNode preNode;
PeerNode postNode;
private String directoryLocation = "";
PeerNode(int port)
{
this.port = port;
this.setDirectoryLocation( port+"");
startClientServer( port );
}
private void sendRequest(String fileName, String host, int port) throws UnknownHostException, IOException
{
Socket socket = new Socket(host, port);//machine name, port number
PrintWriter out = new PrintWriter( socket.getOutputStream(), true );
out.println(fileName);
out.close();
socket.close();
}
private void startClientServer( int portNum )
{
try
{
// Establish the listen socket.
ServerSocket server = new ServerSocket( 0 );
System.out.println("listening on port " + server.getLocalPort());
while( true )
{
// Listen for a TCP connection request.
Socket connection = server.accept();
// Construct an object to process the HTTP request message.
HttpRequestHandler request = new HttpRequestHandler( connection );
// Create a new thread to process the request.
Thread thread = new Thread(request);
// Start the thread.
thread.start();
System.out.println("Thread started for "+ portNum);
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And following class creates all the nodes and connects them:
public class MasterClientServer
{
public static void main( String [] args )
{
int count = 10;
ArrayList<PeerNode> arrayOfNodes = createNodes( count );
}
public static ArrayList<PeerNode> createNodes( int count)
{
System.out.println("Creating a network of "+ count + " nodes...");
ArrayList< PeerNode > arrayOfNodes = new ArrayList<PeerNode>();
for( int i =1 ; i<=count; i++)
{
arrayOfNodes.add( new PeerNode( 0 ) ); //providing 0, will take any free node
}
return arrayOfNodes;
}
}
public class HttpRequestHandler implements Runnable
{
final static String CRLF = "\r\n";
Socket socket;
public HttpRequestHandler(Socket socket) throws Exception
{
this.socket = socket;
}
#Override
public void run()
{
try
{
processRequest();
}
catch (Exception e)
{
System.out.println(e);
}
}
/*
* Gets a request from another node.
* Sends the file to the node if available.
*/
private void processRequest() throws Exception
{
/*DataOutputStream os = new DataOutputStream(socket.getOutputStream());
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// Get the request line of the HTTP request message.
String requestLine = br.readLine();
// Extract the filename from the request line.
// In Get request, the second token is the fie name
String[] tokens = requestLine.split(" ");
String fileName = tokens[1];
// Prepend a "." so that file request is within the current directory.
fileName = "." + fileName;
// Open the requested file.
FileInputStream fis = null;
boolean fileExists = true;
try
{
fis = new FileInputStream(fileName);
}
catch (FileNotFoundException e)
{
fileExists = false;
}
// construct the response Message
// Construct the response message.
String statusLine = null;
String contentTypeLine = null;
String entityBody = null;
if (fileExists)
{
statusLine = "HTTP/1.1 200 OK" + CRLF;
contentTypeLine = "Content-Type: " + contentType(fileName) + CRLF;
}
else
{
statusLine = "HTTP/1.1 404 Not Found" + CRLF;
contentTypeLine = "Content-Type: text/html" + CRLF;
entityBody = "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY>Error 404: Page Not Found</BODY></HTML>";
}
// Send the status line.
os.writeBytes(statusLine);
// Send the content type line.
os.writeBytes(contentTypeLine);
// Send a blank line to indicate the end of the header lines.
os.writeBytes(CRLF);
// Send the entity body.
if (fileExists) {
sendBytes(fis, os);
fis.close();
} else {
os.writeBytes(entityBody);
}
// Close streams and socket.
os.close();
br.close();
socket.close();
}
private static void sendBytes(FileInputStream fis, OutputStream os)
throws Exception
{
// Construct a 1K buffer to hold bytes on their way to the socket.
byte[] buffer = new byte[1024];
int bytes = 0;
// Copy requested file into the socket's output stream.
while ((bytes = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytes);
}*/
}
private static String contentType(String fileName)
{
if (fileName.endsWith(".htm") || fileName.endsWith(".html"))
{
return "text/html";
}
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg"))
{
return "image/jpeg";
}
if (fileName.endsWith(".gif")) {
return "image/gif";
}
if (fileName.endsWith(".ram") || fileName.endsWith(".ra"))
{
return "audio/x-pn-realaudio";
}
return "application/octet-stream";
}
}
Your PeerNode constructor never returns since it is busy accepting new connections. Hence your loop in createNodes only creates the first PeerNode instance. You can solve this by calling startClientServer in a new thread:
new Thread(new Runnable() {
public void run() {
startClientServer( port );
}
}.start();