I am working on my assignment to make UDP reliable using java. How can i add Timeout and re-transmission to handle data-grams that are discarded and add Sequence numbers so the client can verify that a reply is for the appropriate request ??
this is client code
import java.net.*;
import java.io.*;
public class EchoClient {
// UDP port to which service is bound
public static final int SERVICE_PORT = 7;
// Max size of packet
public static final int BUFSIZE = 256;
public static void main(String args[]){
if (args.length != 1)
{
System.err.println ("Syntax - java EchoClient hostname");
return;
}
String hostname = args[0];
// Get an InetAddress for the specified hostname
InetAddress addr = null;
try
{
// Resolve the hostname to an InetAddr
addr = InetAddress.getByName(hostname);
}
catch (UnknownHostException uhe)
{
System.err.println ("Unable to resolve host");
return;
}
try
{
// Bind to any free port
DatagramSocket socket = new DatagramSocket();
// Set a timeout value of two seconds
socket.setSoTimeout (2 * 1000);
for (int i = 1 ; i <= 10; i++)
{
// Copy some data to our packet
String message = "Packet number " + i ;
char[] cArray = message.toCharArray();
byte[] sendbuf = new byte[cArray.length];
for (int offset = 0; offset < cArray.length ; offset++)
{
sendbuf[offset] = (byte) cArray[offset];
}
// Create a packet to send to the UDP server
DatagramPacket sendPacket = new DatagramPacket(sendbuf, cArray.length, addr, SERVICE_PORT);
System.out.println ("Sending packet to " + hostname);
// Send the packet
socket.send (sendPacket);
System.out.print ("Waiting for packet.... ");
// Create a small packet for receiving UDP packets
byte[] recbuf = new byte[BUFSIZE];
DatagramPacket receivePacket = new DatagramPacket(recbuf, BUFSIZE);
// Declare a timeout flag
boolean timeout = false;
// Catch any InterruptedIOException that is thrown
// while waiting to receive a UDP packet
try
{
socket.receive (receivePacket);
}
catch (InterruptedIOException ioe)
{
timeout = true;
}
if (!timeout)
{
System.out.println ("packet received!");
System.out.println ("Details : " + receivePacket.getAddress() );
// Obtain a byte input stream to read the UDP packet
ByteArrayInputStream bin = new ByteArrayInputStream (
receivePacket.getData(), 0, receivePacket.getLength() );
// Connect a reader for easier access
BufferedReader reader = new BufferedReader (
new InputStreamReader ( bin ) );
// Loop indefinitely
for (;;)
{
String line = reader.readLine();
// Check for end of data
if (line == null)
break;
else
System.out.println (line);
}
}
else
{
System.out.println ("packet lost!");
}
// Sleep for a second, to allow user to see packet
try
{
Thread.sleep(1000);
}catch (InterruptedException ie) {}
}
}
catch (IOException ioe)
{
System.err.println ("Socket error " + ioe);
}
}
}
What you can do is adding import TCP headers like sequence number, windows into the UDP message body to make it more like TCP. Here is the a solution that might help you.
Related
I have posted my java proxy code below.
It works but it only gives me 1 server response instead of everything.
After the 1 response I just get client sent packets but with a size of 0.
Screenshots also attached.
Any ideas?
I've done some debugging. If I remove everything in between
typ = streamFromServer.readUnsignedShort();
siz = streamFromServer.readUnsignedShort();
siz <<= 8;
siz |= streamFromServer.readUnsignedByte();
byte[] dat = new byte[siz];
streamFromServer.readFully(dat, 0, siz);
String FullHe = DatatypeConverter.printHexBinary(dat);
System.out.println("Server sending data to Client:");
System.out.println("Type: " + typ + "");
System.out.println("Data Size: " + siz + "");
System.out.println("Full Data: " + FullHe + "");
System.out.println("\n\n");
Which is from the reading server response code it works and I get the client packets. How come it doesn't work with server packets?
Code:
import java.io.*;
import javax.xml.bind.DatatypeConverter;
import java.net.*;
public class proxy{
public static void main(String[] args) throws IOException {
//PrintStream out = new PrintStream(new FileOutputStream("log.txt"));
//System.setOut(out);
try{
String host = "gamea.clashofclans.com";
int remoteport = 9339;
ServerSocket ss = new ServerSocket(9339);
int localport = ss.getLocalPort();
ss.setReuseAddress(true);
// 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,ss); // never returns
System.out.println("Started proxy!");
} catch (Exception e) {
System.out.println("Failed to start proxy" +e+ "");
}
}
public static void runServer(String host, int remoteport, int localport, ServerSocket ss)
throws IOException {
final byte[] request = new byte[2048];
byte[] reply = new byte[4096];
while (true) {
Socket client = null, server = null;
try {
System.out.println("Waiting for Client");
client = ss.accept();
System.out.println("Client Accepted!");
DataInputStream streamFromClient = new DataInputStream(client.getInputStream());
DataOutputStream streamToClient = new DataOutputStream(client.getOutputStream());
System.out.println("Connecting to server...");
// Make a connection to the real server.
server = new Socket("gamea.clashofclans.com", 9339);
System.out.println("Just connected client to " + server.getRemoteSocketAddress());
DataInputStream streamFromServer = new DataInputStream(server.getInputStream());
DataOutputStream streamToServer = new DataOutputStream(server.getOutputStream());
Thread t = new Thread() {
public void run() {
int bytesRead;
int type;
int size;
int version;
try {
while ((bytesRead = streamFromClient.read(request)) != -1) {
type = streamFromClient.readUnsignedShort();
size = streamFromClient.readUnsignedShort();
size <<= 8;
size |= streamFromClient.readUnsignedByte();
version = streamFromClient.readUnsignedByte();
byte[] data = new byte[size];
streamFromClient.readFully(data, 0, size);
String FullHex = DatatypeConverter.printHexBinary(data);
System.out.println("Client sending data to server:");
System.out.println("Type: " + type + "");
System.out.println("Data Size: " + size + "");
System.out.println("Version: " + version + "");
System.out.println("Full Data: " + FullHex + "");
System.out.println("\n\n");
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) {
}
}
};
t.start();
int bytesRea;
int typ;
int siz;
try {
while ((bytesRea = streamFromServer.read(reply)) != -1) {
typ = streamFromServer.readUnsignedShort();
siz = streamFromServer.readUnsignedShort();
siz <<= 8;
siz |= streamFromServer.readUnsignedByte();
byte[] dat = new byte[siz];
streamFromServer.readFully(dat, 0, siz);
String FullHe = DatatypeConverter.printHexBinary(dat);
System.out.println("Server sending data to Client:");
System.out.println("Type: " + typ + "");
System.out.println("Data Size: " + siz + "");
System.out.println("Full Data: " + FullHe + "");
System.out.println("\n\n");
streamToClient.write(reply, 0, bytesRea);
streamToClient.flush();
}
} catch (IOException e) {
}
} catch (IOException e) {
System.err.println(e);
} finally {
try {
if (server != null)
server.close();
if (client != null)
client.close();
} catch (IOException e) {
}
}
}
}
}
This doesn't make sense. You're reading up to 4096 bytes from the server and then reading two type bytes and three length bytes and what you think is the request data, and writing what you read originally. So you're consuming the data about twice.
This can't work. You need to either just read the type, length, and value, and write them out again, or else, much more simply, just copy bytes from the input to the output, in both directions. (That way of course you can't do logging.)
NB Don't ignore IOExceptions, and especially not EOFExceptions when reading from DataInputStreams (or ObjectInputStreams).
I am trying to send a text file from the sender to the receiver however on the sender side I get connection refused: connect. I use a localhost address on the receiver side and I manually enter it in when prompt on the sender side. The error occurs at sendChannel.connect(address) in the sender class.
Sender class:
public static void startProcess(){
SocketChannel sendChannel = null;
RandomAccessFile f = null;
Scanner scan = new Scanner(System.in);
SocketAddress address = null;
try{
sendChannel = SocketChannel.open(); // open the channel
//DatagramSocket socket = dChannel.socket();
boolean validAddr = false;
while(validAddr != true){
try{
System.out.println("Enter in valid server IP Address");
address = new InetSocketAddress(scan.nextLine(),7777);
validAddr = true;
}
catch(Exception e){
System.out.println("Invalid!");
System.out.println(e.getMessage());
}
}
//System.out.println("Address: " + InetAddress.getLocalHost().getHostAddress());
sendChannel.connect(address);
File i = new File("./data.txt");
f = new RandomAccessFile(i,"r");
FileChannel fChannel = f.getChannel();
ByteBuffer bBuffer = ByteBuffer.allocate(1024); //set buffer capacity to 1024 bytes
while (fChannel.read(bBuffer) > 0) {
//SocketAddress client = dChannel.receive(bBuffer); //receive the datagram
bBuffer.flip(); //Set limit to current position
sendChannel.write(bBuffer);
//dChannel.send(bBuffer, client); //send the datagram using channel
bBuffer.clear(); //Get ready for new sequence of operations
}
Thread.sleep(1000);
System.out.println("End of file reached");
sendChannel.close();
f.close();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
Receiver side:
public static void startProcess(){
Scanner scan = new Scanner(System.in);
ServerSocketChannel serverChannel = null;
SocketChannel chan = null;
RandomAccessFile file = null;
try{
serverChannel = ServerSocketChannel.open();
//Read in a valid IP Address
boolean val2 = false;
int tempNum = 0;
for (int portNUM = 7777 ;!val2; portNUM++){
try {
serverChannel.socket().bind(new InetSocketAddress("localhost", portNUM));
tempNum = portNUM;
val2 =true;
} catch (IOException e) {
System.out.println("Error!");
}
}
System.out.println(InetAddress.getLocalHost().getHostAddress());
System.out.println("Port Number: " + tempNum);
chan = serverChannel.accept();
System.out.println("Connected!");
chan.getRemoteAddress();
file = new RandomAccessFile("./output.txt","rw");
ByteBuffer buff = ByteBuffer.allocate(1024);
FileChannel receiveChannel = file.getChannel();
while(chan.read(buff) > 0){
buff.flip();
receiveChannel.write(buff);
buff.clear();
}
// buff.put((byte)65 );
//buff.flip();
Thread.sleep(1000);
receiveChannel.close();
System.out.println("End of file");
chan.close();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
I figured it out I was using the localhost incorrectly on the Receiver side. I changed it to serverChannel.socket().bind(new InetSocketAddress(portNUM));
I want a client to connect to more than one server. i.e. I want my client to send a number to server1 which squares the number and echoes it back to the client. However I want the client to then send this squared number to a second server listening on a different port.
I'm not sure how to implement this functionality, could I do this through threads or would I just open a second socket to server2?
Here is the code for my client.
import java.io.*;
import java.net.*;
public class ClientA {
public static void main(String[] args) {
String serverhost = "localhost";
int serverport = 6789;
Socket clientSocket = null;
DataOutputStream os = null;
BufferedReader is = null;
try {
clientSocket = new Socket(serverhost, serverport);
os = new DataOutputStream(clientSocket.getOutputStream());
is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverhost);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: " + serverhost);
} //end try
if (clientSocket == null || os == null || is == null) {
System.err.println( "An error has occured, please restart." );
return;
} //end if
try {
while ( true ) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String keyboardInput = br.readLine();
os.writeBytes( keyboardInput + "\n" );
int n = Integer.parseInt( keyboardInput );
if ( n == 0 ) {
break;
}
String responseLine = is.readLine();
System.out.println("Server returns its square as: " + responseLine);
}
os.close();
is.close();
clientSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
} //end try
} //end main
} //end class
Based on the info you've given, I don't see the need to make it a multi-threaded application as you're only sending (i.e. not receiving) data to the second server when you receive a reply from the first server. Just set up a second socket to the other address and send the data when you get it from the first server.
I'm trying to code a UDP client to receive packets from a server that is broadcasting on the local network. The problem is the receive method isn't blocking and waiting for a packet to arrive.
Instead, it's receiving null or empty packets.
I've tried to use .setSoTimeout(0), which supposedly will tell the receive to block until it receives a packet, but it doesn't.
Does anyone know how to fix this?
Here's the code:
while (search == true) {
InetAddress addr = InetAddress.getByName("0.0.0.0");
DatagramSocket sock = new DatagramSocket(1355);
sock.setSoTimeout(0);
byte[] recebe = new byte[1024];
sock.setBroadcast(true);
System.out.println("entrou1");
DatagramPacket packet = new DatagramPacket(recebe, recebe.length);
System.out.println("entrou2");
sock.receive(packet);
String info = new String(packet.getData());
System.out.println("tamanho: " + info.length());
if (info.trim().equals("") == false && info != null) {
System.out.println("entrou aqui");
System.out.println("info recebida:" + info + ":fsadfsfs");
String servs[] = info.split("\n");
list1.clear();
servidores.clear();
for (int i = 0; i < servs.length; i++) {
System.out.println("vec: " + servs[i]);
if (servs[i].trim().equals("")) {
System.out.println("break;");
break;
} else {
String aux = servs[i].substring(0, servs[i].lastIndexOf("->"));
System.out.println("aux: " + aux);
list1.add(aux);
servidores.add(servs[i]);
}
}
}
System.out.println("info:\n" + info);
sock.close();
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException ex) {
Logger.getLogger(AcederPartilhaGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I'm writing a simple download accelerator. The problem is I can send and receive messages once. The next time I try to send and receive message, I get no response froms server. I'm not even sure if I am able to send the second message.
The first message is something like;
*HEAD /TIPS/LAWLER/PANOHOW2.PDF HTTP/1.0\r\n
HTTP/1.0\r\n
Connection: close\r\n
\r\n*
and response is;
*HTTP/1.1 200 OK
Date: Mon, 24 Jan 2011 10:53:38 GMT
Server: Apache
Last-Modified: Tue,
22 Sep 1998 13:19:52 GMT
ETag: "1968013-2b4f4-3386e15b6ee00"
Accept-Ranges: bytes
Content-Length: 177396
Connection: close
Content-Type: application/pdf*
When i attemp to sen message;
GET /TIPS/LAWLER/hedeh/PANOHOW2.PDF HTTP/1.0\r\n
Range: bytes=0-44349\r\n
Connection: close\r\n
\r\n
I get nothing.
What is wrong with my code?
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//Parse URL
String cmd = "http://www.imaging-resource.com"; //Host Name
if (cmd.contains("http://"))
{
cmd = cmd.substring(7); //
if (cmd.contains("/"))
{
int index = cmd.indexOf("/");
cmd = cmd.substring(0, index);
System.out.println(cmd);
}
}
String str = "HEAD /TIPS/LAWLER/PANOHOW2.PDF HTTP/1.0\r\nConnection: close\r\n\r\n"; //First message to send
//Create socket, connect, initialize read and write handlers
//in, out
Socket socket = null; //Create a client socket
SocketAddress sockaddr = null;
InetAddress address = null;
InputStream input = null; //Input handler
OutputStream output = null; //Output handler
try
{
address = InetAddress.getByName(cmd); //Get ip using host name
socket = new Socket(); //Contrusct Socket
sockaddr = new InetSocketAddress(address, 80);
//socket.setTcpNoDelay(false);
socket.connect(sockaddr, 2000); //Connect to server set and timeout to 2 sec
} //End of try Block
catch (Exception ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex);
} //End of catch Block
if (!socket.isConnected())
{
System.out.println("not connected");
System.exit(-1);
}
//Sending package here
try
{
int c;
byte[] buf = new byte[65535];
char[] chr = new char[65535];
input = socket.getInputStream(); //Input handler is created
output = socket.getOutputStream(); //Output handler is created
buf = str.getBytes(); //HEAD message converted into byte array
output.write(buf); //Sending message to server
output.flush();
int counter = 0;
while ((c = input.read()) != -1) //Reading received package
chr[counter++]=(char)c;
//input.reset();
str = new String(chr); //For better manipulation, server message is converted to string
System.out.println(str);
} catch (IOException e)
{
System.err.print(e);
} //End of catch
int index = str.indexOf("Content-Length"); //Look for "Content-Length" in response
str = str.substring(index); //Using its beginning index create an substring
index = str.indexOf("\r\n"); //Search for end of line
str = str.substring(0, index); //Erase end if line chars - \r\n
str = str.substring(16, str.length()); //"Content-Length: " 16 chars
int fileSize = Integer.parseInt(str); //Lentgh of file is converted to Integer
int[][] parts = new int[4][2]; //Beginning and en of jobs for threads will be stored here
int remainder = fileSize; //Bytes left to split for rest of the threads will be stored here
int start = 0;
int finish = 0;
for (int i = 0; i < 4; i++) //Number of threads many times
{
parts[i][0] = start; //*******Each threads job Interval(eg. 0-108)
//System.out.print(parts[i][0] + "-"); //******
finish += remainder / 4 - i; //*****
parts[i][1] = finish; //****
start = finish + 1; //***
if (i + 1 == 4)
parts[i][1] = fileSize; //*
}
str = "GET /TIPS/LAWLER/hedeh/PANOHOW2.PDF HTTP/1.0\r\nRange: bytes=" + parts[0][0] + "-" + parts[0][1] + "\r\nConnection: close\r\n\r\n";
//System.out.println(str);
if(!socket.isConnected())
{
System.out.println("closed");
try
{
socket.connect(sockaddr, 2000);
}//End od try
catch(Exception e){
System.err.print(e);
}//End of catch
}//End of If
System.out.println("Is Outputhandler closed :"+socket.isOutputShutdown());
System.out.println("Is Inputhandler closed :"+socket.isInputShutdown());
try
{
int c;
byte[] buf = new byte[65535];
char[] chr = new char[65535];
buf = str.getBytes(); //Output handler is created
output.write(buf); //Sending message to server
output.flush();
int counter = 0;
if((c = input.read()) != -1)
{
chr[counter++] = (char) c;
while ((c = input.read()) != -1) //Reading received package
{
System.out.println("response is not -1");
chr[counter++]=(char)c;
}
str = new String(chr); //For better manipulation, serve message is converted to string
System.out.println("Response "+str);
}//End of If
else System.out.println("No Response!");
}catch(Exception e)
{System.err.print(e);}
//Closing open stuff
try {
output.close();
input.close();
socket.close();
} catch (Exception e) {
System.out.println(e);
}
}// End of main method
}//End of class definition
The first message is something like;
HTTP/1.0\r\n
You have to use HTTP version 1.1 to use multiple requests on a single TCP connection.
From the Wikipedia article on HTTP:
In HTTP/0.9 and 1.0, the connection is closed after a single request/response pair. In HTTP/1.1 a keep-alive-mechanism was introduced, where a connection could be reused for more than one request.
Also, as #Joachim Sauer points out in the comments, you're explicitly saying Connection: close in your header. :-)
I think that the problem is that you are trying to connect to HTTP server using plain TCP socket. Yes, HTTP is on top of TCP but it is complicated protocol that requires a lot of things to know. I'd suggest you to work with higher level API that implements HTTP protocol and provides you more convenient API.
The simplest example is URL+URLConnection from JDK. Probably better is HttpClient from Jakarta.