I have quite a complex question here, I hope understanding my code won't be such a problem.
I'm writing a program based on UDP and TCP communication in Java.
Server is listening on several UDP ports (1. number and quantity of ports is given by a user in program parameters; 2. A Thread is created for each port) for a packets from Clients (there can be more than one trying to send a packet at a time to Server). Each packet contains Clients id, the message and UDP port number of the Client who send this packet. Server receives the packet, puts the message in a HashMap (Client id is the key, sent messages are stored in a List of Strings). On each packet received, Servers checks the List of Strings whether the messages sent from specified Client are matching a password. If the messages are in correct order, Server sends a generated port number for TCP communication with the Client who has sent the correct password, opens ServerSockets, they perform a simple communication and the Client closes.
Now, a Client should be able to send his messages to various ports. For example, Server is listening on ports 2000 and 3000. A Client should be able to send 2 messages to port 2000 and another two messages on port 3000. However, the Server seems to be be receiving messages only on the first opened port.
If a Client sends all his messages on one port, it all works fine.
Here is the Server class:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
public class Server {
static int portsOpenedQuantity;
static HashMap<String, List<String>> packetsReceived = new HashMap<>();
static List<Integer> portsTCP = new ArrayList<>();
public static void main(String[] args) {
portsOpenedQuantity = args.length;
List<String> listOfPorts = new ArrayList<>();
for(int i = 0; i < portsOpenedQuantity; ++i)
if(!listOfPorts.contains(args[i]) && (Integer.parseInt(args[i]) > 1024))
listOfPorts.add(args[i]);
for(int i = 0; i < listOfPorts.size(); ++i) {
final int j = i;
System.out.println("SERVER listening on port: " + listOfPorts.get(j));
Thread listeningPort = new Thread(new Runnable() {
#Override
public void run() {
synchronized (packetsReceived){
try {
byte[] packetReceived = new byte[256];
DatagramSocket ds = new DatagramSocket(Integer.parseInt(listOfPorts.get(j)));
DatagramPacket dp = new DatagramPacket(packetReceived, 256);
while(true){
ds.receive(dp);
List<String> sequence = new ArrayList<>();
System.out.println("SERVER received a packet");
String msgReceived = new String(dp.getData(), 0, dp.getLength());
String[] separatedMsg = msgReceived.split(" ");
int portUDPNumber = Integer.parseInt(separatedMsg[2]);
System.out.println("Id: " + separatedMsg[0]);
System.out.println("Value: " + separatedMsg[1]);
System.out.println("Port UDP: " + separatedMsg[2]);
if(packetsReceived.containsKey(separatedMsg[0])) {
sequence = packetsReceived.get(separatedMsg[0]);
packetsReceived.remove(separatedMsg[0]);
System.out.println(separatedMsg[1]);
sequence.add(separatedMsg[1]);
System.out.println(sequence);
packetsReceived.put(separatedMsg[0], sequence);
} else {
System.out.println(sequence);
sequence.add(separatedMsg[1]);
packetsReceived.put(separatedMsg[0], sequence);
}
String sequenceResult = "";
for(int k = 0; k < sequence.size(); ++k) {
sequenceResult += sequence.get(k);
}
System.out.println(sequenceResult);
if(sequenceResult.equals("!##$")){
System.out.println("Connecting via TCP...");
int portNumber = (int)((Math.random()*100)+5000);
boolean portAvailable = true;
ServerSocket ss = null;
System.out.println("TCP port number: " + portNumber);
while(portAvailable) {
try{
ss = new ServerSocket(portNumber);
portsTCP.add(portNumber);
portAvailable = false;
} catch(Exception e) {
portAvailable = true;
portNumber++;
}
}
System.out.println("socket number aquired");
String portNr = portNumber+"";
byte[] portNrToSend = portNr.getBytes();
dp = new DatagramPacket(portNrToSend, portNrToSend.length, InetAddress.getByName("localhost"), portUDPNumber);
System.out.println("Datagram created");
ds.send(dp);
System.out.println("Datagram sent");
Socket s = ss.accept();
System.out.println("Port number sent to: " + portUDPNumber);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String msgFromClient = in.readLine();
System.out.println("Message from client: " + msgFromClient);
out.println("I received your message");
in.close();
out.close();
s.close();
ss.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
listeningPort.start();
}
}
}
And the Client class:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class Client {
InetAddress ip;
String idClient;
List<Integer> portsUDP = new ArrayList<>();
String sequence;
public Client(String[] args) {
try {
ip = InetAddress.getByName(args[0]);
idClient = args[1];
for(int i = 2; i < args.length; ++i)
portsUDP.add(Integer.parseInt(args[i]));
this.sequence = "!##$";
DatagramSocket ds = new DatagramSocket();
DatagramPacket dp = null;
for(int i = 0; i < portsUDP.size(); ++i) {
byte[] toSend = new byte[256];
String msgToSend = idClient + " " + sequence.charAt(i) + " " + ds.getLocalPort();
System.out.println("CLIENT named as: " + idClient + " sends a message: " + sequence.charAt(i) + " " + ds.getLocalPort());
toSend = msgToSend.getBytes();
dp = new DatagramPacket(toSend, toSend.length, ip, portsUDP.get(i));
ds.send(dp);
System.out.println("CLIENT: " + idClient + " sent a packet");
toSend = new byte[256];
msgToSend = "";
}
String received;
byte[] tabReceived = new byte[256];
dp = new DatagramPacket(tabReceived, tabReceived.length);
System.out.println("Datagram created");
ds.receive(dp);
System.out.println("Datagram received");
received = new String(dp.getData(), 0, dp.getLength());
System.out.println("Received TCP port number: " + received);
int portTCP = Integer.parseInt(received);
int portNumber = (int)((Math.random()*100)+5000);
boolean portAvailable = true;
ServerSocket ss = null;
while(portAvailable) {
try{
ss = new ServerSocket(portNumber);
portAvailable = false;
} catch(Exception e) {
portAvailable = true;
portNumber++;
}
}
System.out.println("ServerSocket created");
Socket s = new Socket(ip, portTCP);
System.out.println("Socket created");
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out.println("Succes of communication");
String msgFromServer = in.readLine();
System.out.println("Message from SERVER: " + msgFromServer);
in.close();
out.close();
s.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Client(args);
}
}
I think what is creating problems here is the synchronization on the HashMap, but when I run it without synchronization, the packets come in a completely random sequence, are not stored in the HashMap properly - it's just much worse.
I'd be grateful for any suggestions and comments.
Your Runnable loops forever after obtaining a lock on a shared object called packetsReceived, so only one of your Threads will actually be able to accomplish anything; the other thread will wait for the lock forever.
You should be able to verify this with a simple thread dump while your sample program is running.
The solution (to the synchronization problem) is to only obtain that lock when you want to actually modify the HashMap. So, remove the synchronized(packetsReceived) from outside the loop and put it around the code that actually performs the containsKey/remove/put calls on the HashMap.
Related
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.
I am trying to send binary files over TCP. The server is written in Python and the client in Java.
Server:
import socket;
TCP_IP = '127.0.0.1'
TCP_PORT = 5001;
BUFFER_SIZE = 1024;
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
except:
"Can not bind server on port: "+ str(TCP_PORT) +"\n";
while 1:
print("Wait for connections!!!\n");
conn, addr = s.accept();
print("Receive a new connection!!!\n");
# presentation of client
data = conn.recv(BUFFER_SIZE);
if not data:
conn.close();
print("Lost connection!!!");
continue;
# respond to client
conn.sendall("Hello 1\n");
# receive new request
data = conn.recv(BUFFER_SIZE);
if not data:
continue;
conn.sendall("OK\n");
f = open('testImage.jpg', "rb");
dataRaw = f.read();
f.close();
fileSize = len(dataRaw); #sys.getsizeof(dataRaw);
# send file size
conn.send(str(fileSize) + "\n");
conn.send(dataRaw);
conn.sendall("OK\n");
Client
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class mainTestReceiveFile
{
public static void main(String[] args) throws Exception
{
String usr2ConnectDefault = "127.0.0.1";
int port2ConnectDefault = 5001;
Socket socket;
BufferedReader in;
PrintWriter out;
socket = new Socket(usr2ConnectDefault, port2ConnectDefault);
System.out.println("Connected to server...sending echo string");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
// say hello to server
out.println("Hello");
// read hello from server
String readString = in.readLine();
System.out.println(readString);
out.println("ReadFile");
// verify if request is OK
readString = in.readLine();
if(readString.compareToIgnoreCase("OK") == 0)
System.out.println("Receive new file!!!");
else
{
socket.close();
return;
}
// get size of file
readString = in.readLine();
int sizeOfFile = Integer.parseInt(readString);
//InputStream is = socket.getInputStream();
byte[] fileData = new byte[sizeOfFile];
for(int i = 0; i < sizeOfFile; i++)
{
fileData[i] = (byte)in.read();
}
// save file to disk
FileOutputStream fos = new FileOutputStream("fileImage.jpg");
try
{
fos.write(fileData);
}
finally {
fos.close();
}
// verify if request is OK
readString = in.readLine();
if(readString.compareToIgnoreCase("OK") == 0)
System.out.println("New file received!!!");
else
{
socket.close();
return;
}
socket.close();
}
}
I am trying to send for example one image. In the client side, the image received has the same size (file size and number of pixels) but the data is corrupted.
I need to code some proxy server for an assignment in my university. It should be able to display the content of some simple web page given by our professor.
Additionally it should filter the URL and the URL content, and block the web page if one of these contain one of the words in my "bad" array.
My question is, how can I perform this filtering in Java.
Code:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class ProxyServer{
//Crate the Port the user wants the proxy to be on
static Scanner sc = new Scanner(System.in);
public static final int portNumber = sc.nextInt();
public static void main(String[] args) {
ProxyServer proxyServer = new ProxyServer();
proxyServer.start();
}
public void start() {
System.out.println("Starting the SimpleProxyServer ...");
try {
String bad[]= new String[4];
bad[0]= "Spongebob";
bad[1]= "Britney Spears";
bad[2]= "Norrköping";
bad[3]= "Paris Hilton";
ServerSocket serverSocket = new ServerSocket(ProxyServer.portNumber);
System.out.println(serverSocket);
byte[] buffer= new byte [1000000] ;
while (true) {
Socket clientSocket = serverSocket.accept();
InputStream inputstream = clientSocket.getInputStream();
System.out.println(" DAS PASSIERT VOR DEM BROWSER REQUEST:");
int n = inputstream.read(buffer);
String browserRequest = new String(buffer,0,n);
System.out.println("Das ist der Browserrequest: "+browserRequest);
System.out.println("Das ist der Erste Abschnitt");
int start = browserRequest.indexOf("Host: ") + 6;
int end = browserRequest.indexOf('\n', start);
String host = browserRequest.substring(start, end - 1);
System.out.println("Connecting to host " + host);
Socket hostSocket = new Socket(host, 80); //I can change the host over here
OutputStream HostOutputStream = hostSocket.getOutputStream();
PrintWriter writer= new PrintWriter (HostOutputStream);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream));
String Input= null;
while (((Input= reader.readLine())!= null)){
writer.write(Input);
writer.flush();
System.out.println("Empfangen vom Client: "+Input);
}
// for (int i=0; i<4;i++){
// if (inString.contains(bad[i])){
// System.out.println("Bye Idiot");
// break;
// }
// }
System.out.println("Forwarding request to server");
HostOutputStream.write(buffer, 0, n);// but then the buffer that is fetched from the client remains same
HostOutputStream.flush();
InputStream HostInputstream = hostSocket.getInputStream();
OutputStream ClientGetOutput = clientSocket.getOutputStream();
System.out.println("Forwarding request from server");
do {
n = HostInputstream.read(buffer);
String inhalt= HostInputstream.toString();
System.out.println("das ist der inhalt vom HOST: "+ inhalt);
String vomHost = new String(buffer,0,n);
System.out.println("Vom Host\n\n"+vomHost);
// for(int i=0;i<n;i++){
// System.out.print(buffer[i]);
// }
System.out.println("Receiving " + n + " bytes");
if (n > 0) {
ClientGetOutput.write(buffer, 0, n);
}
} while (HostInputstream.read(buffer)!= -1);//n>0
ClientGetOutput.flush();
hostSocket.close();
clientSocket.close();
System.out.println("End of communication");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am writing a simple socket program as shown below. I want to send a byte array to a server socket and readi it at the server end.
This is the server
package com.java;
//File Name GreetingServer.java
import java.net.*;
import java.io.*;
public class GreetingsServer extends Thread
{
private ServerSocket serverSocket;
public GreetingsServer(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run()
{
while(true)
{
try
{
System.out.println("Waiting for client on port " +
serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to "
+ server.getRemoteSocketAddress());
DataInputStream in =
new DataInputStream(server.getInputStream());
System.out.println("--"+ server.getReceiveBufferSize());
byte[] b1 = new byte[4] ;
int i =in.read(b1);
System.out.println("i = " + i + "b1 = " +b1);
/* DataOutputStream out =
new DataOutputStream(server.getOutputStream());
out.writeUTF("Thank you for connecting to "
+ server.getLocalSocketAddress() + "\nGoodbye!");*/
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = Integer.parseInt(args[0]);
try
{
Thread t = new GreetingsServer(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
This is the client
package com.java;
import java.net.*;
import java.io.*;
public class GreetingClient
{
public static void main(String [] args)
{
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try
{
System.out.println("Connecting to " + serverName
+ " on port " + port);
Socket client = new Socket(serverName, port);
System.out.println("Just connected to "
+ client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
byte[] b = {1,2,3,4};
DataOutputStream out =
new DataOutputStream(outToServer);
/*BufferedOutputStream out = new BufferedOutputStream(outToServer);*/
System.out.println("**" + b);
out.write(b);
/*out.writeUTF("Hello from "
+ client.getLocalSocketAddress());*/
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
The output I get is this for the server.
Waiting for client on port 6066...
Just connected to /127.0.0.1:52349
--65536
i = 4b1 = [B#48270664
Waiting for client on port 6066...
Socket timed out!
There two things wrong. The first is that the bytearray is not coming entirely to the server. And secondly the server is calling thread twice.
Any input will be helpful. Please let me know if anyone finds a problem!
The problem isn't what is being sent/received but rather how you're trying to output it to the console.
Arrays don't override toString(). In your server you have:
System.out.println("i = " + i + "b1 = " +b1);
The output of b1.toString() is the default from Object.toString() which as noted in the Javdoc for Object is:
a string consisting of the name of the class of which the object is an instance, the at-sign character `#', and the unsigned hexadecimal representation of the hash code of the object.
You need to use Arrays.toString(b1) to get a String that shows the actual bytes in that array as [ x, x, x ,x ] (where each x is the numeric value of the byte)
I'm trying to create a client/server program with java.
when the client connect to the server, the server will show him a message to enter the first value when the user write the first value the server sends him a message to write the sencd value when the user write the second value the server will show him a list of operations ans wait until the client write the number of the operation and then the server will send him the result of this operation.
When I write the program's code and run the server and then the client, it doesn't do any thing the server is blocked from doing anything, also the client.
this is the code I tried :
for the client :
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class Client {
final static String ADRSS = "localhost";
final static int PORT = 1234;
static Socket s = null;
public static void main(String[] args) {
try{
Scanner cn = new Scanner(System.in);
s = new Socket(ADRSS, PORT);
PrintWriter out = new PrintWriter(s.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
in.readLine();
out.println(cn.nextLine());
out.flush();
in.readLine();
out.println(cn.nextLine());
out.flush();
in.readLine();
out.println(cn.nextLine());
out.flush();
System.out.println("Res = " + in.readLine());
out.flush();
}
catch(IOException e){e.printStackTrace();
}
}
}
for the server:
import java.net.*;
import java.io.*;
public class Server {
final static int PORT = 1234;
private static ServerSocket server;
public static void main(String[] args) {
Socket s = null;
try {
server = new ServerSocket(PORT);
s = server.accept();
PrintWriter out = new PrintWriter(s.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out.println("Donner le premier nombre : ");
out.flush();
double n1 = Double.parseDouble(in.readLine());
out.println("Donner le deuxiéme nombre : ");
out.flush();
double n2 = Double.parseDouble(in.readLine());
out.println("Donner l'op : ");
out.flush();
String choix = in.readLine();
String res = null;
switch(choix){
case "1" :
res = String.valueOf(n1 + n2);
break;
case "2" :
res = String.valueOf(n1 - n2);
break;
case "3" :
res = String.valueOf(n1 * n2);
break;
case "4" :
res = (n2 == 0) ? "Impossible d'éfectuer l'op" : String.valueOf(n1 / n2);
break;
default :
res = "erreur";
}
out.println(res);
out.flush();
}catch(IOException e) {
e.printStackTrace();
}finally{
try{
s.close();
}catch(IOException e){e.printStackTrace();}
}
}
}
PrintWriter doesn't flush output after you use regular print (refer to documentation of PrintWriter). You'd have to flush it manually. However, the real reason is your client waits for a line with newline, which never happens. Changing to out.println on the server side should make this running, also covering the flushes.
first, after every print in the server, add
out.flush();
second, you are asking for nextLine() but printing without \n ,
either add \n to end of each string or use out.println