HTTP1.1 Connection:keepalive 实现 java 发生 withjava.net.SocketTimeoutException:读取超时
HTTP1.1 Connection:keepalive implement with java occurs withjava.net.SocketTimeoutException: Read timed out
我使用 java 套接字编程实现了 1.1 版的 http 服务器。我使用 1.0 版示例代码,我想通过不关闭套接字来添加持久连接功能 "Connection : close" 发送到服务器。但是,在我的浏览器上输入 "localhost:8080/xxxx" 之后,我遇到了 "java.net.SocketTimeoutException: Read timed out" 信息,并且在使用客户端程序进行测试时没有收到任何信息。代码太长,我在下面提到问题部分!能帮我找出问题吗,谢谢!!!
////////here is the server part using thread pool techs
//Webserver class
protected static Properties props = new Properties();
/* Where worker threads stand idle */
static Vector threads = new Vector();
public static void main(String[] a) throws Exception {
int port = 8080;
if (a.length > 0) {
port = Integer.parseInt(a[0]);
}
loadProps();
printProps();
/* start worker threads */
for (int i = 0; i < workers; ++i) {
Worker w = new Worker();
(new Thread(w, "worker #"+i)).start();
threads.addElement(w);
}
ServerSocket ss = new ServerSocket(port);
while (true) {
Socket s = ss.accept();
Worker w = null;
synchronized (threads) {
if (threads.isEmpty()) {
Worker ws = new Worker();
ws.setSocket(s);
(new Thread(ws, "additional worker")).start();
} else {
w = (Worker) threads.elementAt(0);
threads.removeElementAt(0);
w.setSocket(s);
}
}
}
}
//Worker class inherit from Webserver class
byte[] buf;
Worker() {
buf = new byte[BUF_SIZE];
s = null;
}
synchronized void setSocket(Socket s) {
this.s = s;
notify();
}
public synchronized void run() {
while(true) {
if (s == null) {
/* nothing to do */
try {
wait();
} catch (InterruptedException e) {
/* should not happen */
continue;
}
}
try {
handleClient();
} catch (Exception e) {
e.printStackTrace();
}
/* go back in wait queue if there's fewer
* than numHandler connections.
*/
if(!headAttri.getPersistConnec())
s = null;
//
Vector pool = WebServer.threads;
synchronized (pool) {
if (pool.size() >= WebServer.workers) {
/* too many threads, exit this one */
try{
if(s != null)
s.close();
}catch (IOException e) {
e.printStackTrace();
}
return;
} else {
if(!headAttri.getPersistConnec())
pool.addElement(this);
}
}
}
}
//in handle client I mention the socket handles here(s is the socket)
void handleClient() throws IOException {
//...
s.setSoTimeout(WebServer.timeout);
s.setTcpNoDelay(true);
//...
try{
//...handle request and response the client
//...
}finally{
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
}
else{
s.close();
}
}
}
//////////end server part
//////here is the client part
public SimpleSocketClient()
{
String testServerName = "localhost";
int port = 8080;
try
{
// open a socket
Socket socket = openSocket(testServerName, port);
// write-to, and read-from the socket.
// in this case just write a simple command to a web server.
String result = writeToAndReadFromSocket(socket, request_str[1]);
// print out the result we got back from the server
System.out.println(result);
// close the socket, and we're done
socket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private Socket openSocket(String server, int port) throws Exception
{
Socket socket;
// create a socket with a timeout
try
{
InetAddress inteAddress = InetAddress.getByName(server);
SocketAddress socketAddress = new InetSocketAddress(inteAddress, port);
// create a socket
socket = new Socket();
// this method will block no more than timeout ms.
int timeoutInMs = 10*1000; // 10 seconds
socket.connect(socketAddress, timeoutInMs);
return socket;
}
catch (SocketTimeoutException ste)
{
System.err.println("Timed out waiting for the socket.");
ste.printStackTrace();
throw ste;
}
}
private String writeToAndReadFromSocket(Socket socket, String writeTo) throws Exception
{
try
{
// write text to the socket
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(writeTo);
bufferedWriter.flush();
//test
//bufferedWriter.write("GET src/WebServer.java HTTP/1.1\r\nHost: localhost\r\nConnection: close");
//bufferedWriter.flush();
// read text from the socket
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
//string handling code
String str;
while ((str = bufferedReader.readLine()) != null)
{
sb.append(str + "\n");
}
// close the reader, and return the results as a String
bufferedReader.close();
return sb.toString();
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
}
////end client part
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
很难从您的代码中看出您真正在做什么,但根据此代码片段,您似乎混淆了 HTTP keep alive(即 Connection: keep-alive
处理,单个 TCP 连接中的多个请求) 与 TCP keep alive(检测断开的 TCP 连接)。有关差异的解释,请参阅 and 。
I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server
你不是那样做的。您必须自己关闭连接,或者
收到带有 Connection: close
header 的请求后 并且 您已发送响应,或
当您在读取下一个请求的套接字上读取超时时。
读取超时的长度完全由您决定,因为除了其他事项外,保护自己免受 DOS 攻击取决于您。
NB 调用 Socket.setKeepAlive(true)
与它完全没有任何关系。
注意 2 您应该研究 java.util.concurrent.Executor
而不是实现自己的线程池。
我使用 java 套接字编程实现了 1.1 版的 http 服务器。我使用 1.0 版示例代码,我想通过不关闭套接字来添加持久连接功能 "Connection : close" 发送到服务器。但是,在我的浏览器上输入 "localhost:8080/xxxx" 之后,我遇到了 "java.net.SocketTimeoutException: Read timed out" 信息,并且在使用客户端程序进行测试时没有收到任何信息。代码太长,我在下面提到问题部分!能帮我找出问题吗,谢谢!!!
////////here is the server part using thread pool techs
//Webserver class
protected static Properties props = new Properties();
/* Where worker threads stand idle */
static Vector threads = new Vector();
public static void main(String[] a) throws Exception {
int port = 8080;
if (a.length > 0) {
port = Integer.parseInt(a[0]);
}
loadProps();
printProps();
/* start worker threads */
for (int i = 0; i < workers; ++i) {
Worker w = new Worker();
(new Thread(w, "worker #"+i)).start();
threads.addElement(w);
}
ServerSocket ss = new ServerSocket(port);
while (true) {
Socket s = ss.accept();
Worker w = null;
synchronized (threads) {
if (threads.isEmpty()) {
Worker ws = new Worker();
ws.setSocket(s);
(new Thread(ws, "additional worker")).start();
} else {
w = (Worker) threads.elementAt(0);
threads.removeElementAt(0);
w.setSocket(s);
}
}
}
}
//Worker class inherit from Webserver class
byte[] buf;
Worker() {
buf = new byte[BUF_SIZE];
s = null;
}
synchronized void setSocket(Socket s) {
this.s = s;
notify();
}
public synchronized void run() {
while(true) {
if (s == null) {
/* nothing to do */
try {
wait();
} catch (InterruptedException e) {
/* should not happen */
continue;
}
}
try {
handleClient();
} catch (Exception e) {
e.printStackTrace();
}
/* go back in wait queue if there's fewer
* than numHandler connections.
*/
if(!headAttri.getPersistConnec())
s = null;
//
Vector pool = WebServer.threads;
synchronized (pool) {
if (pool.size() >= WebServer.workers) {
/* too many threads, exit this one */
try{
if(s != null)
s.close();
}catch (IOException e) {
e.printStackTrace();
}
return;
} else {
if(!headAttri.getPersistConnec())
pool.addElement(this);
}
}
}
}
//in handle client I mention the socket handles here(s is the socket)
void handleClient() throws IOException {
//...
s.setSoTimeout(WebServer.timeout);
s.setTcpNoDelay(true);
//...
try{
//...handle request and response the client
//...
}finally{
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
}
else{
s.close();
}
}
}
//////////end server part
//////here is the client part
public SimpleSocketClient()
{
String testServerName = "localhost";
int port = 8080;
try
{
// open a socket
Socket socket = openSocket(testServerName, port);
// write-to, and read-from the socket.
// in this case just write a simple command to a web server.
String result = writeToAndReadFromSocket(socket, request_str[1]);
// print out the result we got back from the server
System.out.println(result);
// close the socket, and we're done
socket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private Socket openSocket(String server, int port) throws Exception
{
Socket socket;
// create a socket with a timeout
try
{
InetAddress inteAddress = InetAddress.getByName(server);
SocketAddress socketAddress = new InetSocketAddress(inteAddress, port);
// create a socket
socket = new Socket();
// this method will block no more than timeout ms.
int timeoutInMs = 10*1000; // 10 seconds
socket.connect(socketAddress, timeoutInMs);
return socket;
}
catch (SocketTimeoutException ste)
{
System.err.println("Timed out waiting for the socket.");
ste.printStackTrace();
throw ste;
}
}
private String writeToAndReadFromSocket(Socket socket, String writeTo) throws Exception
{
try
{
// write text to the socket
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(writeTo);
bufferedWriter.flush();
//test
//bufferedWriter.write("GET src/WebServer.java HTTP/1.1\r\nHost: localhost\r\nConnection: close");
//bufferedWriter.flush();
// read text from the socket
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
//string handling code
String str;
while ((str = bufferedReader.readLine()) != null)
{
sb.append(str + "\n");
}
// close the reader, and return the results as a String
bufferedReader.close();
return sb.toString();
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
}
////end client part
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
很难从您的代码中看出您真正在做什么,但根据此代码片段,您似乎混淆了 HTTP keep alive(即 Connection: keep-alive
处理,单个 TCP 连接中的多个请求) 与 TCP keep alive(检测断开的 TCP 连接)。有关差异的解释,请参阅 and 。
I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server
你不是那样做的。您必须自己关闭连接,或者
收到带有
Connection: close
header 的请求后 并且 您已发送响应,或当您在读取下一个请求的套接字上读取超时时。
读取超时的长度完全由您决定,因为除了其他事项外,保护自己免受 DOS 攻击取决于您。
NB 调用 Socket.setKeepAlive(true)
与它完全没有任何关系。
注意 2 您应该研究 java.util.concurrent.Executor
而不是实现自己的线程池。