I have made a school app in which teacher sends a string message to the students. Teacher holds a hash-map of logged in students. When Teacher presses next page command in his tablet, students should see the next page. And that is what happens normally, but sometimes when teacher is not able to make connection with a single student in the hash-map for some reason whole process gets very slow and rarely the systems ceases to respond any further.
public static void SendToEveryStudent(String message) throws IOException, ELearningException
{
String command;
String host;
int port;
String failedStudents = "";
int leftOverStudents = 0;
ApplicationLog.log("Command Queue: sendToEveryStudent : " + message, InitializeTeacherJar.getInstance().isLoggingEnabled());
int socketTimeout;
Socket studentSocket = null;
StudentUtility.studentCounter = 0;
port = InitializeTeacherJar.getGlobalPort();
socketTimeout = InitializeTeacherJar.getInstance().getTeacherStudentSocketTimeout();
// Check if no of students are more then zero
if (InitializeTeacherJar.getInstance().getStudentIPList().keySet().size() > 0)
{
StudentUtility.studentCounter = InitializeTeacherJar.getInstance().getStudentIPList().keySet().size();
for (String key : InitializeTeacherJar.getInstance().getStudentIPList().keySet())
{
try
{
host = InitializeTeacherJar.getInstance().getStudentIPList().get(key).get(0);
if (!host.equalsIgnoreCase(""))
{
if (studentSocket != null)
{
studentSocket.close();
studentSocket = null;
}
try
{
studentSocket = new Socket(InetAddress.getByName(host), port);
studentSocket.setSoTimeout(socketTimeout);
}
catch (Exception e)
{
leftOverStudents++;
failedStudents = key + InitializeTeacherJar.getInstance().getDelimiter();
ApplicationLog.log("Exception :: " + host +" is not reachable as the server is down at his end.", InitializeTeacherJar.getInstance().isLoggingEnabled());
continue;
}
if (studentSocket != null)
{
if (InitializeTeacherJar.getInstance().getStudentIPList().get(key).get(1).equalsIgnoreCase("present"))
{
studentSocket.getOutputStream().write((message + "\n").getBytes());
ApplicationLog.log("Command Queue: Message to student :: " + message + " :: " + key, InitializeTeacherJar.getInstance().isLoggingEnabled());
BufferedReader in = new BufferedReader(new InputStreamReader(studentSocket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null)
{
if (line.equalsIgnoreCase("ack"))
{
//ApplicationLog.log("InitializeTeacherJar :: Student Counter is :: " + StudentUtility.studentCounter, InitializeTeacherJar.getInstance().isLoggingEnabled());
ApplicationLog.log("Command Queue: Ack recvd for :: "+ key + " :: " + host, InitializeTeacherJar.getInstance().isLoggingEnabled());
}
else
{
ApplicationLog.log("Command Queue: Did Not received ACK for :: "+ key + " :: " + host, InitializeTeacherJar.getInstance().isLoggingEnabled());
}
}
}
else
{
studentSocket.getOutputStream().write((CONSTANTS.ALERT + InitializeTeacherJar.getInstance().getDelimiter() + ErrorCodes.TABLET_NOT_ASSIGNED).getBytes());
ApplicationLog.log("StudentUtility :: Tablet not assigned to :: " + key, InitializeTeacherJar.getInstance().isLoggingEnabled());
}
studentSocket.close();
}
}
}
catch (Exception e)
{
ApplicationLog.log("CommandQueue :: sendToEveryStudent Exception :: " + e, InitializeTeacherJar.getInstance().isLoggingEnabled());
studentSocket.close();
}
studentSocket = null;
}
}
if (leftOverStudents > 0)
{
failedStudents = StudentUtility.m_stripLastChar(failedStudents);
ApplicationLog.log("SendToEveryStudent :: Some Students Were Not Connected :: " + ErrorCodes.TEACHER_STUDENT_SOCKET_NOT_CONNECTED + InitializeTeacherJar.getInstance().getDelimiter() + failedStudents, InitializeTeacherJar.getInstance().isLoggingEnabled());
InitializeTeacherJar.getInstance().getMyFlexSocket().getOutputStream().write((CONSTANTS.ALERT + InitializeTeacherJar.getInstance().getDelimiter() + ErrorCodes.TEACHER_STUDENT_SOCKET_NOT_CONNECTED + InitializeTeacherJar.getInstance().getDelimiter() + failedStudents + InitializeTeacherJar.getInstance().getCommandDelimeter()).getBytes());
InitializeTeacherJar.getInstance().getMyFlexSocket().getOutputStream().flush();
}
else if (leftOverStudents == 0)
{
InitializeTeacherJar.getInstance().getMyFlexSocket().getOutputStream().write((CONSTANTS.ALERT + InitializeTeacherJar.getInstance().getDelimiter() + CONSTANTS.SENT_SUCCESSFULLY_TO_ALL + InitializeTeacherJar.getInstance().getDelimiter() + "Sent To All" + InitializeTeacherJar.getInstance().getCommandDelimeter()).getBytes());
InitializeTeacherJar.getInstance().getMyFlexSocket().getOutputStream().flush();
}
StudentUtility.studentCounter = StudentUtility.studentCounter - leftOverStudents;
}
}
The area where my apprehensions lies are
1) Loop - loop, which makes the sockets and call the blocking call i.e. accept, should go in a AsynTask. 2) SocketTimeout - it should be bare minimal, right now its 1.2 secs. What is the optimal value for this?
This might be little too much code, but I hope the explanation helps. Thanking in advance.
For the time being I have got a shim to be over with it. However I am going to try the "collection of live sockets" thing after I get over with the due release of the software.
Anyways what i have done is following changes to the above code:
try
{
inAddress = InetAddress.getByName(host);
if (!inAddress.isReachable())
{
leftOverStudents++;
failedStudents = key + InitializeTeacherJar.getInstance().getDelimiter();
ApplicationLog.log("Exception :: " + host +" is not reachable as the server is down at his end.", InitializeTeacherJar.getInstance().isLoggingEnabled());
continue;
}
studentSocket = new Socket(inAddress, port);
studentSocket.setSoTimeout(socketTimeout);
}
All I do is just move to next student if it is not reachable. Thanks for the help anyways.