通过TCP套接字将语音写入服务器

时间:2016-01-19 10:31:14

标签: java android sockets tcp stream

我试图通过TCP套接字和服务器将实时麦克风录制传输到服务器,以将输入流写入文件。 建立了连接,但过了一段时间后,我的客户端出现连接拒绝错误。

服务器代码:

    public class auServer extends Thread{
    private static ServerSocket serverSocket;
    private static int port = 3333; 

    public void run()
    {

        System.out.println("init success");
       while(true)
       {

          try
          {
              serverSocket = new ServerSocket(port);
              serverSocket.setSoTimeout(10000);
              Socket clientSoc = serverSocket.accept();
             System.out.println("Waiting for client on port " +serverSocket.getLocalPort() + "...");
             System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());
             InputStream in = clientSoc.getInputStream();
             while(in!=null)
             {
                 writeToFile(in);
             }
             System.out.println("socket");

             clientSoc.close();
          }catch(SocketTimeoutException s)
          {
             System.out.println("Socket timed out!");
             break;
          }catch(IOException e)
          {
             e.printStackTrace();
                     System.out.println("some io");
             break;
          } catch (Exception e) {
                    System.out.println("some e");
            e.printStackTrace();
        }
       }
    }

    private void writeToFile(InputStream in) throws IOException {
        // Write the output audio in byte
        String filePath = "8k16bitMono1.wav";
        short sData[] = new short[1024];
        byte[] bData = IOUtils.toByteArray(in);
        FileOutputStream os = null;
        try {
         os = new FileOutputStream(filePath);
        } catch (FileNotFoundException e) {
         e.printStackTrace();
        }
         System.out.println("Short wirting to file" + sData.toString());
         try {
          os.write(bData, 0, 2048);
         } catch (IOException e) {
          e.printStackTrace();
         }
        try {
         os.close();
        } catch (IOException e) {
         e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
      try
      {
        Thread serverThread = new auServer();
        serverThread.run();
        System.out.println("runing");
       }catch(IOException e){
         e.printStackTrace();
      }
    }
}

和客户:

private void streamData(byte[] bData) throws UnknownHostException, IOException, InterruptedException {  //bData is byte array to transmit
    Thread.sleep(500);
    Socket client = new Socket("10.221.40.41",3333);
    OutputStream outToServer = client.getOutputStream();
    outToServer.write(bData);
    if(!isRecording)
        client.close();
}

可能是什么问题? 提前谢谢。

4 个答案:

答案 0 :(得分:15)

我会逐条评论你的代码。

private static ServerSocket serverSocket;

没有理由不这样做。

while(true)
{
    try
    {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(10000);

最后两行应该在循环之前。这是连接拒绝的原因,它也会导致您没有提及BindExceptions。目前还不清楚为什么需要超时。

             Socket clientSoc = serverSocket.accept();
             System.out.println("Waiting for client on port " +serverSocket.getLocalPort() + "...");

不,你不是。他已经联系了。你在之前等待 accept().

             System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());
             InputStream in = clientSoc.getInputStream();
             while(in!=null)

循环和测试都是徒劳的。变量最初不是null,并且它不可能变为null。循环是徒劳的,因为writeToFile()方法完全耗尽了输入流,所以永远不会有任何东西要阅读。这将导致垃圾数据,你还没有提到。

             {
                 writeToFile(in);
             }
             System.out.println("socket");

毫无意义的消息。

             clientSoc.close();

accept()之后的行中的所有代码都应该在一个单独的线程中执行。接受循环除了接受连接和启动线程之外什么都不做。

          }catch(SocketTimeoutException s)
          {
             System.out.println("Socket timed out!");

这里的时间是accept(),因为侦听套接字是您设置超时的唯一套接字。我怀疑你需要这个。

             break;
          }catch(IOException e)
          {
             e.printStackTrace();
                     System.out.println("some io");

另一个徒劳的信息。

             break;
          } catch (Exception e) {
                    System.out.println("some e");

还有一个。当你收到异常时,打印异常。不是你自己设计的一些徒劳的信息。否则调试就变成了猜测游戏。

            e.printStackTrace();
        }
       }
    }

    private void writeToFile(InputStream in) throws IOException {
        // Write the output audio in byte
        String filePath = "8k16bitMono1.wav";
        short sData[] = new short[1024];

未使用。删除。

        byte[] bData = IOUtils.toByteArray(in);

不要使用它。它浪费空间并增加延迟。请参阅下面的正确解决方案。

        FileOutputStream os = null;
        try {
         os = new FileOutputStream(filePath);
        } catch (FileNotFoundException e) {
         e.printStackTrace();
        }

技术差。这个catch位置错误。取决于try块中代码成功的代码应位于同一try块内。目前您正在考虑这个try-catch,好像从未发生过异常,这将在下面的代码中导致NullPointerException

         System.out.println("Short wirting to file" + sData.toString());

另一个毫无意义的消息。拼写错误; sData中没有任何内容;无论内容如何,​​sData.toString()都不会打印任何有用的内容;并且不正确,因为你根本没有写sData

         try {
          os.write(bData, 0, 2048);

这准确写入2048个字节,无论读取的数量是多少,都可以更少或更多。如果它少了会抛出一个ArrayIndexOutOfBoundsException或类似的,我希望在第二次调用时看到它,虽然你还没有提到它,因为在第二次和后续的调用中数组应该是零长度,如果有的话。它应该是一个循环,一般形式:

int count;
byte[] buffer = new byte[8192]; // or more if you like
while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

返回您的代码:

         } catch (IOException e) {
          e.printStackTrace();
         }
        try {
         os.close();
        } catch (IOException e) {
         e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
      try
      {
        Thread serverThread = new auServer();
        serverThread.run();

这将运行线程的run()方法。它不会启动一个线程。它应该是serverThread.start().

        System.out.println("runing");

拼错。在您修复上述启动/运行问题之前,在服务器的run()方法退出之前,您才会看到此消息。

  

和客户:

private void streamData(byte[] bData) throws UnknownHostException, IOException, InterruptedException {  //bData is byte array to transmit
    Thread.sleep(500);

毫无意义的。去掉。不要把睡眠放入网络代码中。

    Socket client = new Socket("10.221.40.41",3333);

不要为每个缓冲区创建新连接。在客户的生命中使用相同的连接。

    OutputStream outToServer = client.getOutputStream();
    outToServer.write(bData);
    if(!isRecording)
        client.close();

这应该是无条件的,它应该在其他地方,以及套接字的创建。

  

可能是什么问题?

问题。多个。多。见上文。

答案 1 :(得分:3)

必须在循环外部创建serversocket。 对于并行连接,您需要为每个连接启动一个线程。

还将超时应用于已建立的连接。 serverSocket上的超时将在超时后结束,这在服务器中不是你想要的。

...
public void run() {
    ServerSocket serverSocket;
    try {
        serverSocket = new ServerSocket(port);
    } catch (Exception ex) {
        ex.printStackTrace();
        return;
    }

    System.out.println("init success");

    while (true) {
        try {
            System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
            final Socket clientSoc = serverSocket.accept();
            clientSoc.setSoTimeout(10000);

            System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());


            new Thread() {
                public void run() {
                    try {
                        InputStream in = clientSoc.getInputStream();
                        writeToFile(in);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            clientSoc.close();
                        } catch (Exception ignore) {
                        }
                    }
                }
            }.start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
...

答案 2 :(得分:3)

我猜你的客户端是一个Android应用程序。有一次,我尝试通过套接字连接读取和写入数据到Android应用程序。最后,我使用adb(android调试器桥)完成了它。

可以说,有一个java应用程序创建一个端口号为1992的Socket。还有一个android应用程序,它创建一个端口号为1993的ServerSocket

这是真正的交易!

在开始运行应用程序之前,您需要在adb shell中执行以下命令(或者您可以在cmd / terminal中找到您的adb并执行命令)

adb forward tcp:1992 tcp:1993    

转发端口后,您可以使用套接字的IO流将Java应用程序中的数据写入Android应用程序,反之亦然。

桌面应用程序代码段:

while (flag) {
    try {
        final Socket socket = new Socket("localhost", 1992);
        new Thread(){
            @Override
            public void run() {                        
                while (flag) {                            
                    try {
                        new PrintWriter(socket.getOutputStream(), true).println(new Date().toString());
                    } catch (IOException ex) {
                        break;
                    }
                }
            }                    
        }.start();
    } catch (IOException ex) {
        // need port-forwarding
    }
}    

Android应用程序代码段:

while (flag) {
    try {
        final Socket socket = new ServerSocket(1993).accept();
        new AsyncTask<Void, Void, Void>() {
            @Override
            public Void doInBackground(Void... params) {
                while (flag) {
                    try {
                        String line = new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine();
                        Log.d("", line);
                    } catch (IOException ex) {
                        return null;
                    }
                }
                return null;
            }
        }.execute();
    } catch (IOException ex) {
        break;
    }
}    

您可以将音频转换为字节数组并将其写入输出流。希望我的回答很有用。

答案 3 :(得分:1)

我找到了解决方案。 问题实际上是由于错误编码的流阻塞了网络I / O.

我错过的是

InputStream in = clientSoc.getInputStream();
DataInputStream DataIn =new DataInputStream(in)
while(DataIn!=null)
    {
        writeToFile(DataIn);
    }

和客户端

OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.write(sData);