Abstract 概述
Echo程序,即在Client输入内容,Server接收到后在开头加上“Echo: ”后再返回给Client的程序。这是一个TCP连接的程序。
涉及:
- I/O
- Socket
- Multi-Thread
注意(坑):
- 网络IO中只能传输字节流,不能直接传输字符流。
- 无论是Client还是Server,都应该将获取的字节流内容转换为字符流,以防中文乱码。
Description 具体步骤
步骤一:实现基本功能
- Server可以反复接收由Client发送的消息并回应;
- Client可以反复向Server发送信息;
Server:
public class EchoServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ServerSocket server = null;
Socket client = null;
PrintStream out = null;
BufferedReader in = null;
System.out.println("Running service...");
//service start
server = new ServerSocket(8888);
System.out.println("Waiting for connection..");
while(true){
client = server.accept();
SocketAddress addr = client.getRemoteSocketAddress();
System.out.println("Establishing connection: " + addr);
//keep talking with the user
while(true){
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String content = in.readLine();
//if user wanna quit the program, just let him go.
if(content == null || ".quit".equals(content.toLowerCase())) break;
System.out.println("Receive: " + content);
out = new PrintStream(client.getOutputStream());
out.println("ECHO: " + content);
System.out.println("Replied.");
}
in.close();
out.close();
client.close();
System.out.println("Session ended: " + addr);
}
}
}
Client:
public class EchoClient {
public static void main(String[] args) throws IOException {
BufferedReader kbInput = null;
Socket socket = null;
PrintStream out = null;
BufferedReader in = null;
socket = new Socket("localhost", 8888);
kbInput = new BufferedReader(new InputStreamReader(System.in));
while(true){
//get keyboard input
String content = kbInput.readLine();
if(content == null || content.trim().length() == 0 || ".quit".equals(content)) break;
//send message to server
out = new PrintStream(socket.getOutputStream());
out.println(content);
//retrieve message from server
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String reply = in.readLine();
System.out.println(reply);
}
socket.close();
}
}
虽然实现了基本功能,但却只能处理单个Client连接。 如图:左上角为Server,只能显示单个Client的消息(右上角),不能处理其他Client的连接(左下角),并且会在当前Client(右上角)退出后抛出SocketException
,Server终止运行,因此需要进行步骤二的改进:使用多线程来实现。
当前Client退出后:
步骤二:Server改用多线程
新建线程类处理Client的输入:
public class EchoServerThread implements Runnable{
private Socket socket;
public EchoServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run(){
BufferedReader reader = null;
PrintStream out = null;
try{
SocketAddress addr = socket.getRemoteSocketAddress();
System.out.println("Connected: " + addr);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintStream(socket.getOutputStream());
while(true){
String content = reader.readLine();
//if user wanna leave, just let him go
if(content == null || content.trim().length() == 0 || ".quit".equals(content)) break;
out.println("Echo: " + content);
System.out.println("Received: " + content);
}
socket.close();
System.out.println("Connection ended: " + addr);
}catch(IOException e){
e.printStackTrace();
}
}
}
Server里将循环中的代码用EchoServerThread
替换掉:
public class EchoServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ServerSocket server = null;
Socket client = null;
PrintStream out = null;
BufferedReader in = null;
System.out.println("Running service...");
//service start
server = new ServerSocket(8888);
System.out.println("Waiting for connection..");
while(true){
client = server.accept();
new Thread(new EchoServerThread(client)).start();
}
}
}
Client不变:
public class EchoClient {
public static void main(String[] args) throws IOException {
BufferedReader kbInput = null;
Socket socket = null;
PrintStream out = null;
BufferedReader in = null;
socket = new Socket("localhost", 8888);
kbInput = new BufferedReader(new InputStreamReader(System.in));
while(true){
//get keyboard input
String content = kbInput.readLine();
if(content == null || content.trim().length() == 0 || ".quit".equals(content)) break;
//send message to server
out = new PrintStream(socket.getOutputStream());
out.println(content);
//retrieve message from server
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String reply = in.readLine();
System.out.println(reply);
}
socket.close();
}
}
多个Client同时连接或退出,从Server打印的信息可看到运作正常。
Others 其他
水平所限,或有疏漏,如有任何错误或建议,还望不吝赐教。