Java: Multithreading & UDP Socket Programming - java

I am new to multithreading & socket programming in Java. I would like to know what is the best way to implement 2 threads - one for receiving a socket and one for sending a socket. If what I am trying to do sounds absurd, pls let me know why! The code is largely inspired from Sun's tutorials online.I want to use Multicast sockets so that I can work with a multicast group.
class Server extends Thread
{
static protected MulticastSocket socket = null;
protected BufferedReader in = null;
public InetAddress group;
private static class Receive implements Runnable
{
public void run()
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
socket.receive(pkt);
String received = new String(pkt.getData(),0,pkt.getLength());
System.out.println("From server#" + received);
Thread.sleep(1000);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
}
public Server() throws IOException
{
super("server");
socket = new MulticastSocket(4446);
group = InetAddress.getByName("239.231.12.3");
socket.joinGroup(group);
}
public void run()
{
while(1>0)
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
//String msg = reader.readLine();
String pid = ManagementFactory.getRuntimeMXBean().getName();
buf = pid.getBytes();
pkt = new DatagramPacket(buf,buf.length,group,4446);
socket.send(pkt);
Thread t = new Thread(new Receive());
t.start();
while(t.isAlive())
{
t.join(1000);
}
sleep(1);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
//socket.close();
}
public static void main(String[] args) throws IOException
{
new Server().start();
//System.out.println("Hello");
}
}

First thing is first: your classes should start with a capital letter per the Java Naming Conventions:
Class names should be nouns, in mixed case with the first letter of
each internal word capitalized. Try to
keep your class names simple and
descriptive. Use whole words-avoid
acronyms and abbreviations (unless the
abbreviation is much more widely used
than the long form, such as URL or
HTML).
Second:
Try to break down the code into coherent sections and organize them around some common feature that you're dealing with... perhaps around the functionality or the model you're programming.
The (basic) model for the server is that the only thing it does is receive socket connections... the server relies on a handler to handle those connections and that's it. If you try to build that model it would look something like this:
class Server{
private final ServerSocket serverSocket;
private final ExecutorService pool;
public Server(int port, int poolSize) throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void serve() {
try {
while(true) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// receive the datagram packets
}
}
Third: I would recommend that you look at some existing examples.
Multi-threaded Client/Server Applications:
http://www.ase.md/~aursu/ClientServerThreads.html
Doug Lea:
http://www.developer.com/java/ent/article.php/3645111/Java-5s-BlockingQueue.htm (thanks to John)
http://gee.cs.oswego.edu/dl/cpj/index.html (still can't find the exact example, but it's there somewhere... if you feel brave look over his allcode.java file).
Concurrency in Practice examples:
http://www.javaconcurrencyinpractice.com/listings.html
Java Concurrency Tutorials:
http://java.sun.com/docs/books/tutorial/essential/concurrency/
Updated per comments:
OK Ravi, there are some big issues with your code and some minor issues with it:
I assume that the Receive class is your client... you should pull that out as a separate program (with its own main class) and run your server and multiple clients at the same time. Spawning a new "client thread" from your server for every new UDP package you send is a disturbing idea (big issue).
When you make your client application, you should make it run the receiving code in its own while loop (minor issue), e.g.:
public class Client extends Thread
{
public Client(/*..*/)
{
// initialize your client
}
public void run()
{
while(true)
{
// receive UDP packets
// process the UDP packets
}
}
public static void main(String[] args) throws IOException
{
// start your client
new Client().start();
}
}
You should only need just one thread per client and one thread per server (you technically don't even a separate thread in there since main has its own thread), so you might not find the ExecutorService that useful.
Otherwise your approach is correct... but I would still recommend that you check out some of examples.

Wanting to create threads in an application is not absurd! You won't need exactly 2 threads, but I think you're talking about 2 classes that implement the Runnable interface.
The threading API has gotten better since Java 1.5 and you don't need to mess with java.lang.Thread anymore. You can simply create a java.util.concurrent.Executor and submit Runnable instances to it.
The book Java Concurrency in Practice uses that exact problem - creating a threaded socket server - and walks through several iterations of the code to show the best way to do it. Check out the free sample chapter, which is great. I won't copy/paste the code here, but look specifically at listing 6.8.

It's a good thing Eclipse's history works even for a day back :) Thanks to that, I am able to give both Ravi a working example and Lirik his answer on leakage.
Let me first start of by stating that I have no clue what is causing this leak, but if I leave it long enough, it will fail on a OutOfMemoryError.
Second, I left the working code commented out for Ravi for a working basic example of my UDP server. The timeout was there to test how long my firewall would kill the receivers end (30 seconds). Just remove anything with the pool, and you're good to go.
So here is, a working but leaking version of my example threaded UDP server.
public class TestServer {
private static Integer TIMEOUT = 30;
private final static int MAX_BUFFER_SIZE = 8192;
private final static int MAX_LISTENER_THREADS = 5;
private final static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSSZ");
private int mPort;
private DatagramSocket mSocket;
// You can remove this for a working version
private ExecutorService mPool;
public TestServer(int port) {
mPort = port;
try {
mSocket = new DatagramSocket(mPort);
mSocket.setReceiveBufferSize(MAX_BUFFER_SIZE);
mSocket.setSendBufferSize(MAX_BUFFER_SIZE);
mSocket.setSoTimeout(0);
// You can uncomment this for a working version
//for (int i = 0; i < MAX_LISTENER_THREADS; i++) {
// new Thread(new Listener(mSocket)).start();
//}
// You can remove this for a working version
mPool = Executors.newFixedThreadPool(MAX_LISTENER_THREADS);
} catch (IOException e) {
e.printStackTrace();
}
}
// You can remove this for a working version
public void start() {
try {
try {
while (true) {
mPool.execute(new Listener(mSocket));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
mPool.shutdown();
}
}
private class Listener implements Runnable {
private final DatagramSocket socket;
public Listener(DatagramSocket serverSocket) {
socket = serverSocket;
}
private String readLn(DatagramPacket packet) throws IOException {
socket.receive(packet);
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(packet.getData())), MAX_BUFFER_SIZE).readLine();
}
private void writeLn(DatagramPacket packet, String string) throws IOException {
packet.setData(string.concat("\r\n").getBytes());
socket.send(packet);
}
#Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
String s;
while (true) {
try {
packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
s = readLn(packet);
System.out.println(DateFormat.format(new Date()) + " Received: " + s);
Thread.sleep(TIMEOUT * 1000);
writeLn(packet, s);
System.out.println(DateFormat.format(new Date()) + " Sent: " + s);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
if (args.length == 1) {
try {
TIMEOUT = Integer.parseInt(args[0]);
} catch (Exception e) {
TIMEOUT = 30;
}
}
System.out.println(DateFormat.format(new Date()) + " Timeout: " + TIMEOUT);
//new TestServer(4444);
new TestServer(4444).start();
}
}
btw. #Lirik, I witnessed this behavior first in Eclipse, after which I tested it from the command line. And again, I have NO clue what is causing it ;) sorry...

2 threads is fine. One reader another writer. Remember that with UDP you should not spawn new handler threads (unless what you're doing takes a long time), I recommend throwing the incoming messages into a processing Queue. The same for the send, have a send thread that blocks on an incoming Queue for UDP send.

Related

TCP multithreading

Please have a look at the noobish code of mine below.
The intention is to create a server where multiple clients can join and send data constantly.
The works up to 3 clients with no errors, once the 4th client joins in during the three other have started to transfer data through the server freezes.
I dont have log or anything as the tablet completely frozen. Need to force close the app.
I guess it is caused one of the while(true) super solution i've got but cannot figure out why is it not happening earlier before the 4th client joins in.
SERVER:
public class TCPServer extends Thread implements Serializable {
Message receivedMessage = new Message();
ServerSocket serverSocket;
Socket socket;
ObjectInputStream ois;
public static ArrayList<Socket> ClientList = new ArrayList<>();
public void run() {
try {
serverSocket = new ServerSocket(6000);
while(true)
{
socket = serverSocket.accept();
ClientList.add(socket);
ois = new ObjectInputStream(socket.getInputStream());
Thread t = new Thread(new TCPComThread(socket,ois));
t.start();
}
}catch (IOException ioe){
try{
socket.close();
}catch(Exception e)
{e.printStackTrace();
ioe.printStackTrace();}
}
}
And the TCPCOMTHREAD:
class TCPComThread implements Runnable{
private Socket client;
private ObjectInputStream oisFromOutside;
TCPComThread(Socket client, ObjectInputStream oisFromOutside)
{
this.client = client;
this.oisFromOutside = oisFromOutside;
}
public void run(){
MessageToServer obj_message_to_server;
LessonToServer obj_lesson_to_server;
try {
Object aux;
while(!client.isClosed()) {
aux = oisFromOutside.readObject();
if (aux instanceof LessonToServer) {
obj_lesson_to_server = (LessonToServer) aux;
//receivedMessage.obtain();
receivedMessage = new Message();
receivedMessage.obj = obj_lesson_to_server;
LessonToServerHandler.sendMessage(receivedMessage);
}
if (aux instanceof MessageToServer) {
obj_message_to_server = (MessageToServer) aux;
//receivedMessage.obtain();
receivedMessage = new Message();
receivedMessage.obj = obj_message_to_server;
MessageToServerHandler.sendMessage(receivedMessage);
}
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}
Can someone point out what could be causing the above issue?
Thanks
EDIT: I believe the above code is fine, after commenting out everything after the readobject it does not freeze. So the problem is probably with the handler.
HANDLER CODE:
private static Handler LessonToServerHandler = new Handler(){
#Override
public void handleMessage(Message msg){
LessonToServer obj = (LessonToServer) msg.obj;
// SAVE THE IMAGE TO INTERNAL STORAGE
Log.e("SCHOOLID",obj.SchoolID);
Log.e("CHILDID",obj.ChildID);
Log.e("LESSONNAME",obj.Lessonname);
Log.e("LESSONNUMBER",obj.Lessonnumber);
Log.e("RESULT",obj.Result);
Log.e("ISJUNK",obj.IsJunk.toString());
Bitmap bitmap = Coding.decodeBase64(obj.byteArray);
Shared.Utils.saveToInternalStorage(bitmap,obj.SchoolID,obj.ChildID,obj.Lessonname,obj.Lessonnumber,obj.Result, ServerApplication.getAppContext(),obj.IsJunk);
}
};
This looks like a case of "UI thread doing too much work" (based on the amount of "file-write" jobs that are being queued to the UI thread via sendMessage()).
So, how to fix it? It may be time to offload some work to a non-UI thread. Luckily, you already have several: Your TCPComThreads. Based on the code presented, you don't need to do the file-writes on the UI thread anyway. You could simply replace the LessonToServerHandler.sendMessage() call with your existing handleMessage() logic. Keeping this work on the TCPComThread has the added benefit that jobs will be completed just as quickly as they are received (they will "self-throttle", since each job must be written to disk before a new one can be received).

Java - Iterate through IP Address List and call thread with IP Address as argument

I'm relatively new to Java and I'm writing an application to interrogate an Apache HTTP server's access_log file; with this, I want to submit the IP Addresses individually (probably via the Apache HTTPClient library) to another Java instance on another server (as the Web server does not have FTP enabled) to pull some log files. At the moment I've managed to bumble my way through modifying a 'tail -f' equivalent class to suit the programs needs and then manipulate that data to get the IP Addresses that I need to do something with - I even managed to make the 'tail' class threaded so it could address multiple periods of time!
With that said, I want to use a for loop to iterate through each entry in my computerRebootList String Array and with each address create a thread to perform some more work but all I can think of is this;
for (String tmpIpAddress : computerRebootList ) {
ComputerIpHandler handler = new ComputerIpHandler();
}
and then create another class named ComputerIpHandler like so;
public class KioskIpHandler implements Runnable {
static final Logger logger = LogManager.getLogger( ComputerIpHandler.class );
#Override public void run() {
//do some code
}
public static void main(String computerIp) {
Thread mainThread = new Thread(new ComputerIpHandler());
mainThread.start();
try {
logger.info("log some stuff");
mainThread.join();
logger.info("yay it's done");
}
catch (InterruptedException errInterrupted) {
logger.error(errInterrupted.getMessage());
logger.error(errInterrupted.getStackTrace());
}
}
}
I read somewhere about ensuring that I need to manage resource limitations so I would have to create a maximum number of threads - arguably I could send something like 10 IPs to this class and then have the rest of the addresses 'queue' until the one has returned... I'm just not confident or fluent enough to be able to conceptualise these ideas.
EDIT: I omitted that I am restricted to Java 1.6 as this is the maximum compatible version of the JRE that we can use on this server - not sure if that hinders this effort somewhat...
Can anyone point me in the right direction?
Check ScheduledThreadPoolExecutor and ScheduledExecutorService classes in package java.util.concurrent in java API. Those and some other classes in that package would manage all resources for you. They are available in java since version 1.5
I recommend using Java's built in FTP connection platform to make a thread for continually receiving data on a specified port, until it receives a termination key.
Basically, one class will create a ServerSocket (open socket on server) and upon connection with another socket (the client socket) it would create a new thread for receiving information.
public class Server {
public ServerSocket ss;
public Socket clientSocket;
public Thread receiveingThread;
public BufferedReader inFromClient = null;
public boolean running = false;
public Server(int port) {
try {
ss = new ServerSocket(port);
startReceiving();
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void startReceiving() {
receiveingThread = new Thread("Recieve") {
public void run() {
String dataFromClient = new String("");
while (running) {
try {
inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
dataFromClient = inFromClient.readLine();
} catch (Exception e) {
e.printStackTrace();
}
if (dataFromClient.equals("TERMINATOR_KEY") {
stopRecieving();
}
else if(!dataFromClient.equals("")) {
//add item to array
}
}
}
};
receiveingThread.start();
}
public synchronized void stopReceiving() {
try {
running = false;
receivingThread.join();
ss.close();
clientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
public static void main(String[] args) {
new Server(yourPortHere);
}
}
then the client class would look something like:
public class Client {
public Socket socket;
public Thread send;
public Client(string serverPublicIP, int port) {
try {
socket = new Socket(serverPublicIP, port);
send("some IP address");
} catch (Exception e) {
e.printStackTrace();
}
}
public void send(String toSend) {
send = new Thread("Send") {
public void run() {
PrintWriter outToServer;
try {
outToServer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
outToServer.print(toSend);
outToServer.flush();
} catch (Exception e) {
e.printStackTrace();
}
finally {
outToServer.close();
}
}
};
send.start();
}
public static void main(String[] args) {
new Client("127.0.0.1", yourPortHere);
}
}
This is the link for the start of socket tutorials on the oracle site.
This is the Oracle Documentation for java.net.ServerSocket
This is the Oracle Documentation for java.net.Socket

how to pass reference asynchronously between threads? With Observer?

How do I ensure that:
1.) localThread and remoteThread run independent of each other?
2.) pass messages between localThread and remoteThread?
Specifically, a String object from localThread needs to "percolate" up to Telnet through, I think it's known as, a call-back. However, there's not really anything, per se, for Telnet to observe. It's an anonymous reference to LocalIO, and I don't see that explicitly providing a reference helps.
I've read about java.util.concurrent.Semaphore until my head exploded, all I came away with was that it doesn't seem to apply. For these two threads, they should continue to run regardless of what the other thread is doing. However, there needs to be some mechanism to pass object references between the threads...
public class Telnet {
public Telnet() throws InterruptedException {
startThreads();
}
public static void main(String[] args) throws InterruptedException {
new Telnet();
}
public void startThreads() throws InterruptedException {
Semaphore s = new Semaphore(1, true);
Thread localThread = new Thread(new LocalIO());
Thread remoteThread = new Thread(new RemoteIO());
localThread.start();
remoteThread.start();
}
}
The threads themselves are as follows. LocalIO:
public class LocalIO implements Runnable {
#Override
public void run() {
Scanner scanner;
String line;
while (true) {
scanner = new Scanner(System.in);
line = scanner.nextLine();
out.println("\n\nyou entered\t\"" + line + "\"\n");
}
}
}
RemoteIO:
public class RemoteIO implements Runnable {
private static Logger log = Logger.getLogger(RemoteIO.class.getName());
final String host = "rainmaker.wunderground.com";
final int port = 3000;
#Override
public void run() {
log.fine(host + port);
int byteOfData;
try (Socket socket = new Socket(host, port);
InputStream inputStream = socket.getInputStream();
OutputStream ouputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
while ((byteOfData = inputStream.read()) != -1) {
out.print((char) byteOfData);
}
} catch (Exception e) {
out.println(e);
}
}
}
Keeping in mind that RemoteIO never closes its connection and runs indefinitely.
The concurrent package is very helpful for this sort of thing:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html
For example you can just give each thread a ConcurrentLinkedQueue and they can check the queue to see if there is anything to act on whenever they please. Meanwhile other threads can add new objects to the queue whenever they please.
There is one essential difference in the programming paradigm your code can adopt:
synchronous mode: the receiving end runs an endless loop which explicitly takes items off a concurrent queue, blocking when there are no items ready;
asynchronous mode: the receiving end submits a callback to an item exchange mechanism. This callback is called for every item which arrives from the producer thread.
The Observer pattern may loosely apply to the latter case, but not to the former.
Also note that in the latter case, the "item exchange mechanism" is usually implemented in the synchronous mode.
Not sure what yu are trying to do, but if you want to exchange data between threads, you need a volatile variable to make sure changes are seen by other threads. AtomicReferences are non-blocking and provide some API that might help here.
The solution I found:
public class RemoteConnection extends Observable {
private static Logger log = Logger.getLogger(RemoteConnection.class.getName());
private final Socket socket;
private final BufferedInputStream in;
private final BufferedOutputStream out;
private final static String UTF8 = "UTF-8";
public RemoteConnection(String host, int port) throws UnknownHostException, IOException {
socket = new Socket(host, port);
in = new BufferedInputStream(socket.getInputStream());
out = new BufferedOutputStream(socket.getOutputStream());
}
public void write(Deque<String> commands) throws IOException {
String command;
while (!commands.isEmpty()) {
command = commands.pop();
out.write(command.concat("\r\n").getBytes(Charset.forName(UTF8)));
log.info(command);
}
out.flush();
}
void read() { //probably should use BufferedStream to better effect..?
Thread readRemote = new Thread() {
#Override
public void run() {
StringBuilder sb = new StringBuilder();
char ch;
int i;
while (true) {
try {
i = in.read();
ch = (char) i;
sb.append(ch);
System.out.print(ch);
if (i == 13) {
setChanged();
notifyObservers(sb.toString());
log.fine(sb.toString());
sb = new StringBuilder();
}
} catch (IOException ioe) {
log.fine(ioe.toString());
}
}
}
};
readRemote.start();
}
}
By reorganizing the threading, this approximates a poor-mans telnet, with asynchronous threads for i/o. I think reading from the console was blocking...something...
I really don't know why this works but the other approaches didn't. I would've preferred to have the main class start and handle threads, and pass references between the threads, but that just didn't work despite using the various solutions offered here.
LocalConnection has a similar threading approach.

Using Threads to Handle Sockets

I am working on a java program that is essentially a chat room. This is an assignment for class so no code please, I am just having some issues determining the most feasible way to handle what I need to do. I have a server program already setup for a single client using threads to get the data input stream and a thread to handle sending on the data output stream. What I need to do now is create a new thread for each incoming request.
My thought is to create a linked list to contain either the client sockets, or possibly the thread. Where I am stumbling is figuring out how to handle sending the messages out to all the clients. If I have a thread for each incoming message how can I then turn around and send that out to each client socket.
I'm thinking that if I had a linkedlist of the clientsockets I could then traverse the list and send it out to each one, but then I would have to create a dataoutputstream each time. Could I create a linkedlist of dataoutputstreams? Sorry if it sounds like I'm rambling but I don't want to just start coding this, it could get messy without a good plan. Thanks!
EDIT
I decided to post the code I have so far. I haven't had a chance to test it yet so any comments would be great. Thanks!
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class prog4_server {
// A Queue of Strings used to hold out bound Messages
// It blocks till on is available
static BlockingQueue<String> outboundMessages = new LinkedBlockingQueue<String>();
// A linked list of data output streams
// to all the clients
static LinkedList<DataOutputStream> outputstreams;
// public variables to track the number of clients
// and the state of the server
static Boolean serverstate = true;
static int clients = 0;
public static void main(String[] args) throws IOException{
//create a server socket and a clientSocket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(6789);
} catch (IOException e) {
System.out.println("Could not listen on port: 6789");
System.exit(-1);
}// try{...}catch(IOException e){...}
Socket clientSocket;
// start the output thread which waits for elements
// in the message queue
OutputThread out = new OutputThread();
out.start();
while(serverstate){
try {
// wait and accept a new client
// pass the socket to a new Input Thread
clientSocket = serverSocket.accept();
DataOutputStream ServerOut = new DataOutputStream(clientSocket.getOutputStream());
InputThread in = new InputThread(clientSocket, clients);
in.start();
outputstreams.add(ServerOut);
} catch (IOException e) {
System.out.println("Accept failed: 6789");
System.exit(-1);
}// try{...}catch{..}
// increment the number of clients and report
clients = clients++;
System.out.println("Client #" + clients + "Accepted");
}//while(serverstate){...
}//public static void main
public static class OutputThread extends Thread {
//OutputThread Class Constructor
OutputThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
while(!this.interrupted()) {
try {
msg = outboundMessages.take();
for(int i=0;i<outputstreams.size();i++){
outputstreams.get(i).writeBytes(msg + '\n');
}// for(...){...
} catch (IOException e) {
System.out.println(e);
} catch (InterruptedException e){
System.out.println(e);
}//try{...}catch{...}
}//while(...){
}//public void run(){...
}// public OutputThread(){...
public static class InputThread extends Thread {
Boolean threadstate = true;
BufferedReader ServerIn;
String user;
int threadID;
//SocketThread Class Constructor
InputThread(Socket clientSocket, int ID) {
threadID = ID;
try{
ServerIn = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
user = ServerIn.readLine();
}
catch(IOException e){
System.out.println(e);
}
}// InputThread(...){...
public void run() {
String msg = null;
while (threadstate) {
try {
msg = ServerIn.readLine();
if(msg.equals("EXITEXIT")){
// if the client is exiting close the thread
// close the output stream with the same ID
// and decrement the number of clients
threadstate = false;
outputstreams.get(threadID).close();
outputstreams.remove(threadID);
clients = clients--;
if(clients == 0){
// if the number of clients has dropped to zero
// close the server
serverstate = false;
ServerIn.close();
}// if(clients == 0){...
}else{
// add a message to the message queue
outboundMessages.add(user + ": " + msg);
}//if..else...
} catch (IOException e) {
System.out.println(e);
}// try { ... } catch { ...}
}// while
}// public void run() { ...
}
public static class ServerThread extends Thread {
//public variable declaration
BufferedReader UserIn =
new BufferedReader(new InputStreamReader(System.in));
//OutputThread Class Constructor
ServerThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
try {
//while loop will continue until
//exit command is received
//then send the exit command to all clients
msg = UserIn.readLine();
while (!msg.equals("EXITEXIT")) {
System.out.println("Enter Message: ");
msg = UserIn.readLine();
}//while(...){
outboundMessages.add(msg);
serverstate = false;
UserIn.close();
} catch (IOException e) {
System.out.println(e);
}//try{...}catch{...}
}//public void run(){...
}// public serverThread(){...
}// public class prog4_server
I have solved this problem in the past by defining a "MessageHandler" class per client connection, responsible for inbound / outbound message traffic. Internally the handler uses a BlockingQueue implementation onto which outbound messages are placed (by internal worker threads). The I/O sender thread continually attempts to read from the queue (blocking if required) and sends each message retrieved to the client.
Here's some skeleton example code (untested):
/**
* Our Message definition. A message is capable of writing itself to
* a DataOutputStream.
*/
public interface Message {
void writeTo(DataOutputStream daos) throws IOException;
}
/**
* Handler definition. The handler contains two threads: One for sending
* and one for receiving messages. It is initialised with an open socket.
*/
public class MessageHandler {
private final DataOutputStream daos;
private final DataInputStream dais;
private final Thread sender;
private final Thread receiver;
private final BlockingQueue<Message> outboundMessages = new LinkedBlockingQueue<Message>();
public MessageHandler(Socket skt) throws IOException {
this.daos = new DataOutputStream(skt.getOutputStream());
this.dais = new DataInputStream(skt.getInputStream());
// Create sender and receiver threads responsible for performing the I/O.
this.sender = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Message msg = outboundMessages.take(); // Will block until a message is available.
try {
msg.writeTo(daos);
} catch(IOException ex) {
// TODO: Handle exception
}
}
}
}, String.format("SenderThread-%s", skt.getRemoteSocketAddress()));
this.receiver = new Thread(new Runnable() {
public void run() {
// TODO: Read from DataInputStream and create inbound message.
}
}, String.format("ReceiverThread-%s", skt.getRemoteSocketAddress()));
sender.start();
receiver.start();
}
/**
* Submits a message to the outbound queue, ready for sending.
*/
public void sendOutboundMessage(Message msg) {
outboundMessages.add(msg);
}
public void destroy() {
// TODO: Interrupt and join with threads. Close streams and socket.
}
}
Note that Nikolai is correct in that blocking I/O using 1 (or 2) threads per connection is not a scalable solution and typically applications might be written using Java NIO to get round this. However, in reality unless you're writing an enterprise server which thousands of clients connect to simultaneously then this isn't really an issue. Writing bug-free scalable applications using Java NIO is difficult and certainly not something I'd recommend.

Java: Multiple threads vs. sockets

I've written a simple application in Java where there are two nodes, each with a ServerSocket open to a port listening for incoming connections. The nodes run two threads each, sending 1000 messages to the other node through a persistent TCP socket created when sending the first message. However, the nodes do not receive all 1000 messages. One may receive 850 while the other only receives 650. This number tends to stay constant over multiple runs.
The sending code is as follows:
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
PrintWriter printwr = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
Performance seems to improve if I use
buffwr = new BufferedWriter(printwr)
as well and use buffwr.write(...) instead of printwr.print(...), though it doesn't seem to be a complete solution for the data loss. There are no exceptions to show that packets weren't delivered, so according to the sender, they were all sent successfully.
On the receiving end, the accepted connection is treated as follows:
BufferedReader inbuff = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
while(running) {
String rcvedln = inbuff.readLine();
if(rcvedln != null) {
count++;
System.out.println(count);
}
}
Is there an problem with how the readers and writers have been used that could be causing the problem? Thanks.
SendMsg() is creating a new socket every call, so you aren't using a persistent TCP connection. The method isn't closing the socket, either, so you have a lot of open collections. You may be reaching a limit to the number of connections the process can make (the sockets may not be closed when the objects are garbage collected).
Finally, as kd304 pointed out, the Javadoc for PrintWriter states this about the autoFlush parameter of the PrintWriter constructor: "if true, the println, printf, or format methods will flush the output buffer". Your code wasn't calling a method that did a flush.
Try this:
public class MessageSender implements Closeable {
private final Socket socket;
private final PrintWriter writer;
public MessageSender(String dest, int port) {
socket = new Socket(dest, port);
writer = new PrintWriter(socket.getOutputStream(), true);
}
public void sendMessage(Message message) {
try {
writer.println(message.toString());
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
#Override
public void close() throws IOException {
writer.close();
socket.close();
}
Note I modified the code so that sendMessage() calls Message.toString() to get the formatted message. It doesn't seem right for sendMessage() to reference fields in Message in order to format the message. Instead of using toString() you could create a method in Message specifically for this purpose.
Here's the server side code:
public class Server implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService executor;
private volatile boolean running = true;
public Server(int port, ExecutorService executor) throws IOException {
serverSocket = new ServerSocket(port);
this.executor = executor;
}
#Override
public void run() throws IOExeption {
while (running) {
Socket socket = serverSocket.accept();
executor.execute(new ConnectionHandler(socket));
}
}
public boolean stop(long timeout, TimeUnit unit) {
running = false;
executor.shutdown();
return executor.awaitTermination(timeout, unit);
}
}
You can use Executors to create an ExecutorService to run the tasks. Note that ConnectionHandler needs to close the socket it is given.
Are you closing out the PrintWriter to flush the stream?
} finally {
printwr.close();
sendsock.close();
}
Ah, sorry. I accidentally removed the commenting from the code. It's actually like this:
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
printrw is declared and stored outside the function, so once it's set up, there is no need for sendsock or for reinitializing printrw. In the actual application, I'm storing the PrintWriter for every connection in a HashMap and retrieving it at the start of the SendMsg(...) function.
Since the connections are persistent, every time one is accepted, a new thread is lunch that runs a while loop to check it continuously for data. These threads and connections are only closed once the application is terminated. In addition to my previous question, is there a more efficient way of doing this?
Earlier, I'd implemented this code without the "\n" and using println(...) instead and I still had the issue of some messages not being received, so I'm not sure what is causing the problem. The messages are sent like so:
public class SendPortal2 implements Runnable {
String dest = null;
SendPortal2 (String dest) {
this.dest = dest;
}
public void run() {
for(int i=1; i<1000; i+=2) {
Message myMsg = new Message("Message", Main.myaddy + " " + String.valueOf(i));
Main.myCommMgr.SendMsg(dest, myMsg);
}
}
}
There are two such threads running. When I ran the code again just now, one side got 999 packets whereas the other one only got 500, leading me to believe sometimes the data from an entire thread could be blocked out. Is that likely?
Thanks for the replies!
If I put a Thread.sleep(2) inside the for loop where the SendMsg function is called, more messages are received properly, but it's not always 1000. Could it be possible that the system's resources are being hogged by two threads running while loops continuously?

Categories

Resources