I am trying to simulate UDP using Java. I am sending a file from one host to another. This is the part of the receiver:
server.setSoTimeout(10000);
while (true)
{
try
{
DatagramPacket received = new DatagramPacket(receivedData,receivedData.length);
server.receive(received);
out.write(received.getData());
}
catch (IOException e) {
break;
}
}
server.close();
This solution works, but I am not satisfied with it for some reason.
Sender sends all the packets and then it closes the DatagramSocket. Receiver gets all the packets and it terminates, but it terminates because of the timeout.
So if switch on my receiver and don't execute anything for 10 secs, my Receiver shuts off, so nothing is transmitted.
Is there a way of terminating the loop without specifying the timeout?
I was also wondering if there is a method for the other host to establish connection - something like ServerSocket.accept(), which basically waits for the other host to connect.But, I decided to use DatagramSocket and I can't find a solution to this issue.
Does anybody know of a method that would perform this?
No.
Datagram (UDP) sockets are inherently connectionless. Closing a DatagramSocket does not have any effect which is visible to a remote system. It prevents an application from sending or receiving any further data on that socket, and frees up the port for use by other applications on the local system, but it does not cause any notification to be sent over the network.
If you want to notify the remote server that you are done sending data, you will need to send them a datagram notifying them of that.
If you are trying to transfer a file over UDP, keep in mind that UDP packets are not guaranteed to be received, nor are they guaranteed to be received in the same order they are transmitted! (That is, they may be dropped or reordered by the network.)
Related
There is the connecting timeout value passed to connect method, and there is the reading timeout set using setSoTimeout method. I was wondering why there is no method to set the "writing timeout"? I think there is the writing timeout concept in the TCP Protocol.
It wouldn't be much use.
In general TCP sending is asynchronous to the application. All that send() does is put the data into the socket send buffer. It then returns, while the send buffer is emptied to the network asynchronously. So there is nothing to timeout. And the absence of a timeout does not denote that the data has been sent to the peer.
send() blocks while the send buffer is full, and it would be possible to implement a timeout on that, and indeed you can do that yourself in non-blocking mode with select(), but the problem is that what timed out could be either the current send or a prior one. So delivering a timeout would be rather confusing. Instead what is delivered when all the TCP send timers time out internally is a connection reset.
I think there is the writing timeout concept in the TCP Protocol.
There is indeed, but that's at the level where TCP is asynchronously emptying the socket send buffer. It isn't under application control.
you can first try to connect...if connect fails catch exception
InetSocketAddress sockAdr = new InetSocketAddress(serveradres, 2222);
Socket newsok = new Socket();
int timeout = 2000;
newsok.connect(sockAdr, timeout);
I'm in the process of writing a messaging program, and I'm running into a spot where I'm having trouble understanding how to pass a socket over to a new thread for handling outbound messages via TCP. I'm currently using UDP packets for messages coming from a client, to the server, which, being UDP, doesn't require very much processing, as it's simply listening for incoming packets, before it de-serializes the objects, and processes them as needed in a separate thread. My problem now is, I'm setting up a client initiated TCP socket for reverse traffic, from the server to the assorted clients that connect. I've done a bit of research, and I already understood that each client should have their own thread for handling outgoing messages, along with another thread simply for accepting the incoming connections. I'm unsure of how to actually achieve this, and I've done some research into the topic.
I've found this: http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
The resource above basically verified my original suspicion that this would have to be handled by threads dedicated to the client. They included psuedo code here, which is representing my listener thread.
while (true) {
accept a connection;
create a thread to deal with the client;
}
I'm a bit of a visual learner, and I have been searching for some type of an example where this is done. I'm unsure of what variable I'd be passing over to the thread that keeps the original connection open, and pushes data back to clients. I'm also having a little bit of trouble grasping whether it even keeps the same socket open, or if a new one needs to be established, which then, makes me believe a firewall could interfere, but I know that won't be the case.
Can somebody explain this for me in detail? If possible, an example would be greatly appreciated!
I'll be likely replying and commenting on responses in about 15-30 minutes from the time this is posted.
What you are doing sounds correct. I typically implement a server like this (simplified version with no tracking of the clients and so on):
#Override
public void run() {
//start listening on the port
try {
serverSocket = new ServerSocket(port);
logger.info("Listening for connections on port " + port);
} catch (IOException e) {
logger.error("Cannot start SocketListener on port " + port + ". Stopping.", e);
return;
}
while (!stopped) {
try {
//wait for connection
Socket newSocket = serverSocket.accept();
ClientThread client = new ClientThread(newSocket);
Thread clientThread = new Thread(client, MEANINGFUL_THREAD_ID);
clientThread.start();
} catch ...
}
}
where serverSocket is a ServerSocket instance variable and stopped is a flag I use to stop the listener thread.
So to answer your questions in the comment, you normally pass the Socket object to each client thread so that that thread can work with the input and output stream and handle closing of the socket and so on. Once you "accept" a socket connection, you do not need to recreate the ServerSocket, you simply call .accept() again to start waiting for a new connection.
In most cases, you will need to keep track of all client threads in your server so that you can stop the server gracefully or do broadcasts for example.
public static void main(String args[]){
byte[] message = ...
Socket socket = ...
DataOutputStream dOut = new DataOutputStream(socket.getOutputStream());
dOut.write(message); //#1
dOut.close();
socket.close();
}
Let's assume that the line #1 will put the data into buffer waiting to flush to remote machine. After that the stream and socket are closed.
We assume that, in the sending process, there is some unknown problem happens in network, and our operating system will resend the packet that was in the buffer until the TCP re-tranmission timeout.
I am wondering that how I can catch this exception in Java program? Because the code above already send out data to buffer and probably closed the stream and socket (and probably exit the Java main body), left all the other job (TCP-related, re-tranmission) to operating system.
My question is, will the TCP re-tranmission (we assume packet lost) continue even Java program exit? What is the best method to catch the re-tranmission timeout error?
TCP will continue to try to cleanly shutdown the connection even after the program exits. It is generally recommended that the application perform the shutdown itself. Basically, you perform the following sequence of steps:
Shutdown the TCP connection in the send direction triggering the normal close sequence. If the protocol prohibits the other side from sending any data, you can shutdown the connection in the receive direction as well, however, if you do this and the other side sends any data, it may cause the other side to detect an abnormal shutdown as the data it sent will be lost.
Continue to read from the connection until you detect a clean or abnormal shutdown from the other end. If all goes well, you will detect a clean shutdown as soon as you finish receiving any data the other side has sent.
Close the handle or delete the object/reference to the connection. The actual TCP connection is already shut down.
I am implementing the TFTP (trivial FTP) protocol in Java. I have a client and a server, and so far the client can request a file and the server sends him that data.
Here is where I hit my problem - for obvious testing reasons, I run both the client and the server on my machine. However, when sending a file, there have to be two sockets listening on the same port:
the client needs to listen for received data packages
the server needs to listen for the client's acknowledgements
...and also two respective sockets for sending data and acknowledgements, also sharing a port.
This normally does happen on the same port, but on different machines. Is there a way to get around this, and make both client and server work peacefully on the same host, without any ugly hacks? And by ugly hacks I mean something like:
predefined offset for the ACK communication port (such as +15 over the data port; this is what I'm currently using now. It sort of works but it feels wrong and is error-prone)
repeatedly closing and opening sockets (send data, close socket used to send data so that the client can use that port to send his ACK, etc.); this also works at the moment, but also via a hack. Here is, for example, how I "reopen" a socket used for sending things:
public void open() {
try {
socket = new DatagramSocket(localPortCache);
} catch (SocketException e) {
e.printStackTrace();
}
}
This is evil. My sockets, originally, receive dynamically-allocated ephemeral port numbers. I then memorize that value and use it to "restore" my socket to the old port. However, it can't be guaranteed that that port is still available. It usually is, but there's no guarantee. Am I being overly-paranoid in this case?
generating a new ACK-communication port in the handshake and send it to the client via the control port (69) in an additional step
Update:
I have managed to fix my problem. My issue was that I wasn't trying to reuse my sockets. For instance, I sent something from a socket on port X, but then tried to allocate a new socket on that port to listen for the ACK, instead of just reusing the old socket.
The client doesn't need to use a fixed port number. Just bind it to zero. The server should send the response back to the originating client whatever its port number.
I would like to have this setup:
Server hosting TCP socket server
Multiple clients connected over TCP (keeping connection open)
Then I would like to initiate a message from the Server to the client. I can't figure out how to do this, and have multiple client sessions at the same time. Techniques I've read involve the Server listening on a port, and when it receives communicate from a client, it launches a new thread to handle and process that, and then it goes back to listening on the port for the next request of another client.
So, then how would I tap into that and send a message to a client running on one of those threads?
My actual usage scenario if you are interested is below. Final goal is like a remote control for your file system to upload files to the server.
- Each client has a java background application running in the system tray that connects to the server
- Server hosts connections, and also hosts a RESTFul webservice to initiate communication
- Mobile device connects to Server over RESTFul webservices to request informatino about the client's filesystem. So it can drill down and find a file, then click and have the file uploaded to the server.
The idea here is mobile users needing to upload files from their desktop to the server while away from their office on a mobile device. (and this is for custom product, so can't use a third-party app_
PS: I've been looking at the simple Client-Server chat program here: http://way2java.com/networking/chat-program-two-way-communication/
You want to have a server listening at all times on a specified port. Once the server notices an incoming connection on that port you should create a new Thread to handle the communication between that client and the server, while the main thread keeps on listening for other incoming connections. This way you can have multiple clients connected to one server. Like so:
private void listen() throws IOException {
serverSocket = new ServerSocket(port)
while (GlobalFlags.listening) {
new ServerThread(serverSocket.accept();
if (GlobalFlags.exit) {
serverSocket.close();
break;
}
}
}
Where the GlobalFlags are variables to control the listening process and are not really necessary. You could do a while True and just keep listening for ever and ever.
In my project I have a main server controller which had listeners running in Threads. The controller controlled the GlobalFlags. I'm sure instead of using global flags there is a better way to do inter thread communication but for me this was the simplest at the time.
The ServerThread should be looping all the time switching between sending output to the client and receiving input from the client. Like so:
ServerThread(Socket socket) {
super("GameServerThread");
this.socket = socket;
try {
this.socket.setTcpNoDelay(true);
} catch (SocketException e) {
// Error handling
}
this.terminate = false;
}
#Override
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
while ((inputLine = in.readLine()) != null) {
outputLine = processInput(inputLine);
out.println(outputLine);
if (terminate) {
break;
}
}
}
out.close();
in.close();
socket.close();
} catch (Exception e) {
// Error handling, should not use Exception but handle all exceptions by themselves.
}
On the client side you have a thread running through a similar loop, receiving input from the server and then sending output to the server.
In this example processInput is the function used to process the client's input. If you want the server to initiate contact you can make the server send something to the outputstream before listening for input and make the client listen first.
I have extracted this example from one of my own projects and the this.socket.setTcpNoDelay(true) is supposed to make the process faster. Reference here: http://www.rgagnon.com/javadetails/java-0294.html
"java.net.Socket.setTcpNoDelay() is used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm.
Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase in bandwidth consumption. The Nagle's algorithm is described in RFC 896.
You get the current "TCP_NODELAY" setting with java.net.Socket.getTcpNoDelay()"
So to send a message to a specific client you could put all the threads upon creation in an ArrayList so you can keep track of all the currently connected clients. You can have the processInput method halt and polling a queue/variable until another class puts the message to be send in the queue/variable. So how to gain a handle on the class depends on your implementation of processInput. You could give every thread an ID (which is what I did in my project) and maybe have the processInput method poll an ArrayList at index=ID. Then to send output to the client you would have to set the variable at index=ID.
This method seems kind of clunky to me personally but I'm not really sure how else I would do it. You would probably use Queues and have processInput write the input to its Queue and then wait for another class to read it and put its response in the Queue. But I have personally never worked with Queues in java so you should read up on that yourself.
In my knowledge
1) Server hosting TCP socket server -- Possible
2) Multiple clients connected over TCP -- Possible
3) Then I would like to initiate a message from the Server to the client -- Not Possible. The Client has to initiate a connection creation, then the server might be able to send data packets to You. Example: You need to open Facebook website on your browser, Facebook server cannot decide to send its page to your PC on its own because your PC will not have a static IP address, and also if Facebook hypothetically writes code to initiate connection to Your PC, then it is as good as Your PC is the server and Facebook website/server acts as client.