1.服务器端
1.创建ServerSocket对象,可在构造子中指定监听的端口;
privateintport = 8000;
private ServerSocket serverSocket;
……
serverSocket = new ServerSocket(port);
2.服务器端调用ServerSocket对象的accept()方法,该方法一直监听端口,等待客户的连接请求,如果接收到一个连接请求,accept()方法就会返回一个Socket对象,这个Socket对象与客户端的Socket对象将形成一条通信线路;
Socket socket = null;
socket = serverSocket.accept(); // 等待客户连接
3.Socket类提供了getInputStream()方法和getOutputStream()方法。
InputStream socketIn = socket.getInputStream();
OutputStream socketOut = socket.getOutputStream();
源代码EchoServer.java
publicclass EchoServer {
privateintport = 8000;
private ServerSocket serverSocket;
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
System.out.println("Server Start");
}
public String echo(String msg) {
return"echo:" + msg;
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
returnnew PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
returnnew BufferedReader(new InputStreamReader(socketIn));
}
publicvoid service() {
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept(); // 等待客户连接
System.out.println("New connection accepted "
+ socket.getInetAddress() + ":" + socket.getPort());
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println(msg);
pw.println(echo(msg));
if (msg.equals("bye")) // 如果客户发送的消息为“bye”,就结束通信
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close(); // 断开连接
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
publicstaticvoid main(String args[]) throws IOException {
new EchoServer().service();
}
}
2.客户端
1.创建一个Socket对象,指定服务器端的地址和端口;
private String host = "localhost";
privateintport = 8000;
private Socket socket;
……
socket = new Socket(host, port);
这里作为客户端,它的端口是由操作系统随机产生的。
2.Socket类提供了getInputStream()方法和getOutputStream()方法。
InputStream socketIn = socket.getInputStream();
OutputStream socketOut = socket.getOutputStream();
源代码EchoClient.java
publicclass EchoClient {
private String host = "localhost";
privateintport = 8000;
private Socket socket;
public EchoClient() throws IOException {
socket = new Socket(host, port);
}
publicstaticvoid main(String args[]) throws IOException {
new EchoClient().talk();
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
returnnew PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
returnnew BufferedReader(new InputStreamReader(socketIn));
}
publicvoid talk() throws IOException {
try {
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
BufferedReader localReader = new BufferedReader(
new InputStreamReader(System.in));
String msg = null;
while ((msg = localReader.readLine()) != null) {
pw.println(msg);
System.out.println(br.readLine());
if (msg.equals("bye"))
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.关闭Socket
1.关闭Socket的代码;
try {
……
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Socket类提供3个状态测试方法。
-isClosed():如果Socket已经连接到远程主机,并且还没有关闭,则返回true;
-isConnected():如果Socket曾经连接到远程主机,则返回true;
-isBound():如果Socket已经与一个本地端口绑定,则返回true。
判断一个Socket对象当前是否处于连接状态,
Boolean isConnected = socket.isConnected() && !socket.isClosed();
2.处理关闭
(1)当进程A与进程B交换的是字符流,并且是一行一行地读写数据时,可以事先约定一个特殊的标志。
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println(msg);
pw.println(echo(msg));
if (msg.equals("bye")) // 如果客户发送的消息为“bye”,就结束通信
break;
}
(2)进程A先发送一个消息,告诉进程B所发送的正文长度,然后发送正文。进程B只要读取完该长度的数据就可以停止读数据。
(3)进程A发送完所有数据后,关闭Socket。当进程B读入进程A发送的所有数据后,再次执行输入流的read()方法时,该方法返回-1.
InputStream socketIn = socket.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] buff = newbyte[1024];
int len = -1;
while ((len = socketIn.read(buff)) != -1) {
buffer.write(buff, 0, len);
}
System.out.println(new String(buffer.toByteArray()));
(4)当调用Socket的close()方法关闭Socket时,它的输入流和输出流都被关闭。如果仅仅希望关闭输入或输出流其中之一,可调用半关闭方法:shutdownInput()和shutdownOutput()。先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭输入流和输出流,并不等价于调用close()方法。在通信结束后仍然需要调用close()方法,因为该方法才会释放Socket占用的资源。
4.多线程服务器
EchoServer只能顺序的处理Client端的请求,这里使用ExecutorService指定一个线程池用于处理连接请求。
private ExecutorService executorService; // 线程池
privatefinalintPOOL_SIZE = 4; // 单个CPU时线程池中工作线程的数目
…….
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors()* POOL_SIZE);
……
try {
socket = serverSocket.accept();
executorService.execute(new Handler(socket));
} catch (IOException e) {
e.printStackTrace();
}
Hander类封装了原来处理连接请求的逻辑,只要当前线程池中有空闲的线程,就可以用于处理请求。
源代码MultiEchoServer.java
publicclass MultiEchoServer {
privateintport = 8000;
private ServerSocket serverSocket;
private ExecutorService executorService; // 线程池
privatefinalintPOOL_SIZE = 4; // 单个CPU时线程池中工作线程的数目
public MultiEchoServer() throws IOException {
serverSocket = new ServerSocket(port);
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors()
* POOL_SIZE);
System.out.println("Server Start");
}
publicvoid service() {
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();
executorService.execute(new Handler(socket));
} catch (IOException e) {
e.printStackTrace();
}
}
}
publicstaticvoid main(String args[]) throws IOException {
new MultiEchoServer().service();
}
}
class Handler implements Runnable {
private Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
returnnew PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
returnnew BufferedReader(new InputStreamReader(socketIn));
}
public String echo(String msg) {
return"echo:" + msg;
}
publicvoid run() {
try {
System.out.println("New connection accepted "
+ socket.getInetAddress() + ":" + socket.getPort());
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println(msg);
pw.println(echo(msg));
if (msg.equals("bye"))
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}