HTTP服务器核心就是Socket短连接
先简单说概念:
1、socket就是TCP/IP实现的套接字,就是应用层调用下层服务的接口。
2、短连接指的是连接建立后,双方进行数据交互(通常是一个数据包,也可以是多个),交互完毕后立即关闭连接的TCP/IP实现方式就是常说的短连接,最常见的短连接例子就是HTTP协议。
3、长连接则指的是双方交互完毕后,不关闭连接,而让连接一直空闲着等待下一次交互,这样在一次交互前就免去了再重新建立连接的消耗,本机测试一次 socket连接需要耗时23毫秒。
优点就是性能好。缺点有二,一是实现方式比较复杂,需要单独用线程收,发倒是无所谓;二是需要增加链路检测的机制,由于连接在空闲时双方都无法确认对端是否出现异常退出,因为根据TCP/IP,如果连接的一方正常退出,对端都会收到一个信号,而当一方异常退出时,对端是无法收到信号的,这时就会出现 connection reset、connection reset by peer和broken pipe异常。
接下来说说JAVA如何实现短连接。一、先来看发送到方法,这个比较简单。直接获得socket的OutputStream流,然后用write 方法,flush方法即可。这里要说明的就是,之前认为使用flush方法在底层就是一个TCP包,其实不然,上层何时按照上面策略封装TCP包上层根本无法知道,经过测试可知,下层封装的TCP包大小与flush无必然联系。这里有个参数可以设置,就是 sock.setTcpNoDelay(true),如果设置为true,则对于缓冲区不进行拼接,立即发送。这里涉及nagle算法,用于解决小封包问题,感兴趣的朋友可以自己搜索
热身运动
Java代码
1. /**
2. * 单个文件的HTTP Server,输入本机地址,返回d:/index.html文件
3. */
4. public class SingleFileHttpServer extends Thread {
5.
6. private byte[] content;
7. private byte[] header;
8. private int port;
9.
10. public SingleFileHttpServer(byte[] data, String encoding, String MIMEType) throws UnsupportedEncodingException {
11. this.content = data;
12. this.port = 80;
13. String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0 \r\n"
14. + "Content-length: " + this.content.length
15. + "\r\n" + "Content-type: " + MIMEType + "\r\n";
16. this.header = header.getBytes(encoding);
17. }
18.
19. public void run() {
20. ServerSocket server;
21. try {
22. server = new ServerSocket(port);
23. System.out.println("Accepting connections on port " + server.getLocalPort());
24. System.out.println("Data to be sent:");
25. System.out.write(this.content);
26. while (true) {
27. Socket conn = null;
28. try {
29. conn = server.accept();
30. OutputStream out = conn.getOutputStream();
31. InputStream in = conn.getInputStream();
32. int temp;
33. StringBuilder request = new StringBuilder();
34. if ((temp = in.read()) != -1)
35. request.append((char) temp);
36. if (request.toString().indexOf("HTTP/") != -1)
37. out.write(header);
38. out.write(content);
39. out.flush();
40. } catch (IOException e) {
41. throw new RuntimeException(e);
42. } finally {
43. conn.close();
44. }
45. }
46. } catch (IOException e) {
47. throw new RuntimeException(e);
48. }
49. }
50.
51. public static void main(String[] args) {
52. try {
53. String encoding = "ASCII";
54. String fileName = "D:/index.html";
55. String contentType = "text/plain";
56. if (fileName.endsWith("html") || fileName.endsWith("htm"))
57. contentType = "text/html";
58. InputStream in = new FileInputStream(new File(fileName));
59. ByteArrayOutputStream baos = new ByteArrayOutputStream();
60. int temp;
61. while ((temp = in.read()) != -1)
62. baos.write(temp);
63. byte[] data = baos.toByteArray();
64. SingleFileHttpServer server =
65. new SingleFileHttpServer(data, encoding, contentType);
66. server.start();
67. } catch (FileNotFoundException e) {
68. } catch (IOException e) {
69. }
70. }
71. }
72.
73.
74. /**
75. * 跳转地址,输入本机地址,自动跳转到sina
76. */
77. public class Redirector implements Runnable {
78.
79. private int port;
80. private String siteUrl;
81.
82. public Redirector(int port, String siteUrl) {
83. this.port = port;
84. this.siteUrl = siteUrl;
85. }
86.
87. public void run() {
88. try {
89. ServerSocket server = new ServerSocket(port);
90. while (true) {
91. Socket conn = server.accept();
92. Thread t = new RedirectThread(conn);
93. t.start();
94. }
95. } catch (IOException e) {
96. throw new RuntimeException(e);
97. }
98. }
99. private class RedirectThread extends Thread {
100.
101. private Socket conn;
102.
103. public RedirectThread(Socket conn) {
104. this.conn = conn;
105. }
106.
107. public void run() {
108. try {
109. Writer out = new OutputStreamWriter(conn.getOutputStream());
110. Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
111. StringBuilder sb = new StringBuilder();
112. int temp;
113. while (true) {
114. temp = in.read();
115. if (temp == '\r' || temp == '\n' || temp == -1)
116. break;
117. sb.append((char) temp);
118. }
119. String request = sb.toString();
120. int firstSpace = request.indexOf(' ');
121. int secondSpace = request.indexOf(' ', firstSpace + 1);
122. String theFile = request.substring(firstSpace + 1, secondSpace);
123. if (request.indexOf("HTTP") != -1) {
124. // 这是一个HTTP响应码,告知客户端要被重定向
125. out.write("HTTP/1.0 302 FOUND\r\n");
126. // 服务器当前时间
127. out.write("Date: " + new Date() + "\r\n");
128. // 服务器的名称和版本【可选的】
129. out.write("Server: Redirector 1.0\r\n");
130. // 告知要重定向的位置,浏览器会自动跳转
131. out.write("Location: " + siteUrl + theFile + "\r\n");
132. // 指示客户端看到的是HTML,发送一个空行表明结束
133. out.write("Content-type: text/html\r\n\r\n");
134. out.flush();
135. }
136. // 有些老浏览器,不支持redirection,我们需要生成HTML说明
137. out.write("<HTML><HEAD><TITLE>Document moved</TITLE></HEAD>\r\n");
138. out.write("<BODY><H1>Document moved</H1>\r\n");
139. out.write("The document " + theFile + " has moved to\r\n<A HREF=\""
140. + siteUrl + theFile + "\">" + siteUrl + theFile
141. + "</A>.\r\n Please update your bookmarks<P>");
142. out.write("</BODY></HTML>\r\n");
143. out.flush();
144. } catch (IOException e) {
145. throw new RuntimeException(e);
146. } finally {
147. if (conn != null)
148. try {
149. conn.close();
150. } catch (IOException e) {
151. throw new RuntimeException(e);
152. }
153. }
154. }
155. }
156.
157. public static void main(String[] args) {
158. int port = 80;
159. String siteUrl = "http://www.sina.com.cn";
160. Thread server = new Thread(new Redirector(port, siteUrl));
161. server.start();
162. }
163. }
/**
* 单个文件的HTTP Server,输入本机地址,返回d:/index.html文件
*/
public class SingleFileHttpServer extends Thread {
private byte[] content;
private byte[] header;
private int port;
public SingleFileHttpServer(byte[] data, String encoding, String MIMEType) throws UnsupportedEncodingException {
this.content = data;
this.port = 80;
String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0 \r\n"
+ "Content-length: " + this.content.length
+ "\r\n" + "Content-type: " + MIMEType + "\r\n";
this.header = header.getBytes(encoding);
}
public void run() {
ServerSocket server;
try {
server = new ServerSocket(port);
System.out.println("Accepting connections on port " + server.getLocalPort());
System.out.println("Data to be sent:");
System.out.write(this.content);
while (true) {
Socket conn = null;
try {
conn = server.accept();
OutputStream out = conn.getOutputStream();
InputStream in = conn.getInputStream();
int temp;
StringBuilder request = new StringBuilder();
if ((temp = in.read()) != -1)
request.append((char) temp);
if (request.toString().indexOf("HTTP/") != -1)
out.write(header);
out.write(content);
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
conn.close();
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
try {
String encoding = "ASCII";
String fileName = "D:/index.html";
String contentType = "text/plain";
if (fileName.endsWith("html") || fileName.endsWith("htm"))
contentType = "text/html";
InputStream in = new FileInputStream(new File(fileName));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int temp;
while ((temp = in.read()) != -1)
baos.write(temp);
byte[] data = baos.toByteArray();
SingleFileHttpServer server =
new SingleFileHttpServer(data, encoding, contentType);
server.start();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
/**
* 跳转地址,输入本机地址,自动跳转到sina
*/
public class Redirector implements Runnable {
private int port;
private String siteUrl;
public Redirector(int port, String siteUrl) {
this.port = port;
this.siteUrl = siteUrl;
}
public void run() {
try {
ServerSocket server = new ServerSocket(port);
while (true) {
Socket conn = server.accept();
Thread t = new RedirectThread(conn);
t.start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private class RedirectThread extends Thread {
private Socket conn;
public RedirectThread(Socket conn) {
this.conn = conn;
}
public void run() {
try {
Writer out = new OutputStreamWriter(conn.getOutputStream());
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
int temp;
while (true) {
temp = in.read();
if (temp == '\r' || temp == '\n' || temp == -1)
break;
sb.append((char) temp);
}
String request = sb.toString();
int firstSpace = request.indexOf(' ');
int secondSpace = request.indexOf(' ', firstSpace + 1);
String theFile = request.substring(firstSpace + 1, secondSpace);
if (request.indexOf("HTTP") != -1) {
// 这是一个HTTP响应码,告知客户端要被重定向
out.write("HTTP/1.0 302 FOUND\r\n");
// 服务器当前时间
out.write("Date: " + new Date() + "\r\n");
// 服务器的名称和版本【可选的】
out.write("Server: Redirector 1.0\r\n");
// 告知要重定向的位置,浏览器会自动跳转
out.write("Location: " + siteUrl + theFile + "\r\n");
// 指示客户端看到的是HTML,发送一个空行表明结束
out.write("Content-type: text/html\r\n\r\n");
out.flush();
}
// 有些老浏览器,不支持redirection,我们需要生成HTML说明
out.write("<HTML><HEAD><TITLE>Document moved</TITLE></HEAD>\r\n");
out.write("<BODY><H1>Document moved</H1>\r\n");
out.write("The document " + theFile + " has moved to\r\n<A HREF=\""
+ siteUrl + theFile + "\">" + siteUrl + theFile
+ "</A>.\r\n Please update your bookmarks<P>");
out.write("</BODY></HTML>\r\n");
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null)
try {
conn.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
int port = 80;
String siteUrl = "http://www.sina.com.cn";
Thread server = new Thread(new Redirector(port, siteUrl));
server.start();
}
}
核心开始
Java代码
1. /**
2. * Java版 HTTP服务器
3. */
4. public class JHTTPServer extends Thread {
5.
6. private File docRootDir;
7. private String indexFileName;
8. private ServerSocket server;
9. private int numThread = 50;
10.
11. public JHTTPServer(File docRootDir) throws IOException {
12. this(docRootDir, 80, "index.html");
13. }
14.
15. public JHTTPServer(File docRootDir, int port, String indexFileName)
16. throws IOException {
17. this.docRootDir = docRootDir;
18. this.indexFileName = indexFileName;
19. server = new ServerSocket(port);
20. }
21.
22. public void run() {
23. for (int i = 0; i < numThread; i++) {
24. Thread t = new Thread(new RequestProcessor(docRootDir, indexFileName));
25. t.start();
26. }
27. System.out.println("Accepting connections on port " + server.getLocalPort());
28. System.out.println("Document Root: " + docRootDir);
29. while(true){
30. try {
31. Socket conn = server.accept();
32. RequestProcessor.processRequest(conn);
33. } catch (IOException e) {
34. throw new RuntimeException(e);
35. }
36. }
37. }
38.
39. public static void main(String[] args) {
40. File docRoot = new File("D:/src/HTML_CSS");
41. try {
42. new JHTTPServer(docRoot).start();
43. } catch (IOException e) {
44. System.out.println("Server could not start because of an " + e.getClass());
45. System.out.println(e);
46. }
47. }
48. }
49.
50. /**
51. * 服务线程池
52. */
53. public class RequestProcessor implements Runnable {
54.
55. private static List<Socket> pool = new LinkedList<Socket>();
56. private File docRootDir;
57. private String indexFileName;
58.
59. public RequestProcessor(File docRootDir, String indexFileName) {
60. if (docRootDir.isFile())
61. throw new IllegalArgumentException(
62. "documentRootDirectory must be a directory, not a file");
63. this.docRootDir = docRootDir;
64. try {
65. this.docRootDir = docRootDir.getCanonicalFile();
66. } catch (IOException ex) {
67. }
68. this.indexFileName = indexFileName;
69. }
70.
71. public static void processRequest(Socket conn) {
72. synchronized (pool) {
73. pool.add(pool.size(), conn);
74. pool.notifyAll();
75. }
76. }
77.
78. public void run() {
79. String root = docRootDir.getPath();
80. while (true) {
81. Socket conn;
82. synchronized (pool) {
83. while (pool.isEmpty()) {
84. try {
85. pool.wait();
86. } catch (InterruptedException e) {
87. throw new RuntimeException(e);
88. }
89. }
90. conn = pool.remove(0);
91. }
92. try {
93. OutputStream raw = new BufferedOutputStream(conn.getOutputStream());
94. Writer out = new OutputStreamWriter(raw);
95. Reader in = new InputStreamReader(new BufferedInputStream(conn.getInputStream()));
96. StringBuilder request = new StringBuilder();
97. int c;
98. while (true) {
99. c = in.read();
100. if (c == '\r' || c == '\n')
101. break;
102. request.append((char) c);
103. }
104. String get = request.toString();
105. // 记录请求日志
106. System.out.println(get);
107. StringTokenizer st = new StringTokenizer(get);
108. String method = st.nextToken();
109. String version = "", fileName, contentType;
110. if (method.equals("GET")) {
111. fileName = st.nextToken();
112. if (fileName.endsWith("/"))
113. fileName += indexFileName;
114. contentType = guessContentTypeFromName(fileName);
115. if (st.hasMoreTokens())
116. version = st.nextToken();
117. File theFile = new File(docRootDir, fileName.substring(1, fileName.length()));
118. // 不让请求超出文档根目录
119. if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) {
120. DataInputStream dis = new DataInputStream(
121. new BufferedInputStream(new FileInputStream(theFile)));
122. byte[] theData = new byte[(int) theFile.length()];
123. dis.readFully(theData);
124. dis.close();
125. if (version.startsWith("HTTP ")) {
126. out.write("HTTP/1.0 200 OK\r\n");
127. out.write("Date" + new Date() + "\r\n");
128. out.write("Server: JHTTP/1.0\r\n");
129. out.write("Content-length: " + theData.length + "\r\n");
130. out.write("Content-type: " + contentType + "\r\n\r\n");
131. out.flush();
132. }
133. // 发送文件,可能是图片或其它二进制数据,所以使用底层的输出流不是书写器
134. raw.write(theData);
135. raw.flush();
136. } else { // 没有找到文件
137. if (version.startsWith("HTTP ")) { // send a MIME header
138. out.write("HTTP/1.0 404 File Not Found\r\n");
139. Date now = new Date();
140. out.write("Date: " + now + "\r\n");
141. out.write("Server: JHTTP/1.0\r\n");
142. out.write("Content-type: text/html\r\n\r\n");
143. }
144. out.write("<HTML>\r\n");
145. out.write("<HEAD><TITLE>File Not Found</TITLE>\r\n");
146. out.write("</HEAD>\r\n");
147. out.write("<BODY>");
148. out.write("<H1>HTTP Error 404: File Not Found</H1>\r\n");
149. out.write("</BODY></HTML>\r\n");
150. out.flush();
151. }
152. } else { // method does not equal "GET"
153. if (version.startsWith("HTTP ")) { // send a MIME header
154. out.write("HTTP/1.0 501 Not Implemented\r\n");
155. Date now = new Date();
156. out.write("Date: " + now + "\r\n");
157. out.write("Server: JHTTP 1.0\r\n");
158. out.write("Content-type: text/html\r\n\r\n");
159. }
160. out.write("<HTML>\r\n");
161. out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
162. out.write("</HEAD>\r\n");
163. out.write("<BODY>");
164. out.write("<H1>HTTP Error 501: Not Implemented</H1>\r\n");
165. out.write("</BODY></HTML>\r\n");
166. out.flush();
167. }
168. } catch (IOException e) {
169. throw new RuntimeException(e);
170. } finally {
171. try {
172. conn.close();
173. } catch (IOException ex) {}
174. }
175. }
176. }
177.
178. private String guessContentTypeFromName(String name) {
179. if (name.endsWith(".html") || name.endsWith(".htm")) {
180. return "text/html";
181. } else if (name.endsWith(".txt") || name.endsWith(".java")) {
182. return "text/plain";
183. } else if (name.endsWith(".gif")) {
184. return "image/gif";
185. } else if (name.endsWith(".class")) {
186. return "application/octet-stream";
187. } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) {
188. return "image/jpeg";
189. } else
190. return "text/plain";
191. }
192. }
先简单说概念:
1、socket就是TCP/IP实现的套接字,就是应用层调用下层服务的接口。
2、短连接指的是连接建立后,双方进行数据交互(通常是一个数据包,也可以是多个),交互完毕后立即关闭连接的TCP/IP实现方式就是常说的短连接,最常见的短连接例子就是HTTP协议。
3、长连接则指的是双方交互完毕后,不关闭连接,而让连接一直空闲着等待下一次交互,这样在一次交互前就免去了再重新建立连接的消耗,本机测试一次 socket连接需要耗时23毫秒。
优点就是性能好。缺点有二,一是实现方式比较复杂,需要单独用线程收,发倒是无所谓;二是需要增加链路检测的机制,由于连接在空闲时双方都无法确认对端是否出现异常退出,因为根据TCP/IP,如果连接的一方正常退出,对端都会收到一个信号,而当一方异常退出时,对端是无法收到信号的,这时就会出现 connection reset、connection reset by peer和broken pipe异常。
接下来说说JAVA如何实现短连接。一、先来看发送到方法,这个比较简单。直接获得socket的OutputStream流,然后用write 方法,flush方法即可。这里要说明的就是,之前认为使用flush方法在底层就是一个TCP包,其实不然,上层何时按照上面策略封装TCP包上层根本无法知道,经过测试可知,下层封装的TCP包大小与flush无必然联系。这里有个参数可以设置,就是 sock.setTcpNoDelay(true),如果设置为true,则对于缓冲区不进行拼接,立即发送。这里涉及nagle算法,用于解决小封包问题,感兴趣的朋友可以自己搜索
热身运动
Java代码
1. /**
2. * 单个文件的HTTP Server,输入本机地址,返回d:/index.html文件
3. */
4. public class SingleFileHttpServer extends Thread {
5.
6. private byte[] content;
7. private byte[] header;
8. private int port;
9.
10. public SingleFileHttpServer(byte[] data, String encoding, String MIMEType) throws UnsupportedEncodingException {
11. this.content = data;
12. this.port = 80;
13. String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0 \r\n"
14. + "Content-length: " + this.content.length
15. + "\r\n" + "Content-type: " + MIMEType + "\r\n";
16. this.header = header.getBytes(encoding);
17. }
18.
19. public void run() {
20. ServerSocket server;
21. try {
22. server = new ServerSocket(port);
23. System.out.println("Accepting connections on port " + server.getLocalPort());
24. System.out.println("Data to be sent:");
25. System.out.write(this.content);
26. while (true) {
27. Socket conn = null;
28. try {
29. conn = server.accept();
30. OutputStream out = conn.getOutputStream();
31. InputStream in = conn.getInputStream();
32. int temp;
33. StringBuilder request = new StringBuilder();
34. if ((temp = in.read()) != -1)
35. request.append((char) temp);
36. if (request.toString().indexOf("HTTP/") != -1)
37. out.write(header);
38. out.write(content);
39. out.flush();
40. } catch (IOException e) {
41. throw new RuntimeException(e);
42. } finally {
43. conn.close();
44. }
45. }
46. } catch (IOException e) {
47. throw new RuntimeException(e);
48. }
49. }
50.
51. public static void main(String[] args) {
52. try {
53. String encoding = "ASCII";
54. String fileName = "D:/index.html";
55. String contentType = "text/plain";
56. if (fileName.endsWith("html") || fileName.endsWith("htm"))
57. contentType = "text/html";
58. InputStream in = new FileInputStream(new File(fileName));
59. ByteArrayOutputStream baos = new ByteArrayOutputStream();
60. int temp;
61. while ((temp = in.read()) != -1)
62. baos.write(temp);
63. byte[] data = baos.toByteArray();
64. SingleFileHttpServer server =
65. new SingleFileHttpServer(data, encoding, contentType);
66. server.start();
67. } catch (FileNotFoundException e) {
68. } catch (IOException e) {
69. }
70. }
71. }
72.
73.
74. /**
75. * 跳转地址,输入本机地址,自动跳转到sina
76. */
77. public class Redirector implements Runnable {
78.
79. private int port;
80. private String siteUrl;
81.
82. public Redirector(int port, String siteUrl) {
83. this.port = port;
84. this.siteUrl = siteUrl;
85. }
86.
87. public void run() {
88. try {
89. ServerSocket server = new ServerSocket(port);
90. while (true) {
91. Socket conn = server.accept();
92. Thread t = new RedirectThread(conn);
93. t.start();
94. }
95. } catch (IOException e) {
96. throw new RuntimeException(e);
97. }
98. }
99. private class RedirectThread extends Thread {
100.
101. private Socket conn;
102.
103. public RedirectThread(Socket conn) {
104. this.conn = conn;
105. }
106.
107. public void run() {
108. try {
109. Writer out = new OutputStreamWriter(conn.getOutputStream());
110. Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
111. StringBuilder sb = new StringBuilder();
112. int temp;
113. while (true) {
114. temp = in.read();
115. if (temp == '\r' || temp == '\n' || temp == -1)
116. break;
117. sb.append((char) temp);
118. }
119. String request = sb.toString();
120. int firstSpace = request.indexOf(' ');
121. int secondSpace = request.indexOf(' ', firstSpace + 1);
122. String theFile = request.substring(firstSpace + 1, secondSpace);
123. if (request.indexOf("HTTP") != -1) {
124. // 这是一个HTTP响应码,告知客户端要被重定向
125. out.write("HTTP/1.0 302 FOUND\r\n");
126. // 服务器当前时间
127. out.write("Date: " + new Date() + "\r\n");
128. // 服务器的名称和版本【可选的】
129. out.write("Server: Redirector 1.0\r\n");
130. // 告知要重定向的位置,浏览器会自动跳转
131. out.write("Location: " + siteUrl + theFile + "\r\n");
132. // 指示客户端看到的是HTML,发送一个空行表明结束
133. out.write("Content-type: text/html\r\n\r\n");
134. out.flush();
135. }
136. // 有些老浏览器,不支持redirection,我们需要生成HTML说明
137. out.write("<HTML><HEAD><TITLE>Document moved</TITLE></HEAD>\r\n");
138. out.write("<BODY><H1>Document moved</H1>\r\n");
139. out.write("The document " + theFile + " has moved to\r\n<A HREF=\""
140. + siteUrl + theFile + "\">" + siteUrl + theFile
141. + "</A>.\r\n Please update your bookmarks<P>");
142. out.write("</BODY></HTML>\r\n");
143. out.flush();
144. } catch (IOException e) {
145. throw new RuntimeException(e);
146. } finally {
147. if (conn != null)
148. try {
149. conn.close();
150. } catch (IOException e) {
151. throw new RuntimeException(e);
152. }
153. }
154. }
155. }
156.
157. public static void main(String[] args) {
158. int port = 80;
159. String siteUrl = "http://www.sina.com.cn";
160. Thread server = new Thread(new Redirector(port, siteUrl));
161. server.start();
162. }
163. }
/**
* 单个文件的HTTP Server,输入本机地址,返回d:/index.html文件
*/
public class SingleFileHttpServer extends Thread {
private byte[] content;
private byte[] header;
private int port;
public SingleFileHttpServer(byte[] data, String encoding, String MIMEType) throws UnsupportedEncodingException {
this.content = data;
this.port = 80;
String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0 \r\n"
+ "Content-length: " + this.content.length
+ "\r\n" + "Content-type: " + MIMEType + "\r\n";
this.header = header.getBytes(encoding);
}
public void run() {
ServerSocket server;
try {
server = new ServerSocket(port);
System.out.println("Accepting connections on port " + server.getLocalPort());
System.out.println("Data to be sent:");
System.out.write(this.content);
while (true) {
Socket conn = null;
try {
conn = server.accept();
OutputStream out = conn.getOutputStream();
InputStream in = conn.getInputStream();
int temp;
StringBuilder request = new StringBuilder();
if ((temp = in.read()) != -1)
request.append((char) temp);
if (request.toString().indexOf("HTTP/") != -1)
out.write(header);
out.write(content);
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
conn.close();
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
try {
String encoding = "ASCII";
String fileName = "D:/index.html";
String contentType = "text/plain";
if (fileName.endsWith("html") || fileName.endsWith("htm"))
contentType = "text/html";
InputStream in = new FileInputStream(new File(fileName));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int temp;
while ((temp = in.read()) != -1)
baos.write(temp);
byte[] data = baos.toByteArray();
SingleFileHttpServer server =
new SingleFileHttpServer(data, encoding, contentType);
server.start();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
/**
* 跳转地址,输入本机地址,自动跳转到sina
*/
public class Redirector implements Runnable {
private int port;
private String siteUrl;
public Redirector(int port, String siteUrl) {
this.port = port;
this.siteUrl = siteUrl;
}
public void run() {
try {
ServerSocket server = new ServerSocket(port);
while (true) {
Socket conn = server.accept();
Thread t = new RedirectThread(conn);
t.start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private class RedirectThread extends Thread {
private Socket conn;
public RedirectThread(Socket conn) {
this.conn = conn;
}
public void run() {
try {
Writer out = new OutputStreamWriter(conn.getOutputStream());
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
int temp;
while (true) {
temp = in.read();
if (temp == '\r' || temp == '\n' || temp == -1)
break;
sb.append((char) temp);
}
String request = sb.toString();
int firstSpace = request.indexOf(' ');
int secondSpace = request.indexOf(' ', firstSpace + 1);
String theFile = request.substring(firstSpace + 1, secondSpace);
if (request.indexOf("HTTP") != -1) {
// 这是一个HTTP响应码,告知客户端要被重定向
out.write("HTTP/1.0 302 FOUND\r\n");
// 服务器当前时间
out.write("Date: " + new Date() + "\r\n");
// 服务器的名称和版本【可选的】
out.write("Server: Redirector 1.0\r\n");
// 告知要重定向的位置,浏览器会自动跳转
out.write("Location: " + siteUrl + theFile + "\r\n");
// 指示客户端看到的是HTML,发送一个空行表明结束
out.write("Content-type: text/html\r\n\r\n");
out.flush();
}
// 有些老浏览器,不支持redirection,我们需要生成HTML说明
out.write("<HTML><HEAD><TITLE>Document moved</TITLE></HEAD>\r\n");
out.write("<BODY><H1>Document moved</H1>\r\n");
out.write("The document " + theFile + " has moved to\r\n<A HREF=\""
+ siteUrl + theFile + "\">" + siteUrl + theFile
+ "</A>.\r\n Please update your bookmarks<P>");
out.write("</BODY></HTML>\r\n");
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null)
try {
conn.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
int port = 80;
String siteUrl = "http://www.sina.com.cn";
Thread server = new Thread(new Redirector(port, siteUrl));
server.start();
}
}
核心开始
Java代码
1. /**
2. * Java版 HTTP服务器
3. */
4. public class JHTTPServer extends Thread {
5.
6. private File docRootDir;
7. private String indexFileName;
8. private ServerSocket server;
9. private int numThread = 50;
10.
11. public JHTTPServer(File docRootDir) throws IOException {
12. this(docRootDir, 80, "index.html");
13. }
14.
15. public JHTTPServer(File docRootDir, int port, String indexFileName)
16. throws IOException {
17. this.docRootDir = docRootDir;
18. this.indexFileName = indexFileName;
19. server = new ServerSocket(port);
20. }
21.
22. public void run() {
23. for (int i = 0; i < numThread; i++) {
24. Thread t = new Thread(new RequestProcessor(docRootDir, indexFileName));
25. t.start();
26. }
27. System.out.println("Accepting connections on port " + server.getLocalPort());
28. System.out.println("Document Root: " + docRootDir);
29. while(true){
30. try {
31. Socket conn = server.accept();
32. RequestProcessor.processRequest(conn);
33. } catch (IOException e) {
34. throw new RuntimeException(e);
35. }
36. }
37. }
38.
39. public static void main(String[] args) {
40. File docRoot = new File("D:/src/HTML_CSS");
41. try {
42. new JHTTPServer(docRoot).start();
43. } catch (IOException e) {
44. System.out.println("Server could not start because of an " + e.getClass());
45. System.out.println(e);
46. }
47. }
48. }
49.
50. /**
51. * 服务线程池
52. */
53. public class RequestProcessor implements Runnable {
54.
55. private static List<Socket> pool = new LinkedList<Socket>();
56. private File docRootDir;
57. private String indexFileName;
58.
59. public RequestProcessor(File docRootDir, String indexFileName) {
60. if (docRootDir.isFile())
61. throw new IllegalArgumentException(
62. "documentRootDirectory must be a directory, not a file");
63. this.docRootDir = docRootDir;
64. try {
65. this.docRootDir = docRootDir.getCanonicalFile();
66. } catch (IOException ex) {
67. }
68. this.indexFileName = indexFileName;
69. }
70.
71. public static void processRequest(Socket conn) {
72. synchronized (pool) {
73. pool.add(pool.size(), conn);
74. pool.notifyAll();
75. }
76. }
77.
78. public void run() {
79. String root = docRootDir.getPath();
80. while (true) {
81. Socket conn;
82. synchronized (pool) {
83. while (pool.isEmpty()) {
84. try {
85. pool.wait();
86. } catch (InterruptedException e) {
87. throw new RuntimeException(e);
88. }
89. }
90. conn = pool.remove(0);
91. }
92. try {
93. OutputStream raw = new BufferedOutputStream(conn.getOutputStream());
94. Writer out = new OutputStreamWriter(raw);
95. Reader in = new InputStreamReader(new BufferedInputStream(conn.getInputStream()));
96. StringBuilder request = new StringBuilder();
97. int c;
98. while (true) {
99. c = in.read();
100. if (c == '\r' || c == '\n')
101. break;
102. request.append((char) c);
103. }
104. String get = request.toString();
105. // 记录请求日志
106. System.out.println(get);
107. StringTokenizer st = new StringTokenizer(get);
108. String method = st.nextToken();
109. String version = "", fileName, contentType;
110. if (method.equals("GET")) {
111. fileName = st.nextToken();
112. if (fileName.endsWith("/"))
113. fileName += indexFileName;
114. contentType = guessContentTypeFromName(fileName);
115. if (st.hasMoreTokens())
116. version = st.nextToken();
117. File theFile = new File(docRootDir, fileName.substring(1, fileName.length()));
118. // 不让请求超出文档根目录
119. if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) {
120. DataInputStream dis = new DataInputStream(
121. new BufferedInputStream(new FileInputStream(theFile)));
122. byte[] theData = new byte[(int) theFile.length()];
123. dis.readFully(theData);
124. dis.close();
125. if (version.startsWith("HTTP ")) {
126. out.write("HTTP/1.0 200 OK\r\n");
127. out.write("Date" + new Date() + "\r\n");
128. out.write("Server: JHTTP/1.0\r\n");
129. out.write("Content-length: " + theData.length + "\r\n");
130. out.write("Content-type: " + contentType + "\r\n\r\n");
131. out.flush();
132. }
133. // 发送文件,可能是图片或其它二进制数据,所以使用底层的输出流不是书写器
134. raw.write(theData);
135. raw.flush();
136. } else { // 没有找到文件
137. if (version.startsWith("HTTP ")) { // send a MIME header
138. out.write("HTTP/1.0 404 File Not Found\r\n");
139. Date now = new Date();
140. out.write("Date: " + now + "\r\n");
141. out.write("Server: JHTTP/1.0\r\n");
142. out.write("Content-type: text/html\r\n\r\n");
143. }
144. out.write("<HTML>\r\n");
145. out.write("<HEAD><TITLE>File Not Found</TITLE>\r\n");
146. out.write("</HEAD>\r\n");
147. out.write("<BODY>");
148. out.write("<H1>HTTP Error 404: File Not Found</H1>\r\n");
149. out.write("</BODY></HTML>\r\n");
150. out.flush();
151. }
152. } else { // method does not equal "GET"
153. if (version.startsWith("HTTP ")) { // send a MIME header
154. out.write("HTTP/1.0 501 Not Implemented\r\n");
155. Date now = new Date();
156. out.write("Date: " + now + "\r\n");
157. out.write("Server: JHTTP 1.0\r\n");
158. out.write("Content-type: text/html\r\n\r\n");
159. }
160. out.write("<HTML>\r\n");
161. out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
162. out.write("</HEAD>\r\n");
163. out.write("<BODY>");
164. out.write("<H1>HTTP Error 501: Not Implemented</H1>\r\n");
165. out.write("</BODY></HTML>\r\n");
166. out.flush();
167. }
168. } catch (IOException e) {
169. throw new RuntimeException(e);
170. } finally {
171. try {
172. conn.close();
173. } catch (IOException ex) {}
174. }
175. }
176. }
177.
178. private String guessContentTypeFromName(String name) {
179. if (name.endsWith(".html") || name.endsWith(".htm")) {
180. return "text/html";
181. } else if (name.endsWith(".txt") || name.endsWith(".java")) {
182. return "text/plain";
183. } else if (name.endsWith(".gif")) {
184. return "image/gif";
185. } else if (name.endsWith(".class")) {
186. return "application/octet-stream";
187. } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) {
188. return "image/jpeg";
189. } else
190. return "text/plain";
191. }
192. }
相关推荐
本项目"JAVA基于Socket编写的FTP程序"是一个利用Java语言实现的简单FTP(File Transfer Protocol)客户端和服务端应用。FTP是一种用于在互联网上可靠地传输文件的标准协议,它允许用户从远程主机下载文件或上传文件...
在Java中,可以使用`Socket(String host, int port)`构造函数创建一个Socket实例,其中host参数是服务器的IP或域名,port参数是服务器的端口号。例如: ```java Socket socket = new Socket("www.example.com", 80...
Java Socket 开发高并发小型服务器涉及的核心概念是网络编程中的Socket技术,以及如何利用Java语言构建能够处理大量并发连接的服务端。首先,Socket是网络通信中的一个基础概念,它为两台计算机之间的通信提供了接口...
Java Socket服务器客户端程序是网络编程中的基础组件,用于实现两台计算机...理解并掌握这些知识点,对于编写Java Socket服务器客户端程序至关重要。通过实际的项目练习,你可以更好地了解如何在Java中实现网络通信。
Java基于Socket编写的聊天室程序是一种典型的客户端-服务器(C/S)架构的应用,它利用了Java的网络编程能力,特别是Socket类,来实现用户之间的实时通信。在这个程序中,Server.jar是服务器端程序,它监听特定的端口...
这个软件可以任意设置目标IP和端口实现连接相应的主机服务器,编写语言为java,安装时候需要有相应的java环境运行。
4. **编写服务器主体代码**: - 定义端口号。 - 创建`ServerSocket`对象,监听指定端口。 - 使用`accept()`方法接收客户端的连接请求。 - 获取客户端`Socket`的输入输出流。 - 实现数据读取与发送逻辑。 - ...
### JAVA SOCKET通讯程序知识点 #### 一、Java Socket编程简介 在Java中,Socket编程是一种常用的网络通信方式,它允许程序之间通过TCP/IP协议进行数据交换。Java中的`java.net.Socket`类和`java.net.ServerSocket...
总结来说,这个项目是利用Java Socket实现了一个简单的HTTP代理服务器,用户可以通过配置浏览器的代理设置来使用它。尽管它可能不包含复杂的功能,如缓存、身份验证或协议转换,但对于学习网络编程和理解HTTP代理...
本项目涉及的是使用Java编写的一个简单的浏览器和服务器,这对于学习Java网络编程的初学者来说是一个很好的实践案例。 首先,我们要理解浏览器和服务器的基本工作原理。浏览器是客户端应用程序,用于向服务器发送...
基于java+socket编写的聊天室,启动时必须运行两次程序。其中,先开服务器,再开客户端。一方输入127.0.0.1,另一连接即可进行聊天。如果不会运行或者想买项目,联系qq:937062188
5. **测试**:在测试阶段,我们可以编写一个简单的Java客户端程序,连接到服务器端的Socket,并发送一些测试数据。服务器端接收数据后,可以进行处理并回传结果。这将验证我们的Socket通信是否正常工作。 6. **安全...
Java基于Socket的进程间通信(IPC)是一种网络编程技术,常用于实现客户端和服务器之间的通信。在这个场景下,我们讨论的是一个简单的聊天小程序,它利用了Java的Socket库来搭建客户端与服务器之间的桥梁,实现数据...
### Java Socket 使用加密协议传输对象:深入解析与实践 在当今互联网时代,数据安全成为企业和个人用户关注的焦点。在Java开发中,Socket编程是一种常见的网络通信方式,它允许不同计算机上的应用程序通过网络进行...
Java 编写基于 CMPP3.0 的 Socket 服务端和客户端是移动通讯领域中常见的技术实践,主要用于实现与移动运营商的短信网关进行数据交互。CMPP(China Mobile Short Message Peer-to-Peer)是中国移动制定的一种短消息...
总结起来,使用Java编写客户端向服务器传输文件涉及到的主要知识点有:Java的Socket和ServerSocket类,网络通信的基本原理,文件的输入/输出流操作,以及可能涉及的多线程、异常处理和安全性策略。理解这些概念并能...
【标题】: "基于Socket编写的Java多用户五子棋小游戏" 在计算机编程领域,Java是一种广泛应用的编程语言,尤其在开发网络应用方面表现出色。本项目是一个利用Java Socket技术实现的多用户在线五子棋游戏。Socket是...
4. **数据编码与解码**: 在Java中,可以使用`PrintWriter`或`DataOutputStream`向Socket输出流写入字符串,而使用`BufferedReader`或`ObjectInputStream`从输入流读取数据。为了确保跨平台的兼容性,通常会使用UTF-8...
在这个场景中,我们关注的是C++编写的服务器和Java编写的客户端如何利用Socket进行通信。下面将详细介绍这个过程。 首先,让我们了解Socket的基本概念。Socket可以被看作是两台计算机之间的通信端点,它提供了低...