2013-01-24 50 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(),我的输入流没有意识到它。因此,没有数据发送出去。愚蠢的错误代表我。