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