I am a begginer and i went over tutorials for this but still dont know how exactly to implement this.
I have two while loops one in main() method and one in send() method both need to be executing at the same time how do i go about this.
public static void main(String[] args) throws Exception
{
socket = new DatagramSocket(13373); // 69 Reserved for TFTP
// Listen for incoming packets
while(true) {
// Do things
}
}
private static void sendDATA() {
while(true) {
// Do things
}
}
While loop in sendDATA works by reading 512 bytes from a file then sending them to client class. While loop in main method receives packets from client and updates a variable if variable is true then sendDATA reads next 512 bytes and sends them and so on but i cant work in two threads.
I have done this with one while loop and program works, well sort of it transfers all the packets but the last one. Client never gets the last packet.
Server:
public static void main(String[] args) throws Exception
{
socket = new DatagramSocket(13373); // 69 Reserved for TFTP
// Listen for incoming packets
while(true) {
DatagramPacket packet = new DatagramPacket(incoming, incoming.length);
socket.receive(packet);
clientip = packet.getAddress().toString().replace("/", "");
clientport = packet.getPort();
System.out.println(clientport);
if(incoming[0] == 1 || incoming[0] == 2) {
handleRequest(incoming);
}
}
}
// sends DATA opcode = 3 : | opcode | block # | data |
private static void sendDATA() {
try {
ByteBuffer sDATA = ByteBuffer.allocate(514);
byte[] tmp = new byte[512];
DatagramPacket data = new DatagramPacket(sDATA.array(), sDATA.array().length, InetAddress.getByName(clientip), clientport);
InputStream fis = new FileInputStream(new File(FILE));
int a;
int block = 1;
while((a = fis.read(tmp,0,512)) != -1)
{
data.setLength(a);
sDATA.put((byte)3);
sDATA.put((byte)block);
System.out.println(sDATA.array().length);
sDATA.put(tmp);
System.out.println(tmp.length);
socket.send(data);
socket.setSoTimeout(60000);
while(true) {
DatagramPacket getack = new DatagramPacket(incoming, incoming.length);
try {
socket.receive(getack);
if(incoming[0] == 4 && incoming[1] == block) {
break;
} else if(incoming[0] == 4 && incoming[1] == block && tmp.length < 511) {
fis.close();
break;
}
} catch (SocketTimeoutException e) {
socket.send(data);
continue;
}
}
block++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
Client:
public static void main(String[] args) throws Exception
{
clientSocket = new DatagramSocket(8571);
// WRQ || RRQ
Scanner input = new Scanner(System.in);
int opcode = input.nextInt(); input.close();
// Pripravi paketek
outgoing = makeRequestPacket(opcode,"filename.txt","US-ASCII");
// Odposlje pakete
sendPacket(outgoing);
// Streznik vrne ACK - opcode 4 ali ERROR - opcode 5
// Pri ACK zacnemo posiljat DATA opcode 3 drugace prekinemo povezavo ob ERROR - opcode 5
while(true) {
DatagramPacket receiveResponse = new DatagramPacket(incoming, incoming.length);
clientSocket.receive(receiveResponse);
// opcode 5 - ERROR
if(incoming[0] == 5) {
getError(incoming);
}
else if(incoming[0] == 4 && incoming[1] == 0) { // opcode 4 - Prvi ACK
System.out.print("opcode: (" + incoming[0] +") ACK received operation confirmed.");
continue;
}
else if(incoming[0] == 3) {
System.out.println("Ah got a data packet.");
File initfile = new File("filename2.txt");
if(!initfile.exists()) {
initfile.createNewFile();
}
int block;
FileOutputStream fio = new FileOutputStream(initfile);
if(incoming.length > 511) {
block = incoming[1];
System.out.println("Will start to write.");
for(int i = 2; i < incoming.length; i++) {
fio.write(incoming[i]);
}
ByteBuffer recack = ByteBuffer.allocate(514);
recack.put((byte)4);
recack.put((byte)block);
System.out.println("If i came here and nothing happened something went horribly wrong.");
DatagramPacket replyACK = new DatagramPacket(recack.array(), recack.array().length, InetAddress.getByName("localhost"),13373);
clientSocket.send(replyACK);
} else if (incoming.length < 511) {
System.out.println("Last chunk.");
block = incoming[1];
for(int j = 2; j < incoming.length; j++) {
if(incoming[j] != 0) {
fio.write(incoming[j]);
} else {
break;
}
}
ByteBuffer recack = ByteBuffer.allocate(514);
recack.put((byte)4);
recack.put((byte)block);
DatagramPacket replyACK = new DatagramPacket(recack.array(), recack.array().length, InetAddress.getByName("localhost"),13373);
clientSocket.send(replyACK);
fio.close();
clientSocket.close();
break;
}
continue;
}
}
}
You have to use a blocking channel in order to synchronize communication between your processes:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
More info: http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/channels/SocketChannel.html
Also, sockets are designed to send data between processes, if that's not the case your approach is wrong and you should change your design, i.e. call each loop in a new thread when (or every time) data is ready for it (each thread will process its data and then die) or just execute both blocks of instructions sequentially inside one loop if you don't need concurrent execution. A state diagram of your program can help you determine which is the best solution.
So what i have been looking for was a simple 'crude' way of runing two methods of the same class at the same time for instace two independant loops. Anyhow here is the code:
class MyClass extends Thread {
public void run() { // start new thread
otherMethod(); // will calls another method
}
void otherMethod() {
.... executed in another Thread
}
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.start(); // start other Thread
... continue in main() with actual thread
...
}
}
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
So I'm trying to create an smtp from scratch, (assignment) and I'm trying to connect classes together but miserably failing and trying everything out. The compiler doesn't throw up any errors but when I run it I don't get very far. I tried calling the other classes with the .start thread but still, failure
If you could help me or give tips, I would really appreciate it
//Problem seems to be here: I have no idea how to correct it
socketManager soketManager = null;
DataInputStream clientDataIn = new DataInputStream(soketManager.getInputStream());
socketManager clientReaderSocket = soketManager;```
public class socketManager {
public Socket soc = null;`
`
//socketManager.java
public DataInputStream input = null;
public DataOutputStream output = null;
public socketManager(Socket socket) throws IOException {
soc = socket;
input = new DataInputStream(soc.getInputStream());
output = new DataOutputStream(soc.getOutputStream());
}
public InputStream getInputStream() throws IOException {
input = new DataInputStream(soc.getInputStream());
return null;
}
public OutputStream getOutputStream() throws IOException {
output = new DataOutputStream(soc.getOutputStream());
return null;
}
}
Exception in thread "Thread-1" java.lang.NullPointerException at
me.censored.loopback.SMTPclient.Client$ClientSocketManager.run(Client.java:117)
at java.base/java.lang.Thread.run(Thread.java:834)
// Main Method:- called when running the class file.
public static void main(String[] args) throws UnknownHostException, IOException {
Port Declaration & Checks.
String serverIP = "loopback";
int defaultServerPort = 25;
PortManager portManage = new PortManager();
Thread portManagerThread = new Thread(portManage);
portManagerThread.start();
}// End of main
static public class PortManager implements Runnable {
Scanner userInput = new Scanner(System.in);
int serverPort = 25;
// Will accept only tcp/udp ports as of (2019) After several attempts the port
// will be auto selected to default 25,
// Should we accept parsed HEX?
boolean portCompletion = false;
short portTriesCounter = 1;
public void run() {
try {
do {
// Asks user for server's port at the start up of the client.
System.out.println("Please enter the port the server is on.");
String userEntry = userInput.nextLine();
userInput.close();
try {
serverPort = Integer.parseInt(userEntry);
if (portTriesCounter != 5) { // Partial tries timeout.
if (serverPort != 0) { // "Port Zero" does not officially exist. It is defined as an invalid
// port
// number. But valid Internet packets can be formed and sent "over
// the
// wire"
// to and from "port 0" just as with any other ports.
if ((serverPort > 0 && serverPort <= 1023)
|| (serverPort >= 1024 && serverPort <= 49151)
|| (serverPort >= 49152 && serverPort <= 65535)) // Check for ports inside the
// tcp/udp
// range
portCompletion = true;
else {
System.out.println(
"Wrong input! Make sure you are using correct numbers and port range! ");
portCompletion = false;
portTriesCounter++;
}
// End Check for ports inside the tcp/udp range
} else {
System.out.print("Wrong input! ");
portCompletion = false;
portTriesCounter++;
}
// End Check for zero
}
// End Too many attempts
else {
portTriesCounter = 5;
portCompletion = true;
System.out.print("Many wrong attemps. Selecting and trying the default port (25)... ");
try {
System.out.print("Success");
portCompletion = true;
serverPort = 25; // For SSL connections use port 465.
} catch (Exception except) {
portCompletion = false;
}
}
} catch (Exception except) {
portCompletion = false;
portTriesCounter++;
} finally {
userInput.close();
}
} while (!portCompletion);
ClientSocketManager clientSocketManage = new ClientSocketManager();
Thread clientSocketManagerThread = new Thread(clientSocketManage);
clientSocketManagerThread.start();
System.out.println("DEBUG 0");
} catch (Exception except) { // Any Failure will send 421 Error to client
System.out.println("\t 421 \t Service not available, closing transmission channel.\n" + except);
}
}
}
static class ClientSocketManager implements Runnable {
public void run() {
try {
String CRLF = "\r\n";
String LF = "\n";
boolean SocketInitiation = false;
socketManager soketManager = null;
DataInputStream clientDataIn = new DataInputStream(soketManager.getInputStream());
socketManager clientReaderSocket = soketManager;
DataOutputStream clientDataOut;
clientDataOut = new DataOutputStream(soketManager.getOutputStream());
String sendSocketMessage = (CRLF);
clientDataOut.writeUTF(sendSocketMessage);// Sends string to output stream using UTF-8
clientDataOut.flush();
System.out.println("DEBUG 1");
String socketReplyIn = clientDataIn.readUTF();
PortManager portInstance = new PortManager();
int portNumber = portInstance.serverPort;
Socket soket = new Socket("loopback", portNumber);
ClientWriter clientWrite = new ClientWriter(soket);
Thread clientWriteThread = new Thread(clientWrite);
ClientReader clientRead = new ClientReader(soket);
Thread clientReadThread = new Thread(clientRead);
System.out.println("DEBUG 2");
// Cleans stream from any write buffer method.
System.out.println("Connection to server using TCP...");
if (socketReplyIn.contains("220")) {
System.out.println("\t 220 \t Service ready"); // Connection established successfully
clientReadThread.start();
clientWriteThread.start();
SocketInitiation = true;
} else {
System.out.println("\t 421 \t Service not available, closing transmission channel");
SocketInitiation = false;
}
} catch (IOException e) {
System.out.println("\t 421 \t Service not available, closing transmission channel");
System.out.println("TCP connection error: " + e);
}
}
}
you have defined socketManager soketManager = null; in ClientSocketManager.
but you never assigned a value to it, so it is still null.
The code after that is trying to access streams from it, which is throwing NullPointerException:
DataInputStream clientDataIn = new DataInputStream(soketManager.getInputStream());
socketManager clientReaderSocket = soketManager;
DataOutputStream clientDataOut;
clientDataOut = new DataOutputStream(soketManager.getOutputStream());
String sendSocketMessage = (CRLF);
clientDataOut.writeUTF(sendSocketMessage);// Sends string to output stream using UTF-8
clientDataOut.flush();
System.out.println("DEBUG 1");
just create a new instance of the socketManager and assign it to soketManager before using it.
PortManager portInstance = new PortManager();
int portNumber = portInstance.serverPort;
Socket soket = new Socket("loopback", portNumber);
socketManager soketManager = new sockerManager(soket);
I am getting live audio streaming over the network in the form of RTP packets and I have to write a code to Capture, Buffer and play the audio stream.
Problem
Now to solve this problem I have written two threads one for capture the audio and another for playing it. Now when I start both the threads my capture threads running slower than playing thread :(
Buffer Requirement
RTP Audio Packets.
8kHz, 16-bit Linear Samples (Linear PCM).
4 frames of 20ms audio will be sent in each RTP Packet.
Do not play until AudioStart=24 (# of 20ms frames) have arrived.
While playing ... if the # of 20ms frames in buffer reaches 0 ...
stop playing until AudioStart frames are buffered then restart.
While playing ... if the # of 20ms frames in buffer exceeds
AudioBufferHigh=50 then delete 24 frames (in easiest manner -- delete
from buffer or just drop next 6 RTP messages).
What I have done so far..
Code
BufferManager.java
public abstract class BufferManager {
protected static final Integer ONE = new Integer(1);
protected static final Integer TWO = new Integer(2);
protected static final Integer THREE = new Integer(3);
protected static final Integer BUFFER_SIZE = 5334;//5.334KB
protected static volatile Map<Integer, ByteArrayOutputStream> bufferPool = new ConcurrentHashMap<>(3, 0.9f, 2);
protected static volatile Integer captureBufferKey = ONE;
protected static volatile Integer playingBufferKey = ONE;
protected static Boolean running;
protected static volatile Integer noOfFrames = 0;
public BufferManager() {
//captureBufferKey = ONE;
//playingBufferKey = ONE;
//noOfFrames = new Integer(0);
}
protected void switchCaptureBufferKey() {
if(ONE.intValue() == captureBufferKey.intValue())
captureBufferKey = TWO;
else if(TWO.intValue() == captureBufferKey.intValue())
captureBufferKey = THREE;
else
captureBufferKey = ONE;
//printBufferState("SWITCHCAPTURE");
}//End of switchWritingBufferKey() Method.
protected void switchPlayingBufferKey() {
if(ONE.intValue() == playingBufferKey.intValue())
playingBufferKey = TWO;
else if(TWO.intValue() == playingBufferKey.intValue())
playingBufferKey = THREE;
else
playingBufferKey = ONE;
}//End of switchWritingBufferKey() Method.
protected static AudioFormat getFormat() {
float sampleRate = 8000;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
protected int getByfferSize() {
return bufferPool.get(ONE).size()
+ bufferPool.get(TWO).size()
+ bufferPool.get(THREE).size();
}
protected static void printBufferState(String flag) {
int a = bufferPool.get(ONE).size();
int b = bufferPool.get(TWO).size();
int c = bufferPool.get(THREE).size();
System.out.println(flag + " == TOTAL : [" + (a + b +c) + "bytes] ");
// int a,b,c;
// System.out.println(flag + "1 : [" + (a = bufferPool.get(ONE).size()) + "bytes], 2 : [" + (b = bufferPool.get(TWO).size())
// + "bytes] 3 : [" + (c = bufferPool.get(THREE).size()) + "bytes], TOTAL : [" + (a + b +c) + "bytes] ");
}
}//End of BufferManager Class.
AudioCapture.java
public class AudioCapture extends BufferManager implements Runnable {
private static final Integer RTP_HEADER_SIZE = 12;
private InetAddress ipAddress;
private DatagramSocket serverSocket;
long lStartTime = 0;
public AudioCapture(Integer port) throws UnknownHostException, SocketException {
super();
running = Boolean.TRUE;
bufferPool.put(ONE, new ByteArrayOutputStream(BUFFER_SIZE));
bufferPool.put(TWO, new ByteArrayOutputStream(BUFFER_SIZE));
bufferPool.put(THREE, new ByteArrayOutputStream(BUFFER_SIZE));
this.ipAddress = InetAddress.getByName("0.0.0.0");
serverSocket = new DatagramSocket(port, ipAddress);
}
#Override
public void run() {
System.out.println();
byte[] receiveData = new byte[1300];
DatagramPacket receivePacket = null;
lStartTime = System.currentTimeMillis();
receivePacket = new DatagramPacket(receiveData, receiveData.length);
byte[] packet = new byte[receivePacket.getLength() - RTP_HEADER_SIZE];
ByteArrayOutputStream buff = bufferPool.get(captureBufferKey);
while (running) {
if(noOfFrames <= 50) {
try {
serverSocket.receive(receivePacket);
packet = Arrays.copyOfRange(receivePacket.getData(), RTP_HEADER_SIZE, receivePacket.getLength());
if((buff.size() + packet.length) > BUFFER_SIZE) {
switchCaptureBufferKey();
buff = bufferPool.get(captureBufferKey);
}
buff.write(packet);
noOfFrames += 4;
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} // End of try-catch block.
} else {
//System.out.println("Packet Ignored, Buffer reached to its maximum limit ");
}//End of if-else block.
} // End of while loop.
}//End of run() Method.
}
AudioPlayer.java
public class AudioPlayer extends BufferManager implements Runnable {
long lStartTime = 0;
public AudioPlayer() {
super();
}
#Override
public void run() {
AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine line = null;
try {
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
} catch (LineUnavailableException e1) {
e1.printStackTrace();
}
while (running) {
if (noOfFrames >= 24) {
ByteArrayOutputStream out = null;
try {
out = bufferPool.get(playingBufferKey);
InputStream input = new ByteArrayInputStream(out.toByteArray());
byte buffer[] = new byte[640];
int count;
while ((count = input.read(buffer, 0, buffer.length)) != -1) {
if (count > 0) {
InputStream in = new ByteArrayInputStream(buffer);
AudioInputStream ais = new AudioInputStream(in, format, buffer.length / format.getFrameSize());
byte buff[] = new byte[640];
int c = 0;
if((c = ais.read(buff)) != -1)
line.write(buff, 0, buff.length);
}
}
} catch (IOException e) {
e.printStackTrace();
}
/*byte buffer[] = new byte[1280];
try {
int count;
while ((count = ais.read(buffer, 0, buffer.length)) != -1) {
if (count > 0) {
line.write(buffer, 0, count);
}
}
} catch (IOException e) {
e.printStackTrace();
}*/
out.reset();
noOfFrames -= 4;
try {
if (getByfferSize() >= 10240) {
Thread.sleep(15);
} else if (getByfferSize() >= 5120) {
Thread.sleep(25);
} else if (getByfferSize() >= 0) {
Thread.sleep(30);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// System.out.println("Number of frames :- " + noOfFrames);
}
}
}// End of run() method.
}// End of AudioPlayer Class class.
any help or pointer to the helpful link will be appreciable Thanks...
This answer explains a few challenges with streaming.
In a nutshell, your client needs to deal with two issues:
1) The clock (crystals) on the client and server are not perfectly in sync. The server may be a fraction of a Hz faster/slower than the client. The client continuously match the infer the clock rate of the server by examining the rate that rtp packets are delivered. The client then adjusts the playback rate via sample rate conversion. So instead of playing back at 48k, it may play back at 48000.0001 Hz.
2) Packets loss, out of order arrivals, etc. must be dealt with. If you lose packets, you need to still keep a place holder for those packets in your buffer stream otherwise your audio will skip and sound crackly and become unaligned. The simplest method would be to replace those missing packets with silence but the volume of adjacent packets should be adjusted to avoid sharp envelope changes snapping to 0.
Your design seems a bit unorthodox. I have had success using a ring buffer instead. You will have to deal with edge cases as well.
I always state that streaming media is not a trivial task.
I've got a main program that starts two threads. First I only had this thread, that executes the following inside the while(true):
loopCounter++;
outputStream.write(pollBuf);
readResponse();
Thread.sleep(200);
outputStream.write(statusBuf);
readResponse();
logger.info("status executed");
The problem is that when the second readResponse doesn't return because the device listening to the comport simply doesn't answer I'm stuck and the display that gives the status of the machine simply still shows "running" instead of software error or something alike.
So I need to know when this thread is stuck and therefore I added another thread that now gets created and started in the main program right before the other thread, the code inside the while(true) of the run() method of this second thread:
public class StatusThread implements Runnable {
static Logger logger = Logger.getLogger(StatusThread.class);
private Nv10ToVcdm mainProgram;
public void initialize(Nv10ToVcdm mProgram, boolean acceptBills) {
mainProgram = mProgram;
}
public void run() {
int loopCounter = mainProgram.getLoopCounter();
while (true) {
try {
Thread.sleep(1000);
int currentLoopCounter = mainProgram.getLoopCounter();
if (loopCounter != currentLoopCounter) {
loopCounter = currentLoopCounter;
} else {
mainProgram.writeToDisplay("SOFTWARE", "ERROR");
}
} catch (InterruptedException ie) {
logger.error("Interrupted exception: " + ie.getMessage());
mainProgram.errorOnDisplay();
}
}
}
}
Sadly the first thread being stuck on listening to the comport doesn't release the claim it has on the cpu so the second thread doesn't get any CPU time. So: How to show an error on the display when the thread listening to a com port hangs?
The readResponse method that hangs, afaik it hangs on "byte firstByte = (byte) inputStream.read();" because there's nothing to read:
private void readResponse() {
byte[] bufferLeft = new byte[4];
byte[] bufferRight = new byte[2];
byte size = 0;
boolean responseFound = false;
try {
while(!responseFound) {
byte firstByte = (byte) inputStream.read();
if (firstByte == -1) {
logger.error("first byte of response is -1");
mainProgram.errorOnDisplay();
break;
}
for (int i = 0; i < 4; i++) {
bufferLeft[i] = (byte) inputStream.read();
}
size = bufferLeft[0];
if (size > 0) {
bufferRight = new byte[size];
int i2 = 0;
while (i2 < size) {
bufferRight[i2] = (byte) inputStream.read();
i2++;
}
}
if (firstByte == 1 && bufferLeft[1] == 40) {
responseFound = true;
}
}
if (size == 11) {
// some code
}
} catch(IOException ioe) {
logger.error("IO Exception in readResponse: " + ioe.getMessage());
mainProgram.errorOnDisplay();
}
}
Edit (added complete code for second thread & readResponse method)
Inputstream is initialized as follows:
serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
inputStream = serialPort.getInputStream();
Did you tried to cheack data availability before read?
Something like:
if (inputStream.available() > 0) {
// do your read
} else {
// wait for some time and retry or trow an error
}
This question already has answers here:
Java detect lost connection [duplicate]
(9 answers)
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 9 years ago.
I have a java program with Socket. I need to check if client has disconnected. I need a example how to do that. I have researched but I don't understand. So can someone make example code and explane everything.
sorry for bad English
my code:
package proov_server;
//SERVER 2
import java.io.*;
import java.net.*;
class server2 {
InetAddress[] kasutaja_aadress = new InetAddress[1000];
String newLine = System.getProperty("line.separator");
int kliendiNr = 0;
int kilene_kokku;
server2(int port) {
try {
ServerSocket severi_pistik = new ServerSocket(port);
System.out.println("Server töötab ja kuulab porti " + port + ".");
while (true) {
Socket pistik = severi_pistik.accept();
kliendiNr++;
kasutaja_aadress[kliendiNr] = pistik.getInetAddress();
System.out.println(newLine+"Klient " + kliendiNr + " masinast "
+ kasutaja_aadress[kliendiNr].getHostName() + " (IP:"
+ kasutaja_aadress[kliendiNr].getHostAddress() + ")");
// uue kliendi lõime loomine
KliendiLoim klient = new KliendiLoim(pistik,kliendiNr);
// kliendi lõime käivitamine
klient.start();
}
}
catch (Exception e) {
System.out.println("Serveri erind: " + e);
}
}
DataOutputStream[] väljund = new DataOutputStream[1000];
DataInputStream[] sisend = new DataInputStream[1000];
int klient = 0;
int nr;
// sisemine klass ühendusega tegelemiseks
class KliendiLoim extends Thread {
// kliendi pistik
Socket pistik;
// kliendi number
KliendiLoim(Socket pistik2,int kliendiNr) {
nr = kliendiNr;
this.pistik = pistik2;
}
public boolean kontroll(){
try{
System.out.println("con "+pistik.isConnected());
System.out.println("close "+pistik.isClosed());
if(pistik.isConnected() && !pistik.isClosed()){
//System.out.print(con_klient);
return true;
}
}catch(NullPointerException a){
System.out.println("Sihukest klienti pole!!!");
}
kliendiNr --;
return false;
}
public void run() {
try {
sisend[nr] = new DataInputStream(pistik.getInputStream()); //sisend
väljund[nr] = new DataOutputStream(pistik.getOutputStream()); //väljund
}catch (Exception ea) {
System.out.println(" Tekkis erind: " + ea);
}
while(true){
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Sisesta k2sk: ");
String k2sk = null;
k2sk = br.readLine();
/*
String command;
if(k2sk.indexOf(" ") < 0){
command = k2sk;
}else{
command = k2sk.substring(0, k2sk.indexOf(" "));
}
*/
String[] words = k2sk.split("\\s+");
for (int i = 0; i < words.length; i++) {
words[i] = words[i].replaceAll(" ", "");
}
switch(words[0]){
case "suhtle":
if(väljund.length > klient && väljund[klient] != null)
{
väljund[klient].writeUTF("1");
}else{
väljund[klient] = null;
sisend[klient] = null;
System.out.println("Sihukest klienti pole");
}
break;
case "vaheta":
try{
int klinetnr = Integer.parseInt(words[1]);
//if(kontroll(klinetnr) ){
klient = Integer.parseInt(words[1]);
//}
}
catch(NumberFormatException e){
System.out.println("See pole number!!! ");
}
break;
case "kliendid":
if(kliendiNr != 0){
for(int i=1;i <= kliendiNr;i++){
if(kontroll()){
System.out.println("Klient:"+i+" ip: " + kasutaja_aadress[i] );
}else{
System.out.println("Pisi");
väljund[klient] = null;
sisend[klient] = null;
}
}
System.out.println(newLine);
}else{
System.out.println("Kiente pole");
}
break;
}
System.out.println(kliendiNr);
}catch(SocketException a){
System.out.println("Klient kadus");
}
catch(Exception e){
System.out.println(" Viga: " + e);
}
}
}
}
public static void main(String[] args) {
new server2(4321);
}
}
If the client has disconnected properly:
read() will return -1
readLine() returns null
readXXX() for any other X throws EOFException.
The only really reliable way to detect a lost TCP connection is to write to it. Eventually this will throw an IOException: connection reset, but it takes at least two writes due to buffering.
A related thread on Stackoverflow here along with the solution. Basically, the solution says that the best way to detect a client-server disconnect is to attempt to read from the socket. If the read is successfully, then the connection is active.If an exception is thrown during the read there is no connection between the client and the server. Alternatively it may happen that the socket is configured with a timeout value for the read operation to complete. In case, this timeout is exceeded a socket timeout exception will be thrown which can be considered as either the client is disconnected or the network is down.
The post also talks about using the isReachable method - refer InetAddress documentation. However, this method only tells us whether a remote host is reachable or not. This may just one of the reasons for the client to disconnect from the server. You wont be able to detect disconnection due to client crash or termination using this technique.
As part of a course assignment, we have been tasked with adding an extra layer of reliability on top of the UDP layer java offers in order to send a large picture file. This is to be done using the Go-Back-N protocol: http://en.wikipedia.org/wiki/Go_back_N
From what i understand, the crux of this problem relies on being able to send packets while simultaneously checking if any Acknowledgements have come in for old packets which would allow you to move your window along.
I am currently doing this by having two threads: One which sends the next packets if there is space in the window; and one which continually just listens for any incoming acknowledgements and reacts appropriately.
My problem is that the program should be threaded such that it is as if these two threads are acting simulatneously, but in fact, it seems as if the ACKReceiver thread is getting a hugely disproportionate amount of time. From the thread dump it appears to "starve" the sending thread for a little while when it reaches the DataSocket.receive() line, blocking execution here and not giving the other thread an opportunity to run in the meantime.
I have had a look at the following question which seems to hint that the problem is something to do with the fact that DatagramSocket.receive is synchronized...but offers no usable solution to the problem:
Java Thread won't pause on I/O operation
Here is the code to the sender part of my code, i am relatively sure the receiver on the other side is perfectly fine (for one thing, i didn't have to use any threads to get that to work!):
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
public class Sender3 {
short base = 0;
short nextSeqNum = 0;
DatagramPacket[] packets;
ByteBuffer bb;
String endSys;
int portNum;
String fileName;
int retryTime;
int windowSize;
DatagramSocket clientSocket;
InetAddress IPAddress;
boolean timedOut = false;
public Sender3(String endSys, int portNum, String fileName, int retryTime, int windowSize){
this.endSys = endSys;
this.portNum = portNum;
this.fileName = fileName;
this.retryTime = retryTime;
this.windowSize = windowSize;
}
public static void main(String args[]) throws Exception{
//Check for current arguments and assign them
if(args.length != 5){
System.out.println("Invalid number of arguments. Please specify: <endSystem> <portNumber> <fileName> <retryTimeout><windowSize>");
System.exit(1);
}
Sender3 sendy = new Sender3(args[0], Integer.parseInt(args[1]), args[2], Integer.parseInt(args[3]), Integer.parseInt(args[4]));
sendy.go();
}
private void go() throws Exception{
clientSocket = new DatagramSocket();
bb = ByteBuffer.allocate(2);
byte[] picData = new byte[1021];
byte[] sendData = new byte[1024];
Thread.yield()
short seqNum = 0;
byte[] seqBytes = new byte[2];
byte EOFFlag = 0;
boolean acknowledged = false;
int lastPacketRetrys = 0;
int resends = 0;
IPAddress = InetAddress.getByName(endSys);
FileInputStream imReader = new FileInputStream(new File(fileName));
double fileSizeKb = imReader.available() / 1021.0; //We add 3 bytes to every packet, so dividing by 1021 will give us total kb sent.
int packetsNeeded = (int) Math.ceil(fileSizeKb);
packets = new DatagramPacket[packetsNeeded];
long startTime = System.currentTimeMillis();
long endTime;
double throughput;
//Create array of packets to send
for(int i = 0; i < packets.length; i++){
if(i == packets.length - 1){
EOFFlag = 1;
picData = new byte[imReader.available()];
sendData = new byte[picData.length + 3];
}
imReader.read(picData);
bb.putShort((short)i);
bb.flip();
seqBytes = bb.array();
bb.clear();
System.arraycopy(seqBytes, 0, sendData, 0, seqBytes.length);
sendData[2] = EOFFlag;
System.arraycopy(picData, 0, sendData, 3, picData.length);
packets[i] = new DatagramPacket((byte[])sendData.clone(), sendData.length, IPAddress, portNum);
}
ACKGetter ackGet = new ACKGetter();
Thread ackThread = new Thread(ackGet);
ackThread.start();
//System.out.println("timeout is: " + timedOut + " base is: " + base + " packet length is: " + packets.length + " nextSeqNum: " + nextSeqNum);
while(base != packets.length){
if(timedOut){
//System.out.println("Timed out waiting for acknowledgement, resending all unACKed packets in window");
clientSocket.setSoTimeout(retryTime);
resends++;
if(nextSeqNum == packets.length)
lastPacketRetrys++;
//Resend all packets in window
for (int i = base; i < nextSeqNum; i++){
// System.out.println("Resending packets with number: " + i);
clientSocket.send(packets[i]);
}
timedOut = false;
}
if(nextSeqNum - base < windowSize && nextSeqNum < packets.length){
//System.out.println("sending packet with seqNum: " + nextSeqNum);
clientSocket.send(packets[nextSeqNum]);
if(base == nextSeqNum){
clientSocket.setSoTimeout(retryTime);
}
nextSeqNum++;
}
else{
//Thread.yield();
}
}
if(lastPacketRetrys > 10){
System.out.println("Last packet ACK was lost (we think). So we just gave up, number of retransmissions will probably be higher");
}
endTime = System.currentTimeMillis();
throughput = 1000 * fileSizeKb / (endTime - startTime);
clientSocket.close();
imReader.close();
System.out.println("Number of retransmissions: " + resends);
System.out.println("Average throughput is: " + throughput + "Kb/s");
}
private class ACKGetter implements Runnable {
//Listen out for ACKs and update pointers accordingly
DatagramPacket ackPacket;
byte[] ackData = new byte[2];
public void run() {
while(base != packets.length){
if(base != nextSeqNum){
try{
ackPacket = new DatagramPacket(ackData, ackData.length);
clientSocket.receive(ackPacket);
ackData = ackPacket.getData();
bb.put(ackData[0]);
bb.put(ackData[1]);
bb.flip();
short ack = bb.getShort();
bb.clear();
if(base <= ack){
//System.out.println("acknowledgement for base num: " + base + "ack num:" + ack);
base = (short) (ack + 1);
//If theres nothing left in window, stop timing, otherwise restart the timer
if(base == nextSeqNum){
clientSocket.setSoTimeout(0);
}
else{
clientSocket.setSoTimeout(retryTime);
}
}
else{
//System.out.println("ACK didnt change anything: " + ack);
}
}
catch(Exception ex){
timedOut = true;
//System.out.println("Packet timed out...resending..");
}
}
Thread.yield();
}
}
}
}
I think you are having a deadlock here because the reader thread is in clientSocket.receive() while the sender makes a call to clientSocket.setSoTimeout(). See the following DatagramSocket method definitions:
public synchronized void setSoTimeout(int timeout) throws SocketException {
...
public synchronized void receive(DatagramPacket p) throws IOException {
If you are receiving with a socket timeout of 0 then receive hangs waiting for a packet. If you issue a SIGQUIT your JVM will dump the threads and should show you the deadlock and you can track the stack frames to see where the sender and receiver are stuck.
To fix this you should stop changing the setSoTimeout value which sounds like very bad practice to me. I would switch to using DatagramChannel, making the socket non-blocking, and use NIO receive to do the reads. See the NIO docs for more information on how to use a channel Selector.