Запись звука на сервер через TCP-сокет

Я пытаюсь передать микрофонную запись в реальном времени на сервер через 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(); } 

В чем может быть проблема? Заранее спасибо.

Solutions Collecting From Web of "Запись звука на сервер через TCP-сокет"

Я прокомментирую ваш код по частям.

 private static ServerSocket serverSocket; 

Нет причин для статичности.

 while(true) { try { serverSocket = new ServerSocket(port); serverSocket.setSoTimeout(10000); в 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() здесь должен быть выполнен в отдельном потоке. Контур принятия должен ничего не делать, кроме как принимать соединения и запускать потоки.

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

Это должно быть безусловным, и оно должно быть в другом месте вместе с созданием сокета.

В чем может быть проблема?

Проблемы. Множественное число. Множественный. См. Выше.

Создание serverocket должно выполняться вне цикла. И для параллельных соединений вам нужно запустить поток для каждого соединения.

Также применяйте тайм-аут к установленным соединениям. Тайм-аут на сервере Server прекратит прием после таймаута, это ничего не нужно на сервере.

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

Я предполагаю, что ваша клиентская сторона – приложение для Android. Однажды я попытался прочитать и записать данные в приложение Android через соединение сокета. В конце концов, я сделал это, используя adb (мост отладчика android).

Допустим, есть приложение java, которое создает Socket с номером порта 1992. И есть приложение Android, которое создает ServerSocket с номером порта 1993.

Здесь идет реальная сделка!

Перед запуском приложений вам необходимо выполнить следующую команду в оболочке adb (или вы можете найти свой adb в cmd / terminal и выполнить команду)

 adb forward tcp:1992 tcp:1993 

После перенаправления порта вы можете записывать и считывать данные из приложения 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; } } 

Вы можете преобразовать свой аудио в массив байтов и записать его в выходной поток. Надеюсь, мой ответ будет полезен.

Я понял решение. На самом деле проблема заключалась в блокировке сетевого ввода-вывода из-за неправильно закодированного потока.

То, что я пропустил, было

 InputStream in = clientSoc.getInputStream(); DataInputStream DataIn =new DataInputStream(in) while(DataIn!=null) { writeToFile(DataIn); } в 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);