12

我有一个 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){}
    }

}

我已经评论了实际代码的很大一部分,因为我只是想让它工作。我的写入功能在第一次写入时无限期阻塞。这可能是我的线程的问题吗?我唯一的想法是输出和输入流共享我的套接字对象,这可能会导致死锁或其他东西。请让我知道发生了什么事。

4

3 回答 3

19

是的,您可以同时写入套接字输入和输出流。

来自do-java-sockets-support-full-duplex

由于输入流和输出流是 Socket 中的独立对象,您唯一可能关心的是,如果您有 2 个线程同时尝试读取或写入(两个线程,相同的输入/输出流)会发生什么时间?InputStream/OutputStream 类的读/写方法不同步。但是,如果您使用 InputStream/OutputStream 的子类,则您调用的读/写方法可能是同步的。您可以检查 javadoc 以了解您正在调用的任何类/方法,并很快找到它。

于 2013-01-24T05:14:45.413 回答
5

是的,您可以在读取时在套接字上写入,但您必须在独立线程中读取套接字。我正在使用这个概念。这里的例子是(仔细阅读它也支持多个客户端):

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;

}
}

根据您的要求更改代码......

于 2013-01-24T05:31:22.603 回答
0

我的 write() 似乎阻塞的原因是我愚蠢地关闭了 Socket() 而我的输入流没有意识到这一点。因此,永远不会发送任何数据。代表我的愚蠢错误。

于 2013-01-24T07:27:02.893 回答