2013-01-24 12 views
7

Ho un'applicazione Java che è Voip. Sto usando l'unico socket per inviare e ricevere informazioni allo stesso tempo tramite thread. Codice è mostrato di seguito ..È possibile scrivere contemporaneamente su un ingresso e un flusso di uscita socket?

Socket clientSocket = sockList.accept(); 
OutputStream outSock = clientSocket.getOutputStream(); 
InputStream inSock = clientSocket.getInputStream(); 
new Thread(new Capture(outSock)).start(); 
new Thread(new PlayAudio(inSock)).start(); 
outSock.close(); 
clientSocket.close(); 

Il problema che sto trovando è che quando scrivo al OutputStream, si blocca sul primo scrittura. Sto inviando non molti byte. Bellow è il mio codice di scrittura.

private class Capture implements Runnable{ 

    private OutputStream out; 
    public Capture(OutputStream out){ 
     this.out = out; 
    } 
    @Override 
    public void run() { 
     try{ 
      int numBytesRead; 
      TargetDataLine outLine = getMic(); 
      outLine.open(); 
      outLine.start(); 

      byte[] data = new byte[outLine.getBufferSize()/5]; 
      byte[] test = {0x1,0x1,0x1}; 

      while(true) {  
       //numBytesRead = outLine.read(data, 0, data.length); 
       //System.out.println(numBytesRead); 
       out.write(test, 0, test.length); 
       out.flush(); 
       /*if(numBytesRead > 0){ 
        out.write(data, 0, data.length); 
        System.out.println("C"); 
       }*/ 
      } 
     }catch(Exception ex){} 
    } 
} 

L'altro thread che legge il codice del suono è ...

private class PlayAudio implements Runnable{ 

    private InputStream in; 
    public PlayAudio(InputStream in){ 
     this.in = in; 
    } 
    @Override 
    public void run() { 
     int write; 
     try{ 
     SourceDataLine inLine = getSpeaker(); 
     inLine.open(); 
     inLine.start(); 
     byte[] data = new byte[inLine.getBufferSize()]; 
     byte[] test = new byte[3]; 
     while(true){ 
      System.out.println(1); 
      //write = in.read(data, 0, data.length); 
      in.read(test, 0 , test.length); 
      System.out.println(2); 
      /*if(write > 0){ 
       inLine.write(data, 0, write); 
       System.out.println(3); 
       System.out.println(write); 
      }*/ 
     } 
     } catch(Exception ex){} 
    } 

} 

Ho commentato una buona parte del codice vero e proprio dal momento che sto solo cercando di farlo funzionare. La mia funzione di scrittura blocca indefinitamente la prima scrittura. È possibile che questo potrebbe essere un problema con i miei thread? Il mio unico pensiero è che i flussi di output e di input stiano condividendo il mio oggetto socket che potrebbe causare un deadlock o qualcosa del genere. Per favore fatemi sapere cosa succede.

risposta

11

Sì, è possibile scrivere contemporaneamente in uno stream di input e output di socket.

da do-java-sockets-support-full-duplex

Dal momento che il flusso di input e l'output stream sono oggetti separati all'interno del Socket, l'unica cosa che potrebbe riguardano te stesso con è, cosa succede se si ha 2 thread cercando di leggere o scrivere (due thread, stesso flusso di input/output) allo stesso tempo? I metodi di lettura/scrittura delle classi InputStream/OutputStream non sono sincronizzati. È possibile, tuttavia, che se si utilizza una sottoclasse di InputStream/OutputStream, i metodi di lettura/scrittura che si stanno chiamando siano sincronizzati. Puoi controllare javadoc per qualunque classe/metodo stai chiamando e scoprirlo abbastanza velocemente.

+0

Ho pensato che dal momento che dentro e fuori (due flussi separati) sono oggetti separati, operare su di essi allo stesso tempo non dovrebbe avere importanza. Quindi il tuo modo di dire dovrebbe ancora preoccuparmi della sincronizzazione, a prescindere? –

4

Sì, è possibile scrivere sul socket durante la lettura, ma è necessario leggere il socket in un thread indipendente. Sto usando questo concetto. Qui l'esempio è (leggere attentamente supporta mutiple cliente così):

public class TeacherServerSocket { 

private Logger logger = Logger.getLogger(TeacherServerSocket.class); 
public static Map<String, TeacherServerThread> connectedTeacher = new HashMap<String, TeacherServerThread>(); 
ServerSocket serverSocket;; 

@Override 
public void run() { 
    // starting teacher server socket 
    this.serverSocket = startServer(); 
    // if unable to to start then serverSocket would have null value 
    if (null != this.serverSocket) { 

     while (true) { 
      //listening to client for infinite time 
      Socket socket = listenToClient(); 
      if (null != socket) { 

       TeacherServerThread teacherServerThread = new TeacherServerThread(socket); 
       Thread thread = new Thread(teacherServerThread); 
       thread.start(); 

       //putting teacher ip address and teacher object into map 
       connectedTeacher.put(teacherServerThread.getTeacherIp(),teacherServerThread); 
       System.out.println("INFO: Teacher is connected with address "+ teacherServerThread.getTeacherIp()); 

      } 

     } 


    } 

} 

@Override 
public ServerSocket startServer() { 
    //port number on which teacher server will be run. 
    int port=12345; 

    try { 
     // throw an exception if unable to bind at given port 
     ServerSocket serverSocket = new ServerSocket(port); 
     System.out.println("Teacher server socket started on port no :"+port); 
     return serverSocket; 

    } catch (IOException e) { 

     logger.error("Unable to start Teacher Server socket"); 
     e.printStackTrace(); 

    } 

    return null; 

} 

@Override 

public Socket listenToClient() { 

    if (this.serverSocket != null) { 

     try { 
      // throw an exception is unable to open socket 
      Socket socket = this.serverSocket.accept(); 
      return socket; 

     } catch (IOException e) { 

      logger.error("Unable to open socket for teacher"); 
      e.printStackTrace(); 

     } 
    } 
    else { 

     logger.error("TeacherServerSocket has got null value please restart the server"); 

    } 

    return null; 
} 





@Override 
public Map getConnectedDevicesMap() { 

return TeacherServerSocket.connectedTeacher; 

} 

/** 
* This method will send message to connected teacher which comes form student 
* @author rajeev 
* @param message, which comes form student 
* @return void 
* * */ 
@Override 
public void publishMessageToClient(String message) { 
    if(TeacherServerSocket.connectedTeacher.size()>0){ 
     System.out.println("Total Connected Teacher: "+TeacherServerSocket.connectedTeacher.size()); 
     for (String teacherIp : TeacherServerSocket.connectedTeacher.keySet()) { 

      TeacherServerThread teacherServerThread=TeacherServerSocket.connectedTeacher.get(teacherIp); 
      teacherServerThread.publishMessageToTeacher(message); 

     } 
    } 

} 



@Override 
public void stopServer() { 

    if (this.serverSocket != null) { 

     try { 

      serverSocket.close(); 

     } catch (Exception e) { 

      e.printStackTrace(); 

     } 
    } 

} 


} 

Per leggere in un in filo indipendente per più client:

public class TeacherServerThread implements Runnable { 


Logger logger=Logger.getLogger(TeacherServerThread.class); 
Socket socket; 
String teacherIp; 

public TeacherServerThread(Socket socket) { 
this.socket=socket; 
this.teacherIp=socket.getInetAddress().toString(); 
} 


@Override 
public void run() { 
    //starting reading 
    ReadFromTeacherAndPublishToStudent messageReader=new ReadFromTeacherAndPublishToStudent(); 
    Thread thread=new Thread(messageReader); 
    thread.start(); 
} 





private class ReadFromTeacherAndPublishToStudent implements Runnable { 

    @Override 
    public void run() { 
     String message=null; 
     try { 
      BufferedReader readTeacherData=new BufferedReader(new InputStreamReader(socket.getInputStream())); 

      StudentServerSocket studentServerSocket=new StudentServerSocket(); 
      //sending message to student which is read by teacher 
      while((message=readTeacherData.readLine())!=null){ 
       //System.out.println("Message found : "+message); 
       // studentServerSocket.publishMessageToClient(message); // do more stuff here 

      } 
      // if message has null value then it mean socket is disconnected. 
     System.out.println("INFO: Teacher with IP address : "+teacherIp+" is disconnected"); 
     TeacherServerScoket.connectedTeacher.remove(getTeacherIp()); 
     if(null!=socket){ 
      socket.close(); 
     } 

    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 




} 

} //class 



public void publishMessageToTeacher(String message){ 

    if(this.socket!=null){ 

     try { 

     PrintWriter writeMessageToTeacher=new PrintWriter(this.socket.getOutputStream()); 
     writeMessageToTeacher.println(message); 
     writeMessageToTeacher.flush(); 
     System.out.println(" Message published to teacher"+message); 
     }catch(Exception e){ 
     logger.error(e.toString()); 
     logger.error("Exception In writing data to teacher"); 

     } 


    }else { 
     logger.error("Unable to publish message to teacher .Socket has Null value in publishMessageToTeacher");  
     System.out.println("ERROR: socket has null value can not publish to teacher"); 
    } 



} 

public String getTeacherIp() 
{ 
    return teacherIp; 

} 
} 

cambiare il codice secondo voi requisito .... ..

+0

Sto usando i thread per leggere e scrivere. Un thread da leggere e l'altro da scrivere. Inoltre, non posso usare PrintWriter poiché devo inviare array di byte primitivi, questo è ciò che sono i miei dati audio. –

0

Il motivo per cui sembra che il mio write() stia bloccando è perché ho stupidamente chiuso Socket() ei miei flussi di input non se ne sono resi conto. Quindi, nessun dato viene mai inviato. Sciocco errore a mio nome.

Problemi correlati