上一篇文章说到怎样写一个最简单的Java Socket通信,但是在上一篇文章中的例子有一个问题就是Server只能接受一个Client请求,当第一个Client连接后就占据了这个位置,后续Client不能再继续连接,所以需要做些改动。
当Server每次接受到一个Client的请求之后,都建立一个线程,然后继续等待下一个Client的连接请求。这样就不会阻塞Server端接收请求了。具体代码如下:
代码流程图如下:
服务端的代码
public class MyServer1 implements Runnable {
private Socket socket;
private String clientId;
public MyServer1(Socket socket) {
this.socket = socket;
}
public static void main(String[] args) throws IOException {
int port = 9999;
// 监听服务器端口
ServerSocket server = new ServerSocket(port);
System.out.println("listening on " + port);
while(true) {
Socket socket = server.accept();
new Thread(new MyServer1(socket)).start();
}
}
public void run() {
// 设置客户端名称,方便区分不同client
setClientId();
System.out.println("the client " + this.getClientId() + " has connected!");
// 获取客户端的输入流
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 获取客户端的输出流
out = new PrintWriter(socket.getOutputStream());
while (true) {
String msg = in.readLine();
System.out.println("----------------------------------------------------");
System.out.println("-------------client " + this.getClientId() + "--------------");
System.out.println("----------------------------------------------------");
System.out.println("\nServer received " + msg);
if (msg.equals("bye")) {
System.out.println("Server stoped!");
break;
} else {
// 向客户端发送信息
System.out.println("Server send " + msg + "\n");
out.print("Server responsed " + msg);
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public String getClientId() {
return clientId;
}
public void setClientId() {
Time now = new Time(new Date().getTime());
this.clientId = socket.getInetAddress().getHostAddress() + "-" + now.toString();
}
}
客户端代码
public class MyClient {
public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
Scanner reader = new Scanner(System.in);
// 创建客户端socket
Socket client = new Socket("localhost", 9999);
// 获取客户端的输出流(获取服务器端的输入流)
PrintWriter out = new PrintWriter(client.getOutputStream());
// 获取客户端的输入流(获取服务器端的输出流)
InputStream in = client.getInputStream();
while (true) {
System.out.println("---------------------------");
System.out.println("Input Something: ");
String msg = reader.nextLine();
System.out.println("Client sended " + msg);
out.println(msg);
out.flush();
Thread.sleep(1000);
byte[] buff = new byte[in.available()];
in.read(buff);
System.out.println(new String(buff, "UTF-8"));
if (msg.equals("bye")) {
System.out.println("Client stop!");
break;
}
}
out.close();
client.close();
}
}
先运行MyServer1类,再运行两个MyClient类(相当与两个线程)。结果如下所示:
clent1(127.0.0.1-16:22:53)
---------------------------
Input Something:
11
Client sended 11
Server responsed 11
---------------------------
Input Something:
123
Client sended 123
Server responsed 123
---------------------------
Input Something:
bye
Client sended bye
Client stop!
client2(1127.0.0.1-16:22:59)
---------------------------
Input Something:
333
Client sended 333
Server responsed 333
---------------------------
Input Something:
bye
Client sended bye
Client stop!
服务端
listening on 9999
the client 127.0.0.1-16:22:53 has connected!
the client 127.0.0.1-16:22:59 has connected!
----------------------------------------------------
-------------client 127.0.0.1-16:22:59--------------
----------------------------------------------------
Server received 333
Server send 333
----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------
Server received 11
Server send 11
----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------
Server received 123
Server send 123
----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------
Server received bye
Server stoped!
----------------------------------------------------
-------------client 127.0.0.1-16:22:59--------------
----------------------------------------------------
Server received bye
Server stoped!
这种实现方式有以下不足之处
1、服务器创建和销毁工作线程的开销很大;
2、活动的线程也消耗系统资源。每个线程本身都会占用一定的内存(每个线程需要大约1MB内存),这样就很容易导致系统的内存不足;
3、Java虚拟机会为每个线程分配独立的堆栈空间,工作线程数目越多,系统开销越大,而且增加了Java虚拟机调度线程的负担,增加了线程之间同步的复杂性,提高了线程死锁的可能性。
4、工作线程的许多时间都浪费在阻塞I/O操作上,Java虚拟机需要频繁地转让CPU的使用权,使进入阻塞状态的线程放弃CPU,再把CPU分配给处于可运行状态的线程。