【问题标题】:How to stream music using java as server?如何使用 java 作为服务器流式传输音乐?
【发布时间】:2012-12-11 22:23:28
【问题描述】:

我正在为 http 尝试一个简单的 java 代码, 如果我使用带有文件位置的 chrome (http://localhost:8888/somefile.mp3) 它工作正常,但如果我在 iphone 上使用 safari,它会抛出错误: java.net.SocketException:管道损坏 但如果我使用 LAMP 或任何 php 服务器,它工作正常。 我怎样才能使它也与 java 一起工作?

这是http服务器:

package com.streamternet;


import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.StringTokenizer;

public class HTTPServer extends Thread {

static final String HTML_START =
        "<html>" +
                "<title>HTTP Server in java</title>" +
                "<body>";

static final String HTML_END =
        "</body>" +
                "</html>";

Socket connectedClient = null;
BufferedReader inFromClient = null;
DataOutputStream outToClient = null;


public HTTPServer(Socket client) {
    connectedClient = client;
}

public void run() {

    try {

        System.out.println( "The Client "+
                connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");

        inFromClient = new BufferedReader(new InputStreamReader (connectedClient.getInputStream()));
        outToClient = new DataOutputStream(connectedClient.getOutputStream());

        String requestString = inFromClient.readLine();
        String headerLine = requestString;

        StringTokenizer tokenizer = new StringTokenizer(headerLine);
        String httpMethod = tokenizer.nextToken();
        String httpQueryString = tokenizer.nextToken();

        StringBuffer responseBuffer = new StringBuffer();
        responseBuffer.append("<b> This is the HTTP Server Home Page.... </b><BR>");
        responseBuffer.append("The HTTP Client request is ....<BR>");

        System.out.println("The HTTP request string is ....");
        while (inFromClient.ready())
        {
            // Read the HTTP complete HTTP Query
            responseBuffer.append(requestString + "<BR>");
            System.out.println(requestString);
            requestString = inFromClient.readLine();
        }

        if (httpMethod.equals("GET")) {
            if (httpQueryString.equals("/")) {
                // The default home page
                sendResponse(200, responseBuffer.toString(), false);
            } else {
                //This is interpreted as a file name
                String fileName = httpQueryString.replaceFirst("/", "");
                fileName = URLDecoder.decode(fileName);
                fileName="/"+fileName;
                if (new File(fileName).isFile()){
                    sendResponse(200, fileName, true);
                }
                else {
                    sendResponse(404, "<b>The Requested resource not found ....</b>", false);
                }
            }
        }
        else sendResponse(404, "<b>The Requested resource not found ...." +
                "Usage: http://127.0.0.1:5000 or http://127.0.0.1:5000/</b>", false);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void sendResponse (int statusCode, String responseString, boolean isFile) throws Exception {

    String statusLine = null;
    String serverdetails = "Server: Java HTTPServer";
    String contentLengthLine = null;
    String fileName = null;
    String contentTypeLine = "Content-Type: text/html" + "\r\n";
    FileInputStream fin = null;

    if (statusCode == 200)
        statusLine = "HTTP/1.1 200 OK" + "\r\n";
    else
        statusLine = "HTTP/1.1 404 Not Found" + "\r\n";

    if (isFile) {
        fileName = responseString;
        fin = new FileInputStream(fileName);
        contentLengthLine = "Content-Length: " + Integer.toString(fin.available()) + "\r\n";
        if (!fileName.endsWith(".htm") && !fileName.endsWith(".html"))
            contentTypeLine = "Content-Type: audio/mpeg\r\n";
    }
    else {
        responseString = HTTPServer.HTML_START + responseString + HTTPServer.HTML_END;
        contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";
    }

    outToClient.writeBytes(statusLine);
    outToClient.writeBytes(serverdetails);
    outToClient.writeBytes(contentTypeLine);
    outToClient.writeBytes(contentLengthLine);
    outToClient.writeBytes("Connection: close\r\n");
    outToClient.writeBytes("\r\n");

    if (isFile) 
        sendFile(fin, outToClient);
    else 
        outToClient.writeBytes(responseString);

    outToClient.close();
}

public void sendFile (FileInputStream fin, DataOutputStream out) throws Exception {
    byte[] buffer = new byte[1024] ;
    int bytesRead;

    while ((bytesRead = fin.read(buffer)) != -1 ) {
        out.write(buffer, 0, bytesRead);
        out.flush();
    }
    fin.close();
}

public static void main (String args[]) throws Exception {

    ServerSocket Server = new ServerSocket (8888);

    System.out.println ("TCPServer Waiting for client on port 8888");

    while(true) {
        Socket connected = Server.accept();
        (new HTTPServer(connected)).start();
    }
}
}

【问题讨论】:

    标签: java stream webserver mp3


    【解决方案1】:

    首先,这不是流媒体,这只是一个普通的 HTTP 请求-响应对话。查看您的服务器,它似乎在很多方面都出现了问题,甚至很难判断 Chrome 为何能够下载任何内容。

    我放了一个minimal HTTP server online,只是为了好玩。它远未完成,它不可配置且仅支持GET 请求,但是我认为如果您不想依赖其他服务器或框架,这是一个很好的起点。它只能给出两种响应:200 OK404 NOT FOUND。在 CLASSPATH 上搜索资源,并与基于扩展的 MIME 类型信息一起发送到客户端。您可能想要添加 MP3 MIME,但请注意,这只是一个玩具,仅用于展示 HTTP 的基础知识。

    代码:

    public class TinyHTTPServer {
    
        public static void main(String[] args) throws IOException {
    
            ServerSocket server = new ServerSocket(8888);
    
            while (true) {
                final Socket connection = server.accept();
                new Thread(new Runnable(){
                    public void run() {
                        RequestHandler handler = new RequestHandler();
                        handler.handle(connection);
                    }
                }).start();
            }
        }
    
        public static class RequestHandler {
    
            public void handle(Socket socket) {
                try {
                    Scanner scanner = new Scanner(socket.getInputStream(), "US-ASCII");
                    String path = getPath(scanner.nextLine());
    
                    Response response = find(path);
    
                    PrintStream out = new PrintStream(socket.getOutputStream());
    
                    for (String header : response.headers) {
                        out.print(header);
                        out.print("\r\n");
                    }
    
                    out.print("\r\n");
                    if (response.url != null)
                        writeEntity(response.url.openStream(), socket.getOutputStream());
                    out.print("\r\n");
    
                    out.flush();
                } catch (Exception exception) {
                    exception.printStackTrace();
                } finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            private String getPath(String requestLine) throws IOException {
                Matcher matcher = Pattern.compile("GET (/\\S*) HTTP/1\\.1").matcher(requestLine);
                matcher.find();
                return matcher.group(1);
            }
    
            private Response find(String path) {
    
                if (path.equals("/"))
                    path = "/index.html";
    
                Response response = new Response();
                URL url = RequestHandler.class.getResource(path);
    
                if (url == null) {
                    response.headers.add("HTTP/1.1 404 NOT FOUND");
                } else {
                    response.url = url;
                    response.headers.add("HTTP/1.1 200 OK");
    
                    String type = "application/octet-stream";
                    String extension = url.toString();
    
                    if (extension.endsWith(".mp3"))
                        type = "audio/mp3";
                    else if (extension.endsWith(".html"))
                        type = "text/html; charset=utf-8";
    
                    response.headers.add("Content-Type: " + type);
                }
    
                return response;
            }
    
            private void writeEntity(InputStream in, OutputStream out) throws IOException {
                byte[] buffer = new byte[1024];
                int read = -1;
    
                while ((read = in.read(buffer, 0, buffer.length)) > -1) {
                    out.write(buffer, 0, read);
                }
            }
    
        }
    
        public static class Response {
    
            public List<String> headers = new LinkedList<String>();
            public URL url;
    
        }
    }
    

    【讨论】:

    • 非常感谢!这实际上解决了问题,现在它在 iphone 上播放。但我不能在这个播放上前进/后退,有没有办法改进这个服务器,让它支持它? (它适用于灯)
    • 没有。 HTTP 是这里的问题。如果您需要流媒体协议,请查看 Adob​​e RTMP。但是,一旦文件完全下载,您当然可以播放、暂停、跳过和快进,但这一切都发生在客户端
    • 同意。我认为他的意思是他可以在其音乐播放器中查找从 Apache 服务器下载的音频文件。 @DimaGoltsman 只是猜测,但也许您可以测量 MP3 并发送 Content-Length 标头
    • @DimaGoltsman 您的评论具有误导性。 PHP 服务器 没有任何东西,也许您想要 Apache httpd,但是当您下载文件时 PHP 不会进入游戏。而且seek发生在客户端,因为在HTTP协议层面,没有办法跳过3分钟、10秒等,尤其是MP3是压缩的,程序无法判断要跳过多少字节在不先解码流的情况下提前 X 秒。请描述您在这两种情况下采取的步骤
    • @DimaGoltsman iOS 使用 HTTP 范围请求。我的小型服务器显然不支持部分内容,但是如果您喜欢填写,您当然可以自己实现该功能。 Here is the relevant RFC
    猜你喜欢
    • 2012-11-23
    • 2011-05-20
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多