2013-01-24 51 views
7

我有一個Java應用程序是Voip。我正在使用一個套接字通過線程同時發送和接收信息。代碼如下所示。您可以同時寫入套接字輸入和輸出流嗎?

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(); 

我發現的問題是,當我寫入輸出流時,它會在第一次寫入時阻塞。我發送的字節數不多。貝婁是我寫的代碼。

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){} 
    } 
} 

另一個線程讀取的音頻碼是...

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){} 
    } 

} 

我評論的實際代碼的很大一部分,因爲我只是想獲得它的工作。我的寫入功能在第一次寫入時無限期地阻塞。這可能是我的線程有問題嗎?我唯一的想法是,輸出和輸入流共享我的套接字對象,這可能會導致死鎖或什麼。請讓我知道最新情況。

回答

11

是的,您可以同時寫入套接字輸入和輸出流。

do-java-sockets-support-full-duplex

由於輸入流和輸出流是插座內單獨的對象,唯一的事情,你不妨關注一下,如果你有2個線程試圖讀取或寫入會發生什麼(兩個線程,相同的輸入/輸出流)在同一時間? InputStream/OutputStream類的讀取/寫入方法不同步。但是,如果您使用InputStream/OutputStream的子類,則可能會調用您所調用的讀/寫方法。你可以檢查javadoc是否可以調用你正在調用的任何類/方法,並且可以很快找到它。

+0

我認爲,由於進出(兩個獨立的流)是獨立的對象,同時對它們進行操作應該沒有關係。所以你說我應該仍然擔心同步,不管? –

4

是的,您可以在讀取時在套接字上編寫代碼,但是您必須在獨立線程中讀取套接字。我正在使用這個概念。下面的例子是(仔細閱讀,支持多發客戶端以及):

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(); 

     } 
    } 

} 


} 

要在獨立線程的多個客戶端閱讀:根據您的要求

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; 

} 
} 

改變代碼.... ..

+0

我正在使用線程來讀取和寫入。一個線程讀取,另一個線程寫入。此外,我不能使用PrintWriter,因爲我必須發送原始字節數組,這是我的音頻數據所在。 –

0

它似乎我的寫()阻塞的原因是因爲我愚蠢地關閉了Socket(),我的輸入流沒有意識到它。因此,沒有數據發送出去。愚蠢的錯誤代表我。