您的位置:首页 > 理论基础 > 计算机网络

网络编程简介(1)之JAVA网络编程

2015-11-08 16:32 465 查看
作为整个网络编程系列的第一篇,在这篇文章里,使用JAVA语言编写了一个小例子,实现了一个可以提供时间查询服务的Server端,和一个客户端。

服务端代码结构如下:



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)
10052
20054
30080
40087
500107
600146
700130
800142
900168
1000184
1200230
1400259
1600302
1800332
2000380
然后我们对代码进行修改,使得每个线程在创建后,就立马开始发出请求,不再等待其他请求一起开始。即将TimeClientThread中的如下代码注释掉。

//          startSignal.countDown();
//          startSignal.await();


实验结果如下:

线程数耗费时间(ms)
10042
20053
30065
40075
50091
600120
700109
800123
900135
1000149
1200183
1400209
1600239
1800264
2000299
2500370
3000444
3500521
4000596
4500858
5000743
6000887
70001036
80001181
90001328
100001472
由上图可以看到由于不必所有线程同时开始,所以我们在实验室中可以启动的最大线程数就变多了,可以看到我们可以启动大约10000个线程,但是,在时间上和同时开始,并没有过大的区别。

所以我们可以估计整个程序的性能瓶颈并不是在客户端的请求方式,而是在服务端接受并处理请求的方式上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: