- 浏览: 334007 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
右手边的你:
你确定你测试过batch是没问题的???
使用DbUtils进行数据库操作 -
电点mxn:
...
使用DbUtils进行数据库操作 -
sljackson:
顶
Spring事务管理 -
geyaandy:
...
Oracle行列互换 横表和纵表 -
weizou_china:
Request URL:http://localhost:80 ...
Spring mvc3的ajax
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算法,用于解决小封包问题,感兴趣的朋友可以自己搜索
热身运动
核心开始
先简单说概念:
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算法,用于解决小封包问题,感兴趣的朋友可以自己搜索
热身运动
/** * 单个文件的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版 HTTP服务器 */ public class JHTTPServer extends Thread { private File docRootDir; private String indexFileName; private ServerSocket server; private int numThread = 50; public JHTTPServer(File docRootDir) throws IOException { this(docRootDir, 80, "index.html"); } public JHTTPServer(File docRootDir, int port, String indexFileName) throws IOException { this.docRootDir = docRootDir; this.indexFileName = indexFileName; server = new ServerSocket(port); } public void run() { for (int i = 0; i < numThread; i++) { Thread t = new Thread(new RequestProcessor(docRootDir, indexFileName)); t.start(); } System.out.println("Accepting connections on port " + server.getLocalPort()); System.out.println("Document Root: " + docRootDir); while(true){ try { Socket conn = server.accept(); RequestProcessor.processRequest(conn); } catch (IOException e) { throw new RuntimeException(e); } } } public static void main(String[] args) { File docRoot = new File("D:/src/HTML_CSS"); try { new JHTTPServer(docRoot).start(); } catch (IOException e) { System.out.println("Server could not start because of an " + e.getClass()); System.out.println(e); } } } /** * 服务线程池 */ public class RequestProcessor implements Runnable { private static List<Socket> pool = new LinkedList<Socket>(); private File docRootDir; private String indexFileName; public RequestProcessor(File docRootDir, String indexFileName) { if (docRootDir.isFile()) throw new IllegalArgumentException( "documentRootDirectory must be a directory, not a file"); this.docRootDir = docRootDir; try { this.docRootDir = docRootDir.getCanonicalFile(); } catch (IOException ex) { } this.indexFileName = indexFileName; } public static void processRequest(Socket conn) { synchronized (pool) { pool.add(pool.size(), conn); pool.notifyAll(); } } public void run() { String root = docRootDir.getPath(); while (true) { Socket conn; synchronized (pool) { while (pool.isEmpty()) { try { pool.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } conn = pool.remove(0); } try { OutputStream raw = new BufferedOutputStream(conn.getOutputStream()); Writer out = new OutputStreamWriter(raw); Reader in = new InputStreamReader(new BufferedInputStream(conn.getInputStream())); StringBuilder request = new StringBuilder(); int c; while (true) { c = in.read(); if (c == '\r' || c == '\n') break; request.append((char) c); } String get = request.toString(); // 记录请求日志 System.out.println(get); StringTokenizer st = new StringTokenizer(get); String method = st.nextToken(); String version = "", fileName, contentType; if (method.equals("GET")) { fileName = st.nextToken(); if (fileName.endsWith("/")) fileName += indexFileName; contentType = guessContentTypeFromName(fileName); if (st.hasMoreTokens()) version = st.nextToken(); File theFile = new File(docRootDir, fileName.substring(1, fileName.length())); // 不让请求超出文档根目录 if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) { DataInputStream dis = new DataInputStream( new BufferedInputStream(new FileInputStream(theFile))); byte[] theData = new byte[(int) theFile.length()]; dis.readFully(theData); dis.close(); if (version.startsWith("HTTP ")) { out.write("HTTP/1.0 200 OK\r\n"); out.write("Date" + new Date() + "\r\n"); out.write("Server: JHTTP/1.0\r\n"); out.write("Content-length: " + theData.length + "\r\n"); out.write("Content-type: " + contentType + "\r\n\r\n"); out.flush(); } // 发送文件,可能是图片或其它二进制数据,所以使用底层的输出流不是书写器 raw.write(theData); raw.flush(); } else { // 没有找到文件 if (version.startsWith("HTTP ")) { // send a MIME header out.write("HTTP/1.0 404 File Not Found\r\n"); Date now = new Date(); out.write("Date: " + now + "\r\n"); out.write("Server: JHTTP/1.0\r\n"); out.write("Content-type: text/html\r\n\r\n"); } out.write("<HTML>\r\n"); out.write("<HEAD><TITLE>File Not Found</TITLE>\r\n"); out.write("</HEAD>\r\n"); out.write("<BODY>"); out.write("<H1>HTTP Error 404: File Not Found</H1>\r\n"); out.write("</BODY></HTML>\r\n"); out.flush(); } } else { // method does not equal "GET" if (version.startsWith("HTTP ")) { // send a MIME header out.write("HTTP/1.0 501 Not Implemented\r\n"); Date now = new Date(); out.write("Date: " + now + "\r\n"); out.write("Server: JHTTP 1.0\r\n"); out.write("Content-type: text/html\r\n\r\n"); } out.write("<HTML>\r\n"); out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n"); out.write("</HEAD>\r\n"); out.write("<BODY>"); out.write("<H1>HTTP Error 501: Not Implemented</H1>\r\n"); out.write("</BODY></HTML>\r\n"); out.flush(); } } catch (IOException e) { throw new RuntimeException(e); } finally { try { conn.close(); } catch (IOException ex) {} } } } private String guessContentTypeFromName(String name) { if (name.endsWith(".html") || name.endsWith(".htm")) { return "text/html"; } else if (name.endsWith(".txt") || name.endsWith(".java")) { return "text/plain"; } else if (name.endsWith(".gif")) { return "image/gif"; } else if (name.endsWith(".class")) { return "application/octet-stream"; } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) { return "image/jpeg"; } else return "text/plain"; } }
- java_http_server.zip (4.9 KB)
- 下载次数: 85
发表评论
-
Java网络编程URL和URI
2010-08-25 17:13 2770获得URL的方法 URI.toURL() File.toUR ... -
Java网络编程 非阻塞I/O
2010-07-16 17:53 2453对于CPU速度高于网络的 ... -
Java 新I/O
2010-07-06 21:23 1642Java新IO所使用的结构 更接近于操作系统执行I/O的方式: ... -
Java I/O系统
2010-07-01 23:21 1184编程语言的I/O类库,常使用流这个抽象概念,它代表任何有能力产 ... -
Java UDP数据报和Socket
2010-06-29 18:36 2042两个核心类DatagramPacket 数据包、Datagra ... -
Java线程学习
2010-06-29 16:12 1281从线程中取得信息 轮询 主程序无限循环,从子线程取得返回值, ... -
中文FTP环境下,使用commons-net,FTPClient.listFiles()方法返回null的问题及解决办法
2010-06-28 16:42 13229项目中需要从FTP上下载数据,采用了开源的commons-ne ... -
Comparable和Comparator接口
2010-05-20 15:23 1447Java中有2个用于比较的接口,Comparable和Comp ... -
中序后缀表达式
2010-01-25 17:11 1555import java.io.BufferedReader; ... -
java异常链处理
2009-07-29 12:54 3433jdk1.4后的,所有异常根类Throwable部分代码 ... -
java正则表达式
2009-07-07 23:06 1512Scanner与正则表达式运用 import java.uti ...
相关推荐
这个软件可以任意设置目标IP和端口实现连接相应的主机服务器,编写语言为java,安装时候需要有相应的java环境运行。
基于java+socket编写的聊天室,启动时必须运行两次程序。其中,先开服务器,再开客户端。一方输入127.0.0.1,另一连接即可进行聊天。如果不会运行或者想买项目,联系qq:937062188
JAVA SOCKET通讯程序
JAVA编写的TCP协议的socket客户端服务器程序代码
Java语言编写,基于socket的简单聊天软件,C/S模式,非常实用。内容包括服务器端与客户端。
使用java编写的简单的socket网络通信软件,客户端和服务端进行连接和通信,为了测试方便,当使用客户端发送消息时隐藏了服务端窗口,服务端也一样,bye消息结束通话。
通过一个socket来实现聊天室的各种功能版本,用一个线程来实现这些功能,客户端发送每一条消息的时候,前三个字都是用来标识这个信息的功能的,服务器接受到以后来判断,分别对每一个功能进行不同操作,服务器再发给...
JAVA编写的UDP协议的socket客户端服务器程序代码
使用JAVA编写一个使用TCP协议传输文件的Socket,实现客户端向服务器端发送一个文件,服务器端接收之后按相同的文件名在指定的目录下保存文件
用java编写的基于socket的进程间通信程序 客户端服务器聊天小程序
基于java socket实现的多人聊天程序,分为客户端和服务器端,希望可以对你有帮助
基于 socket 实现简单的聊天程序 通过 socket 程序的编写、调试,掌握 socket 编程的基本方法,了解客户端与服务器端的特点,掌握并熟悉运用 socket 类与 serversocket 类。
使用java socket开发的上网代理,编译后,运行Start.class,然后修改浏览器的代理服务器,端口为10101
用java编写的FTP服务器、客户端。服务器底层采用apache FTPserver的JAR包。客户端底层采用sun.net包。两者都可以独立使用。在myeclipse10.6里面编写,java版本是1.6。
java netty编写的socket tcp服务器+flash actionscript3编写的游戏客户端 C/S程序游戏源代码
基于socket编写的java五子棋项目,采用tcp iP协议。操作方法:先启动服务器,再开两个客户端,随便填写用户名加入游戏即可!
JICQ是用JAVA语言编写的一个基于客户机/服务器(C/S)模式的局域短信实时通信工具系统,系统采用了Microsoft公司的SQL Server 2000作为后台数据库,系统通过JDBC访问数据库。系统分为服务器程序和客户程序两部分,...
java socket聊天室,Javaswing编写图形化界面,可以连接mysql数据库登录和注册,实现私聊和多人聊天
基于netty框架编写的socket服务器