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

2022-09-03 01:32:39

我正在尝试通过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();
}

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


答案 1

我将逐段评论您的代码。

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)

循环和测试都是徒劳的。该变量最初不为空,并且它不可能变为空。循环是徒劳的,因为该方法完全耗尽了输入流,因此再也没有要读取的内容了。这将导致垃圾数据,您没有提到。writeToFile()

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

毫无意义的消息。

             clientSoc.close();

从后面的行到此处的所有代码都应在单独的线程中执行。accept 循环应该只接受连接并启动线程。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();
        }

技术差。这是在错误的地方。依赖于块中代码成功的代码应位于同一块内。目前,您正在通过此情况,就好像异常从未发生过一样,这将导致下面的代码中的a。catchtrytrytry-catchNullPointerException

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

另一个毫无意义的信息。拼写错误; 里面什么都没有; 无论内容如何,都不会打印任何有用的东西;和不正确,因为你根本没有写。sDatasData.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();

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

可能是什么问题?

问题。复数。倍数。见上文。


答案 2

服务器套筒的创建必须在循环之外完成。对于并行连接,您需要为每个连接启动一个线程。

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

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

推荐