网络编程简介(1)之JAVA网络编程
2015-11-08 16:32
465 查看
作为整个网络编程系列的第一篇,在这篇文章里,使用JAVA语言编写了一个小例子,实现了一个可以提供时间查询服务的Server端,和一个客户端。
服务端代码结构如下:
![](https://img-blog.csdn.net/20151108162355126)
TimeServer是启动类,启动后监听请求,每当收到一个socket请求时,TimeServer类就新建一个Handler线程来处理该请求,具体的就是由TimeServerHandler来处理这个请求。
TimeServer类代码如下:
TimeServerHandler类代码如下:
客户端代码结构如下:
![](https://img-blog.csdn.net/20151108162724072)
客户端代码分为两个类,启动类为TimeClient,这个类会不断的新建线程,并让新建的线程去请求TimeServer,同时记录开始时间与结束时间。
TimeClient代码如下:
TimeClientThread代码如下
我们可以看到,在TimeClient端我们可以开启大量的线程去同时访问服务端,然后记录时间,就可以得到对服务端性能的一个简单评估。
然后我们将代码部署在两个主机上,两台主机都是百兆网卡,位于同一局域网,RTT<1ms;
其中服务端运行参数如下:-Xmx2G -Xms1000M
客户端运行参数如下:-Xmx1000m -Xms200M
然后先启动服务端,再启动客户端,结果如下:
然后我们对代码进行修改,使得每个线程在创建后,就立马开始发出请求,不再等待其他请求一起开始。即将TimeClientThread中的如下代码注释掉。
实验结果如下:
由上图可以看到由于不必所有线程同时开始,所以我们在实验室中可以启动的最大线程数就变多了,可以看到我们可以启动大约10000个线程,但是,在时间上和同时开始,并没有过大的区别。
所以我们可以估计整个程序的性能瓶颈并不是在客户端的请求方式,而是在服务端接受并处理请求的方式上。
服务端代码结构如下:
TimeServer是启动类,启动后监听请求,每当收到一个socket请求时,TimeServer类就新建一个Handler线程来处理该请求,具体的就是由TimeServerHandler来处理这个请求。
TimeServer类代码如下:
package bio.sample; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class TimeServer { public static void main(String[] args) { int port = 8070; if(args != null && args.length > 0) { port = Integer.valueOf(args[0]); } ServerSocket server = null; try{ server = new ServerSocket(port); System.out.println("The time Server is start in port :"+ port); Socket socket = null; while(true) { socket = server.accept(); new Thread(new TimeServerHandler(socket)).start(); } } catch(Exception e) { e.printStackTrace(); } try { server.close(); } catch (IOException e) { e.printStackTrace(); } } }
TimeServerHandler类代码如下:
package bio.sample; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Date; public class TimeServerHandler implements Runnable { private Socket socket; public TimeServerHandler(Socket socket) { this.socket = socket; } @Override public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); //PrintWriter构造方法的第二个参数,如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区 out = new PrintWriter(this.socket.getOutputStream(),true); String currentTime = null; String body = null; while(true) { body = in.readLine(); if(body != null && body.length() != 0) break; } System.out.println("the time server receive order:"+body); currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString():"BAD ORDER"; out.println(currentTime); } catch (IOException e) { e.printStackTrace(); } try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
客户端代码结构如下:
客户端代码分为两个类,启动类为TimeClient,这个类会不断的新建线程,并让新建的线程去请求TimeServer,同时记录开始时间与结束时间。
TimeClient代码如下:
package bio.sample; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.concurrent.CountDownLatch; public class TimeClient { private static int PORT = 8070; private static String inataddress = "192.168.192.151"; public static void main(String[] args) { for(int i = 100;i <= 2000;i+=100) { test(i); System.gc(); } } private static void test(int THREAD_SIZE) { CountDownLatch startSignal = new CountDownLatch(THREAD_SIZE); CountDownLatch doneSignal = new CountDownLatch(THREAD_SIZE); Thread[] trs = new Thread[THREAD_SIZE]; for(int i = 0;i < THREAD_SIZE;i++) { trs[i] = new Thread(new TimeClientThread(inataddress,PORT,startSignal,doneSignal)); } long start_ms = System.currentTimeMillis(); for(int i = 0;i < THREAD_SIZE;i++) trs[i].start(); try { doneSignal.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } long end_ms = System.currentTimeMillis(); System.out.println("|"+THREAD_SIZE+"|"+ (end_ms - start_ms)+"|"); } }
TimeClientThread代码如下
package bio.sample; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.concurrent.CountDownLatch; public class TimeClientThread implements Runnable { private int port; private String serverAddress; private CountDownLatch startSignal; private CountDownLatch doneSignal; public TimeClientThread(String inatAddres,int serverPort, CountDownLatch sSignal, CountDownLatch dSignal) { port = serverPort; serverAddress = inatAddres; startSignal = sSignal; doneSignal = dSignal; } @Override public void run() { Socket socket = null; BufferedReader in = null; PrintWriter out = null; try{ startSignal.countDown(); startSignal.await(); socket = new Socket(serverAddress,port); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(),true); out.println("QUERY TIME ORDER"); //System.out.println("Send order to server"); String resp = in.readLine(); //System.out.print("Now is" + resp); doneSignal.countDown(); } catch(Exception e) { e.printStackTrace(); } try { in.close(); out.close(); socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
我们可以看到,在TimeClient端我们可以开启大量的线程去同时访问服务端,然后记录时间,就可以得到对服务端性能的一个简单评估。
然后我们将代码部署在两个主机上,两台主机都是百兆网卡,位于同一局域网,RTT<1ms;
其中服务端运行参数如下:-Xmx2G -Xms1000M
客户端运行参数如下:-Xmx1000m -Xms200M
然后先启动服务端,再启动客户端,结果如下:
线程数 | 耗费时间(ms) |
---|---|
100 | 52 |
200 | 54 |
300 | 80 |
400 | 87 |
500 | 107 |
600 | 146 |
700 | 130 |
800 | 142 |
900 | 168 |
1000 | 184 |
1200 | 230 |
1400 | 259 |
1600 | 302 |
1800 | 332 |
2000 | 380 |
// startSignal.countDown(); // startSignal.await();
实验结果如下:
线程数 | 耗费时间(ms) |
---|---|
100 | 42 |
200 | 53 |
300 | 65 |
400 | 75 |
500 | 91 |
600 | 120 |
700 | 109 |
800 | 123 |
900 | 135 |
1000 | 149 |
1200 | 183 |
1400 | 209 |
1600 | 239 |
1800 | 264 |
2000 | 299 |
2500 | 370 |
3000 | 444 |
3500 | 521 |
4000 | 596 |
4500 | 858 |
5000 | 743 |
6000 | 887 |
7000 | 1036 |
8000 | 1181 |
9000 | 1328 |
10000 | 1472 |
所以我们可以估计整个程序的性能瓶颈并不是在客户端的请求方式,而是在服务端接受并处理请求的方式上。
相关文章推荐
- 僵尸网络的相关研究文章
- POJ 3281 Dining(网络流最大匹配)
- 基于HTTPS协议的12306抢票软件设计与实现--相关接口以及数据格式
- ioS无限后台任务(后台长期网络请求任务)
- java基于UDP协议的网络编程
- JAVA高性能网络编程——牛刀小试
- 当刘小立访问Google时,刘小立如何能访问? ---《计算机网络-自顶向下方法》
- Linux之Vsftpd虚拟用户、扩展应用tcp_wrapper实验总结
- Xcode7 使用NSURLSession发送HTTP请求的问题
- plupload 参考网址 http://chaping.github.io/plupload/demo/index.html
- 网络协议
- ServletContext、HttpServletRequest 、HttpServletResponse和HttpSession
- Http协议之获取自定义文件Head信息(2)
- java网络编程(二)
- java网络编程(一)
- 用CornerStone配置SVN,HTTP及svn简单使用说明
- 黑马程序员——java基础---网络编程
- 如何保证http传输安全性
- Http协议之获取自定义文件Head信息(1)
- C# TCP/IP 连接实现数据收发 Demo (Visual Studio)