Java 在不关闭套接字的情况下使用套接字交换字符串和二进制数据

Java 在不关闭套接字的情况下使用套接字交换字符串和二进制数据,java,android,sockets,stream,Java,Android,Sockets,Stream,我正在做一个即时消息项目,它的客户端是android,服务器是java 我需要将套接字与流一起使用 这是我的协议(类似HTTP): 假设我想将此消息从客户端发送到服务器 通过这样做,交换标题部分进行得非常顺利 但在服务器端读取二进制数据永远不会完成,服务器将永远处于挂起状态 客户端代码: Socket socket = new Socket(); SocketAddress address = new InetSocketAddress(SERVER_ADDRESS, SERV

我正在做一个即时消息项目,它的客户端是android,服务器是java
我需要将套接字与流一起使用
这是我的协议(类似HTTP):

假设我想将此消息从客户端发送到服务器
通过这样做,交换标题部分进行得非常顺利
但在服务器端读取二进制数据永远不会完成,服务器将永远处于挂起状态

客户端代码:

    Socket socket = new Socket();
    SocketAddress address = new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT);
    try {
        socket.connect(address);
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
        byte[] data = getSomeBinaryData();
        writer.write("Method : attachment" + "\n");
        writer.write("Content-Length : " + data.length + "\n");
        writer.write("\r\n");
        writer.flush();
        out.write(data); // write binary data
        // do more exchange later
    } catch (IOException ex) {
        // handle exception
    }
服务器启动程序代码:

public static void main(String[] args){
    ExecutorService pool = Executors.newFixedThreadPool(50);
    try (ServerSocket server = new ServerSocket(PORT_NUMBER)) {
        while (true) {
            try {
                Socket connection = server.accept();
                Callable<Void> task = new ClientTask(connection);
                pool.submit(task);
            } catch (IOException ex) {}
        }
    } catch (IOException ex) {
        System.err.println("Couldn't start server");
    }
}
publicstaticvoidmain(字符串[]args){
ExecutorService池=Executors.newFixedThreadPool(50);
try(ServerSocket服务器=新的ServerSocket(端口号)){
while(true){
试一试{
套接字连接=server.accept();
可调用任务=新客户端任务(连接);
提交(任务);
}catch(IOException ex){}
}
}捕获(IOEX异常){
System.err.println(“无法启动服务器”);
}
}
每个客户端的服务器任务线程:

class ClientTask implements Callable<Void> {

private Socket connection;
private HashMap<String, String> header = new HashMap<>();
private byte[] content;

ClientTask(Socket c) {
    this.connection = c;
}

@Override
public Void call() throws Exception {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    readHeader(reader);
    System.out.println("incoming message : " + header.get("Method"));
    int contentLength = Integer.parseInt(header.get("Content-Length"));
    content = new byte[contentLength];
    int bytesRead = in.read(content, 0, contentLength);
    System.out.print(bytesRead);
    return null;
}

private void readHeader(BufferedReader reader){
    try {
        char c;
        StringBuilder builder = new StringBuilder();
        while ((c = (char) reader.read()) != '\r'){
            if(c == '\n'){
                String line = builder.toString();
                line = line.replaceAll(" ", "");
                String[] sections = line.split(":");
                header.put(sections[0], sections[1]);
                builder = new StringBuilder();  // clear builder
            }else {
                builder.append(c);
            }
        }
        reader.read();  // skip the last \n character after header
    } catch (IOException e) {
        e.printStackTrace();
    }
}
class ClientTask实现可调用{
专用插座连接;
private HashMap header=new HashMap();
私有字节[]内容;
客户端任务(套接字c){
这个连接=c;
}
@凌驾
public Void call()引发异常{
InputStream in=connection.getInputStream();
BufferedReader=新的BufferedReader(新的InputStreamReader(在“UTF-8”中));
readHeader(读卡器);
System.out.println(“传入消息:”+header.get(“方法”);
int contentLength=Integer.parseInt(header.get(“Content Length”);
content=新字节[contentLength];
int bytesRead=in.read(content,0,contentLength);
系统输出打印(字节读取);
返回null;
}
私有void readHeader(BufferedReader读取器){
试一试{
字符c;
StringBuilder=新的StringBuilder();
而((c=(char)reader.read())!='\r'){
如果(c=='\n'){
String line=builder.toString();
line=line.replaceAll(“,”);
String[]sections=line.split(“:”);
页眉.put(第[0]节、第[1]节);
生成器=新的StringBuilder();//清除生成器
}否则{
附加(c);
}
}
reader.read();//跳过头后面的最后\n个字符
}捕获(IOE异常){
e、 printStackTrace();
}
}

正如詹姆斯所说,我想分享解决方案的线索
也许它能帮助有类似问题的人
在ClientTask类的调用方法中,我应该使用以下代码:

@Override
public Void call() throws Exception {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    readHeader(reader);
    System.out.println("incoming message : " + header.get("Method"));

    // read binary Content
    int bytesRead = 0;
    int bytesToRead = Integer.parseInt(header.get("Content-Length"));
    content = new byte[bytesToRead];
    while (bytesRead < bytesToRead) {
        int result = in.read(content, bytesRead, bytesToRead - bytesRead);
        if (result == -1) 
            break; // end of stream
        bytesRead += result;
    }
    return null;
}
@覆盖
public Void call()引发异常{
InputStream in=connection.getInputStream();
BufferedReader=新的BufferedReader(新的InputStreamReader(在“UTF-8”中));
readHeader(读卡器);
System.out.println(“传入消息:”+header.get(“方法”);
//读取二进制内容
int字节读取=0;
int-bytesToRead=Integer.parseInt(header.get(“内容长度”);
内容=新字节[bytesToRead];
while(bytesRead
@JamesKPolk我正在用
Writer
编写头字符串,用
OutputStream
编写二进制数据。我不知道我怎么会漏掉它。忽略我以前的评论。
ClientTask.call()中的代码
需要循环,直到它接收到预期的数据量,或EOF或套接字异常。不能保证.read(content,0,contentLength)中的
将在一次调用中读取
contentLength
字节。
@Override
public Void call() throws Exception {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    readHeader(reader);
    System.out.println("incoming message : " + header.get("Method"));

    // read binary Content
    int bytesRead = 0;
    int bytesToRead = Integer.parseInt(header.get("Content-Length"));
    content = new byte[bytesToRead];
    while (bytesRead < bytesToRead) {
        int result = in.read(content, bytesRead, bytesToRead - bytesRead);
        if (result == -1) 
            break; // end of stream
        bytesRead += result;
    }
    return null;
}