我正在使用SocketChannel进行单一连接:
int sampleBufferSize = 50;
StringBuilder data = new StringBuilder();
ByteBuffer bf = ByteBuffer.allocate(sampleBufferSize);
SocketChannel sc = new SocketChannel();
while(true)
if(sc.read(bf) > 0){
bf.flip();
while(bf.hasRemaining())
data.append((char) bf.get());
bf.clear();
}else{
fireDataReceived(data.toString());
data.delete(0, data.length());
}
此代码效率不高,但它在0.05秒内从同一台PC读取130 KB的HTTP POST请求。现在我正在尝试编写一个具有类似功能但使用Socket的类。这是代码:
private static final int TIMEOUT_MILLIS = 50;
private boolean reading = false;
private long readBeginTime = 0;
private StringBuilder buffer = new StringBuilder();
private Thread thread = new Thread(){
public void run(){
while(!isInterrupted()){
try {
int b = getInputStream().read();
if(b == -1){
if(reading)
fireDataReceived();
close();
}else{
if(!reading){
reading = true;
readBeginTime = System.currentTimeMillis();
setSoTimeout(TIMEOUT_MILLIS);
}
buffer.append((char) b);
}
} catch (SocketTimeoutException e){
fireDataReceived();
} catch (IOException e) {
e.printStackTrace();
if(reading)
fireDataReceived();
close();
}
}
}
};
private void fireDataReceived(){
BufferedSocketEvent e = new BufferedSocketEvent(this, System.currentTimeMillis() - readBeginTime, buffer.toString());
buffer.setLength(0);
reading = false;
try {
setSoTimeout(0);
} catch (SocketException e1) {
e1.printStackTrace();
}
for(BufferedSocketListener listener: listeners)
listener.dataReceived(e);
}
问题是同一个请求需要0.4秒,我不知道为什么需要这么长时间。请解释我的代码有什么问题。
答案 0 :(得分:0)
您的流代码的问题在于您一次只读取一个字节,这个字节很慢,并且一次只能附加到StringBuilder
个字节,同上。试试这个:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());
char[] chars = new char[8192];
int count;
while ((count = in.read(chars)) > 0)
{
buffer.append(chars, 0, count);
fireDataReceived();
}
请注意,使用读取超时作为分隔请求的方法并不正确。您需要解析数据才能执行此操作。 TCP是没有消息边界的流协议,并且不保证单独接收单独的发送。
答案 1 :(得分:0)
您必须使用readLine()
或类似方法。 HTTP标头的末尾用空行标记。如果您没有检测到线路,则无法知道何时停止读取数据。依赖超时或TCP片段不是正确的解决方案。如果请求不包含新行,则需要等到一个出现或连接终止/超时。你应该等待至少几秒钟。
我也会摆脱那些听众。能够为单个套接字添加多个侦听器似乎是一个好主意,但对HTTP标头唯一明智的做法是解析它。解析器还需要通知读者何时停止阅读。
我会从这样的事情开始:
ServerSocket serverSocket = new ServerSocket(8888);
Socket clientSocket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ASCII"));
String[] r = reader.readLine().split(" ");
String type = r[0];
String resource = r[1];
String version = r[2];
Map<String, String> headers = new HashMap<String,String>();
while(true) {
String line = reader.readLine();
if(line.isEmpty()) {
break;
}
String headerLine[] = line.split(":",2);
headers.put(headerLine[0],headerLine[1].trim());
}
processHeader(type, resource, version, headers);