I have a simple working program that can transfer files with UDP . But for each client and server, I have two sockets which send data at a port and receive data at a different port.
For example, my client socket_out sends data packet at port 9000 and receives data with socket_in which listens at port 9001. My server socket_in listens at port 9000 and sends ACK data packet at port 9001.
Now I want to simplify the design and use only one port number for receiving and sending messages at each client and server. For example, both client and server program sends and receives data at port 9000.
Is it possible to do that? How should I make the change? I tried to create two socket for send and receiving at the same port number, but I always get this error:
java.net.BindException: Address already in use
I googled found out two sockets cant share the same port number.
Adding on the code:
Sender:
public FileSender(String fileName, int unrelPort, String rcvFileName) {
DatagramSocket socket_out_client, socket_in_client;
System.out.println("Start Sending " + fileName + " through port " +unrelPort + " as " + rcvFileName + ".");
try {
// create sockets
socket_out_client = new DatagramSocket();
socket_in_client = new DatagramSocket(unrelPort);
// create input file
File inputFile = new File(fileName);
if (!inputFile.exists()) {
System.err.println("Input file does not exist");
System.exit(-1);
}
// create threads to process data
InThread th_in = new InThread(socket_out_client,socket_in_client);
OutThread th_out = new OutThread(socket_in_client, unrelPort, inputFile, rcvFileName);
th_in.start();
th_out.start();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
Same for receiver
A port number is a number embedded in the network packets. Once a computer's operating system processes an inbound network packet, it needs to "know" which program to pass the pack to as input. The port number is used to lookup the program in the receiving operating system's port to program table.
That's why you cannot have two programs reading from the same port, as that roughly makes it impossible for the operating system to determine which of the two programs the packet should be sent to as input.
Note that this is not the only way you can get a port conflict. You could just have two copies of the program running on the same machine too.
First of all why did you create two sockets at client side for sending and receiving when you can use same socket_client to send and receive. You can do this by creating two threads one for sending and one for receiving with the same socket_client.
code: something like this
DatagramSocket sock = new DatagramSocket();
new Thread(new Runnable() {
#Override
public void run() {
try{
//create packet
//your logic
sock.send(packet);
}
}catch(Exception e){}
}
}).start();
System.out.println("Debug :: "+"thread 1 started");
new Thread(new Runnable() {
#Override
public void run() {
try{
//your logic
sock.receive(packet)
}
}catch(Exception e){}
}
}).start();
System.out.println("Debug :: "+"thread 2 started");
Related
I've just started with both java and networking with servers and clients. Although i understand the basics of whats going on, i was struggling to put it all together and do what i wanted to do in the title.
I was able to make this to send a message to the server, however i was wondering how i'd turn the message into a input string from the user, and also how id send multiple messages between the client and server
thanks
SERVER
import java.io.*;
import java.net.*;
public class Server {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
//Remember to close the socket once we have finished with it.
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
CLIENT
import java.io.*;
import java.net.*;
public class Client {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
//ServerIP:- IP address of the server.
String serverIP = "localhost";
try{
//Create a new socket for communication
Socket soc = new Socket(serverIP,portNumber);
//Create the outputstream to send data through
DataOutputStream dataOut = new DataOutputStream(soc.getOutputStream());
//Write message to output stream and send through socket
dataOut.writeUTF("Hello other world!");
dataOut.flush();
//close the data stream and socket
dataOut.close();
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
There are some "problems" with your code.
You should only close the ServerSocket if you are done.
You should handle the newly connected client inside a thread to allow multiple clients to simultaniously "send messages".
1.
you could easily wrap your code inside an while loop.
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
//Remember to close the socket once we have finished with it.
soc.close();
}
Now your programm should continue to accept clients. But only one at a time. You can now terminate the Server by stopping the programm or by changing the someCondition to false and accepting the next client.
A bit more advanced would be, to shutdown the ServerSocket to stop the programm and catching the exception inside the while loop.
2.
To allow multiple clients to be handled simultaniously, you should pack the handle part into another Thread.
private ExecutorService threadPool = Executors.newCachedThreadPool();
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console in a new Thread.
threadPool.submit(() -> {
DataInputStream dataIn = new
DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
}
//Remember to close the socket once we have finished with it.
soc.close();
}
The part inside the threadPool.submit block could be specified as an custom instance of the Runnable interface of as an method, to call it using method reference.
I assumed you are knowing about ThreadPools. They have multiple advantages over Threads
This should get you going for any number of clients.
Note: This is not good designed, but it is for demonstrational porpurses only.
I tried to find in exact solution for this problem but I'm not able to find it
I have written a while loop to accept client sockets in server program
because of this I'm unable to close the serversocket as it is always listening
here is my server code
public class nserver {
public static void main(String[] args) throws IOException {
int port=4413;
//server is running on port
try(ServerSocket ss = new ServerSocket(port)){;
// socket accepts data from the incoming clients
while(true){
Socket socket = ss.accept();
// id I don't put the if case then this loop never breaks and
// although I wrote ss.close() - it will never reached - so use if case
if(socket.equals(null))
break;
System.out.println("Server is running on port "+port);
//socket.getInetAddress gives address of client ip not the server ip as the socket is mada as client socket
System.out.println("server recieved connection from "+socket.getInetAddress()+" : "+socket.getPort());
//create two threads to send and receive from client
rxClientData rx = new rxClientData(socket);
Thread t = new Thread(rx);
t.start();
sdServerData sd = new sdServerData(socket);
Thread t2 = new Thread(sd);
t2.start();
// if I put ss.close() here then it will accept only one client socket and serversocket will be closed after this line
}
ss.close();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
}
how to close serversocket after my client socket requests,I have 3 clients
with for loop I will have a limit of no.of client sockets,but a server should accept so many no.of requests - so I used while loop
for a server do we need to keep serversocket open in real world scenario ? - so that it accepts client requests all the time
I have a server-client application set. (HOMEWORK)
So far I have figured out how to have multiple clients connect to the server and have the server aggregate the messages the clients send, as well as having the server send the client's message back to the client and displaying it in the chat pane.
My issue is trying to send a message to multiple clients. I am only allowed to use ServerSocket and Socket libraries.
Say I have 2 clients connected to the server. One client sends a message, the message is displayed in the client's chat. The second client sends a message, the first client does NOT receive it, and the second client's chat window displays the first client's message.
Essentially the server is sending the most recent message that the respective client has not displayed in the chatbox, and I have no idea why or how.
Code for server-to-client communication :
Class CommunicationThread extends Thread {
//Vector containing all client sockets currently connected
//Held offsite, here for clarity
public Vector<Socket> socketVector;
public CommunicationThread (Socket clientSoc, Server ec3, Vector<Socket>socketVectorg)
{
//add new socket to vector, start thread
clientSocket = clientSoc;
socketVectorg.add(clientSocket);
this.socketVector = socketVectorg;
gui = ec3;
}
public void run()
{
System.out.println ("New Communication Thread Started");
try {
//Client's chat box (output)
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
//Input line from client
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
gui.history.insert(inputLine + "\n", 0);
//*************HERE IS MY ISSUE*******************
for(Socket s : socketVector){
out = new PrintWriter(s.getOutputStream(),
true);
out.println(inputLine);
}
if (inputLine.equals("Bye."))
break;
if (inputLine.equals("End Server."))
gui.serverContinue = false;
}
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
System.err.println("Problem with Communication Server");
//System.exit(1);
}
}
}
I know I am overwriting "out" but I don't think that is my issue so it is in my code while I am testing.
My issue is marked in the code above. The vector accurately stores the socket ID, and since I am creating a new PrinterWriter based on the vector, I would only assume that it would get the output field of the respective client, but it does not.
My intuition is that it is a problem with threading or closing the output, but I honestly don't know.
Any recommendations are appreciated.
Your problem it seems to me is that you want to do the input and output work on the client socket all in the same place, and there's no need for that. The client socket's output stream can be written to in the GUI thread, and all in one place. You can keep a collection of the output streams if need be and when you want to reply to all, iterate through the collection (probably a HashMap<String, OutpuStream> where the String is some client identifier) and send the messages.
I am trying to implement a method that sends an UDP packet to multiple receivers. I thought that this should be doable setting setReuseAddress(true) on the receiving DatagramSocket instances.
My problem is that in certain conditions I need to limit the communication to the local computer - hence the localhost interface (useLocalhost=true in the demo code below). In such a case suddenly only the first receiver socket gets the incoming packet, the two other don't see anything.
I tested this on Windows (oracle 64bit) and Linux (OpenJDK 64bit), therefore I only see three possibilities:
This is an intended and known behavior (and I don't understand the whole mechanism - aka "bug in my brain")
There is a bug in the Java JRE
There is a bug in my code.
Does somebody have any experience on that topic and can me help to identify where the problem is located?
See below a minimal working example that demonstrates this. Note that I am using the broadcast address for simulating network packets that come from a real external host.
If everything goes right you should see three lines at the end (in this or a different order):
Thread-0 - packet received
Thread-1 - packet received
Thread-2 - packet received
public static void main(String[] args) throws Exception {
boolean useLocalhost = true;
InetSocketAddress addr;
String sendPacketTo = "192.168.1.255"; // we use broadcast so that packet comes from an real external address
if (useLocalhost)
sendPacketTo = "localhost"; // does not work (only listener 1 received packet)
addr = new InetSocketAddress(15002);
new MyThread(addr).start(); // Datagram socket listener 1
new MyThread(addr).start(); // Datagram socket listener 2
new MyThread(addr).start(); // Datagram socket listener 3
DatagramSocket so = new DatagramSocket();
so.setBroadcast(true); // does not change anything
so.connect(new InetSocketAddress(sendPacketTo, 15002));
so.send(new DatagramPacket("test".getBytes(), 4));
Thread.sleep(1000);
System.exit(0);
}
public static class MyThread extends Thread {
DatagramSocket socket;
public MyThread(InetSocketAddress addr) throws SocketException {
super();
setDaemon(true);
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setBroadcast(true); // does not change anything
socket.bind(addr);
System.out.println("Listener started: " + socket.getLocalAddress());
}
public void run() {
byte[] buf = new byte[10];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
socket.receive(p);
System.out.println(Thread.currentThread().getName() + " - packet received");
} catch (IOException e) {
e.printStackTrace();
}
}
}
192.168.1.255 is a broadcast address, so the datagram is broadcast, under the rules for UDP broadcast. 127.0.0.1 is a unicast address, so the packet is unicast. So you get different behaviour.
As #DavidSchwartz commented, your code is a mixture. Connecting to a broadcast address for example doesn't have a lot of meaning, and neither does binding to it. I think what you are looking for is multicast.
You can use multicast on localhost
However, there are several things you need to be careful of to make it work.
example:
lo0 (127.0.0.1)
en0 (192.168.0.111)
en1 (10.1.0.111)
for each interface 2 separate sockets, one for receiving, one for
sending. In the above example this means creating a total of 6
sockets.
Never bind() a socket that will send multicast UDP packets.
Always bind() a socket that will receive multicast UDP packets.
Never try to setsockopt() or reconfigure multicast sockets after you call bind()
Instead, when machine's interfaces change due to cables being unplugged/plugged,
destroy all send/receive multicast sockets and recreate them.
sample code:
iMulticastSocketInterfaceIPAddress would be one of the three interfaces
/* use setsockopt() to request that the kernel join a multicast group */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr( "239.192.0.133" );
myAddress.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
mreq.imr_interface.s_addr=( htonl(iMulticastSocketInterfaceIPAddress) );
theErr = setsockopt( CFSocketGetNative( mSocketBroadcast ) ,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
I have a java server which is using TCP and sockets to connect to an Android application (the client) and sends strings (currently taken in from a scanner object) which are then displayed as notifications by the client.
heres the Server code without all the imports.
public class Server {
// define our Main method
public static void main(String[] args) throws IOException {
// set up our Server Socket, set to null for the moment.
ServerSocket serverSocket = null;
boolean isConnected = false;
// Lets try and instantiate our server and define a port number .
try {
serverSocket = new ServerSocket(6789);
isConnected = true;
System.out.println("*** I am the Server ***\n");
// make sure to always catch any exceptions that may occur.
} catch (IOException e) {
// always print error to "System.err"
System.err.println("Could not listen on port: 6789.");
System.exit(1);
}
// We always want to check for connection from Clients, so lets define
// a for ever loop.
for (;;) {
// define a local client socket
Socket clientSocket = null;
// lets see if there are any connections and if so, accept it.
try {
clientSocket = serverSocket.accept();
// don't forget to catch your exceptions
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Prepare the input & output streams via the client socket.
// fancy way of saying we want to be able to read and write data to
// the client socket that is connected.
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
PrintWriter outToClient = new PrintWriter(clientSocket.getOutputStream(),
true);
while (isConnected) {
// read a sentence from client
String hiFromClient = inFromClient.readLine();
// Set up the logging system and timestamp and log message.
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter=
new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss");
String dateNow = formatter.format(currentDate.getTime());
try{
// Create file
File fstream = new File("log.txt");
FileWriter out = new FileWriter(fstream);
out.write(hiFromClient + " " + dateNow);
//Close the output stream
out.close();
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
// Print the client sentence to the screen
System.out.println("The Client said: "+hiFromClient);
// Reply to the client
Scanner scanner = new Scanner(System.in);
String sentence = scanner.nextLine();
outToClient.println(sentence );
System.out.println("The Server said: " + sentence);
}
// always remember to close all connections.
inFromClient.close(); // the reader
outToClient.close(); // the writer
clientSocket.close(); // and the client socket
}
}}
Growl uses port 23053 for notification forwarding. What i am hoping to do is to listen in on 23053 and send anything in from that as a string to the client connected at 6789. Sadly Growl binds the port number so a new Socket connection cant be made.
Any one have any ideas on how i could get notifications from the port number growl uses or even just use growl as the server for the client itself (the client's code is very similar to the servers by the way just using Socket instead of ServerSocket)
Any help on this would be greatly appreciated, its wrecking my brain
All the best,
Patrick.
There is a round-about way you could do it. If you are desperate, read on:
Growl can forward any notifications it receives to another machine running Growl (configured on the Network tab). Growl uses the GNTP protocol (a TCP-based protocol: http://www.growlforwindows.com/gfw/help/gntp.aspx) to forward the messages. The trick is that that 'other machine running Growl' doesnt have to really be another machine OR running Growl per se, it just needs to appear to Growl that it is. Growl (on the Mac, which is what I assume you are using) will automatically detect any other machines on the network running Growl (using Bonjour and looking for the _gntp._tcp service name), so if your server advertises itself as supporting the GNTP protocol, Growl should show it in the list of available destinations. (Growl for Windows also lets you manually add a hostname/port to forward to, but I dont believe the Mac version currently allows that).
So then you could configure Growl to forward notifications to your server using its already-built-in capabilities. You would have to implement code in your server to receive the GNTP packets (the format is very similar to HTTP headers) and parse them. Then you could forward the notifications using your current server code.
Still with me? I did say it was round-about, but it is not only technically possible, but I have built a Growl-impersonating daemon before so that I could have notifications forwarded from Growl to my custom code. Not suggesting it as the best idea, but just an alternative since you asked.