I try to create a program which is based on client/server communication.
In this program I have several clients and several servers.
At the beginning of the program some clients go up, and wait for new connections from different servers.
When the first server goes up, I want him to know who is the clients that are available in the network, and then it begins to communicate with all these clients in tcp protocol (ServerSocket).
However, if a new clients goes up, this server should know about it.
The same happens when new servers go up.
My first think, is to use multicast commnication. The client will send every 5 seconds a broadcast to the networks and the servers will listen to these messages.
My broblem is how to combine these two methods (multicast and tcp) in order to built this program.
Should I use two differnet ports one for the multicast, and one for the tcp protocol?
Is it possible to allow the server\client to listen for different communication (multicast or tcp) with treads?
I just need a litle push, and some basic code in order to begin this...
EDIT: OK, I succeeded to built a multicast comunication.
The agent goes up, and send every 5 seconds its name.
the server goes up, and receives the agent's broadcast.
If a new agent goes up, the server know about it.
The code look like this:
Agent code:
import java.io.BufferedReader;
import java.io.IOException;
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.util.Scanner;
public class Agent {
private static int portMulticasting = 1004;
private DatagramSocket socket;
private boolean broadcast = true;
private String group = "230.0.0.1"; //group address
private int delay = 5000;
public Agent(){
try{
socket = new DatagramSocket();
System.out.println("agent ready");
}
catch (SocketException e){
e.printStackTrace();
System.exit(1);
}
}
public void start(String agentName){
DatagramPacket packet;
try{
InetAddress address = InetAddress.getByName(group);
while (broadcast){
byte[] buf = new byte[256];
buf = agentName.getBytes();
packet = new DatagramPacket(buf,buf.length,address,portMulticasting);
socket.send(packet);
try{
Thread.sleep(delay);
} catch (InterruptedException e){
System.exit(0);
}
}
socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
public static void main (String[] args) throws IOException {
System.out.println("Enter name of the new agent: ");
Scanner sc = new Scanner(System.in);
String agentName = sc.nextLine();
Agent agent = new Agent();
agent.start(agentName);
}
}
Server Code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Server {
public static void main(String[] args) throws IOException {
String groupIP = "230.0.0.1";
int portMulticasting = 1004;
if (args.length > 0)
groupIP = args[0];
try{
//get a multicast socket and join group
MulticastSocket socket = new MulticastSocket(portMulticasting);
InetAddress group = InetAddress.getByName(groupIP);
socket.joinGroup(group);
//get packet
DatagramPacket packet;
while (true){
byte[] buf = new byte[256];
packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
buf = packet.getData();
int len = packet.getLength();
String received = (new String(buf)).substring(0,len);
try{
System.out.println("Agent name: " + received);
} catch (NumberFormatException e){
System.out.println("cannot interpret number");
}
}
socket.leaveGroup(group);
socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
Now, I want that the agents continue to send broadcast every 5 seconds, but meanwhile the server begin to work with the agents (send messages, ask for information from the agents etc).
Related
I have a network programming topic that requires file transfer using TCP and UDP. If TCP send fails then UDP will be executed. I have built each part but I am not sure how can I run the server of TCP and UDP at the same time to be able to receive data of both protocols (my problem is starting 2 server in the master server because I have as the interface). Hope everybody help please .
In one case you need to open a ServerSocket, in the other case a DatagramSocket. It should be possible to open them in parallel, which means you can run both your implementations in parallel running on different threads.
If you are suppose to run the TCP and the UDP Server on the same machine, you will need to use different ports. Then you can start up two different thread, one for each server:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
public class TcpUdpServer {
private final static int UDP_PORT = 8100;
private final static int TCP_PORT = 8200;
public static void main(String[] args) {
new Thread(() -> executeTcpServer()).start();
new Thread(() -> executeUdpServer()).start();
}
public static void executeTcpServer() {
try (ServerSocket serverSocket = new ServerSocket(TCP_PORT)) {
while (true) {
System.out.println("waiting for TCP connection...");
// Blocks until a connection is made
final Socket socket = serverSocket.accept();
final InputStream inputStream = socket.getInputStream();
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
System.out.println(text);
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static void executeUdpServer() {
try (DatagramSocket socket = new DatagramSocket(UDP_PORT)) {
while (true) {
byte[] packetBuffer = new byte[2024];
final DatagramPacket packet = new DatagramPacket(packetBuffer, packetBuffer.length);
System.out.println("waiting for UDP packet...");
// Blocks until a packet is received
socket.receive(packet);
final String receivedPacket = new String(packet.getData()).trim();
System.out.println(receivedPacket);
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
I am writing a program to send an integer (variable called intToSend) over a network using UDP. I run the program on two machines on the same network, one after the other. I thought that after running them both, the first one to be run would open a message box with the sent integer, but this doesn't happen. Both programs wait for a packet to be received as shown by "Waiting..." being printed to the console. I have the program ask for the destination ip to be input to the console. Then after that, the createSocket method is called, followed by sendData and then receiveData.
Here is the code:
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class Main {
Scanner s = new Scanner(System.in);
PrintStream o = System.out, e = System.err;
InetAddress thisAddr, destAddr;
DatagramSocket socket;
int port = 1729, intToSend = 8;
boolean running = true;
public static void main(String[] args) {
new Main();
}
private Main() {
try {
thisAddr = InetAddress.getLocalHost();
System.out.println("Internal IP: " + thisAddr.getHostAddress().toString());
System.out.println("External IP: " + getIp());
} catch (Exception e) {
e.printStackTrace();
}
try {
destAddr = InetAddress.getByName(getDestIp());
} catch (UnknownHostException e) {
e.printStackTrace();
}
createSocket();
sendData();
receiveData();
}
private void receiveData(){
byte[] receiveBuffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
while(true){
System.out.println("Waiting...");
try {
socket.receive(receivePacket);
} catch (IOException e) {
e.printStackTrace();
}
String receivedText = new String(receivePacket.getData());
JOptionPane.showMessageDialog(null, receivedText);
}
}
private void sendData(){
byte[] dataToSend = String.valueOf(intToSend).getBytes();
DatagramPacket packet = new DatagramPacket(dataToSend, dataToSend.length, destAddr, port);
try {
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
private void createSocket(){
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
public static String getIp() throws IOException{
URL whatismyip = new URL("http://icanhazip.com");
BufferedReader in = new BufferedReader(new InputStreamReader(whatismyip.openStream()));
return in.readLine();
}
private String getDestIp() {
String temp;
o.println("What is the other user's ip?");
temp = s.nextLine();
return temp;
}
}
This code works for me. If I input the target IP as the local machine's IP then I get the popup. If I input another machine on the network I also get the popup. My guess would be that either one of your machines has a firewall running that is blocking the incoming UDP packet, or your machines have multiple network interfaces and the IP you detect is not the one that is on the same network as the other machine.
In the former case you can disable the firewall (not a good idea if your machines are not behind a router with a firewall or are on a network which you don't have full control over) or open the specific port for incoming and outgoing UDP on both machines.
In the latter case you want to look out for the IPs presented on both machines being on the same subnet (the first three numbers being the same in the case if IPv4) e.g. both starting with 192.168.1. or similar.
When you do get your packet through you will probably get a very long popup window because you allocate a 1024 byte array and put the string at the start of that array but then convert the entire 1024 byte array into a string which may include various stuff off the end of the first N bytes you wrote the int into.
There are various ways to resolve that but this but a simple way to be able to pack a bunch of data into a packet and then read it back reliably is to use ByteArrayInput/OutputStreams and DataInput/OutputStreams:
//Sending side
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
dout.writeInt(N); //this will write 4 bytes
byte[] packetData = bout.toByteArray();
//Receiving side
byte[] packetBuffer = ...;
ByteArrayInputStream bin = new ByteArrayInputStream(packetBuffer);
DataInputStream din = new DataInputStream(bin);
int N = din.readInt(); //This will read only the first 4 bytes, and use the same marshalling as DataOutputStream to produce a consistent value, even if the integer value is something exceptional like infinity or NaN.
So there this problem that has been giving me headaches for days now.I am making a multi-user chat application.My design is as follows:
1.There is a login window.
2.As soon as the details are entered, the client-side chat window opens.
3.Now the user starts typing.
4.As soon as he hits enter or clicks on the send button,the message is sent to the server.
5.The server sends it to all clients, including the one that send it the original message.
The problem:I am unable to receive any messages from the server to the client.
Here is my server class:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server implements Runnable {
static InetAddress address;
static ArrayList<Integer> clients=new ArrayList<Integer>();
static ArrayList<Socket> socs=new ArrayList<>();
static String message="";
static DataOutputStream toClient;
static ServerSocket socket;
static Socket socketNew;
static boolean running=false;
public static void main(String[] args) throws IOException
{
socket=new ServerSocket(8000);
System.out.println("Server started on port 8000");
running=true;
while(true)
{
socketNew=socket.accept();
socs.add(socketNew);
address=socketNew.getInetAddress();
System.out.println("connected to client at address: "+address);
Server server=new Server();
new Thread(server).start();
}
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socketNew.getInputStream()));
String message;
PrintWriter out;
while ((message = br.readLine()) != null) {
System.out.println(message);
for (Socket s : socs) // sending the above msg. to all clients
{
out = new PrintWriter(s.getOutputStream(), true);
out.write(message);
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
And here is the receive_message function in the client class.Note that this method,I've run on a separate thread that starts as soon as the user logs-in.
public void receive_data()
{while(true)
{
try {
BufferedReader in;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(in.readLine()!=null)
{
System.out.println(in.readLine());
console(in.readLine());
}
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
Any suggestions?Thanks for your time. :-)
You are writing messages without a line ending, while your client is waiting for a line ending character in the readLine loop. By placing out.write('\n') in your server send loop, it will also send a newline character.
Example:
for (Socket s : socs) {
out = new PrintWriter(s.getOutputStream(), true);
out.write(message);
out.write('\n'); // added this line
out.flush();
}
I have a question with java sockets. My code sends messages to all clients, including sending. I want him to send only for other clients How can I do this? I test using telnet 127.0.0.1 2015 command in the terminal.
Client
package socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Clientes implements Runnable {
public Socket cliente;
public Clientes(Socket cliente) {
this.cliente = cliente;
}
public void run() {
try {
PrintWriter out = new PrintWriter(cliente.getOutputStream(), true);
out.write("---Seja Bem Vindo---\n");
out.flush();
System.out.println("Nova conexao: "
+ this.cliente.getInetAddress().getHostAddress());
while (true) {
BufferedReader in = new BufferedReader(new InputStreamReader(
cliente.getInputStream()));
String veioDoCliente = in.readLine();
if(veioDoCliente.equalsIgnoreCase("SAIR")){
cliente.close();
break;
}
System.out.println("MSG vinda do cliente " + veioDoCliente);
for (Clientes writer : Servidor.clientes) {
PrintWriter out2 = new PrintWriter(writer.cliente.getOutputStream(), true);
out2.write("teste:"+veioDoCliente+"\n");
out2.flush();
}
//s.close();
//this.cliente.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server
package socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Servidor {
public Socket cliente;
public Servidor(Socket cliente) {
this.cliente = cliente;
}
public static List<Clientes> clientes = new ArrayList<Clientes>();
public static void main(String[] args) throws IOException {
ServerSocket servidor = new ServerSocket(2015);
System.out.println("Esperando alguem se conectar...");
while (true) {
Socket cliente = servidor.accept();
Clientes tratamento = new Clientes(cliente);
clientes.add(tratamento);
Thread t = new Thread(tratamento);
t.start();
}
}
}
I'm not seeing where your server is handling the code coming in, so I'm shooting in the dark.
Basically, when your data comes in, you see which client it originated from and then check in your loop to see if that client matches the current client. If no match, then send the data out.
If not possible any other way, you will need to give each client and ID and it will send the data with the ID string, but I'm sure that you can keep track of your clients using the socket.
I'm experiencing a weird issue, and I can't figure out what is occurring.
So basically, when I try to make a simple connection between a server and a client with an exchange of a float number (with DataInputStream and DataOutputStream), it seems that there is a fixed ping limit, exactly 40ms on three different computers with openjdk.
Furthermore, I tried to change the way I send the float number with:
outs.write(ByteBuffer.allocate(4).putFloat(3.14f).array(), 0, 4);
which is supposed to do the same thing as:
outs.writeFloat(3.14f);
and this odd ping limit surprisingly vanished!
Maybe I am doing something wrong with the following code:
client side
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.nio.ByteBuffer;
public class client {
private Socket sock;
private DataOutputStream outs;
private DataInputStream ins;
public client() throws IOException{
byte c;
sock = new Socket(InetAddress.getByName("localhost"),9998);
outs = new DataOutputStream(sock.getOutputStream());
ins = new DataInputStream(sock.getInputStream());
do{
long start = System.currentTimeMillis();
/* here is the thing */
//outs.write(ByteBuffer.allocate(4).putFloat(3.14f).array(), 0, 4); // either this outs
outs.writeFloat(3.14f); // or this one
outs.flush();
c = ins.readByte();
long stop = System.currentTimeMillis();
System.out.println("elapsed time: "+(stop-start)+"ms");
}while(c == (byte) 1);
}
public static void main(String[] args) {
try{
client client = new client();
} catch(SocketException e){
System.out.println("Socket disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
}
server
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
public class server extends Thread{
private DataOutputStream outs;
private DataInputStream ins;
public server(Socket sock) throws IOException{
System.out.println("client connected");
outs = new DataOutputStream(sock.getOutputStream());
ins = new DataInputStream(sock.getInputStream());
}
public void run(){
try{
while(true){
float f = ins.readFloat();
System.out.println("value: "+f);
outs.writeByte((byte) 1);
outs.flush();
}
} catch (IOException e) {
System.out.println("client disconnected");
}
}
public static void main(String[] args) {
try{
ServerSocket serverSock = new ServerSocket(9998);
while(true){
server server = new server(serverSock.accept());
server.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
which gives me (on localhost) with the usual writeFloat:
elapsed time: 40ms
else with write():
elapsed time: 0ms
Edit :
Apparently, it seems that Mike's answer solved the issue! No more 40ms latency with writeFloat...
Windows? Try to increase the number of bytes you send. There is (or was) a limit within the Windows TCP/IP stack, which waits for an amount of time the get get more bytes to get a full Package to send.