服务器就是网路上开放一个端口用来等待客户端连接,并在连接之后能够按照一定的协议与客户端进行单工或者双工的通信的电脑。所以要构建一个简单的服务器就需要开放一定的端口,并且要让客户端知道服务器的IP以及开放的端口的类型号。
在构建服务器时,用到了一个新的类来创建服务器的对象,java.net.ServerSocket,创建的语句大致如下
java.net.ServerSocket server = new java.net.ServerSocket(port);
其中port是一个int类型的值,表示这个服务器对象所开放的端口号。电脑中可用的端口号从0~65535,一个端口同时只能被一个程序所占用,其中前1024个端口称为知名端口,通常都被一些电脑中常用软件所占用。所以在写测试程序时,要尽量避免使用这些知名端口。
由于存在输入的port被占用或者port的值不在可用范围之内的等等不可预知的情况存在,所以这条语句需要强制检测异常,即需要try catch语句或者throws关键字。
在创建对象之后,需要用accept()方法来在有客户端进行连接时获得一个Socket对象作为客户端对象。由于这条语句是在客户端连接服务器时有效,所以在这条语句时会有一个阻塞的效果。由于需要与客户端进行通信,就需要从Socket对象上获得其输入输出流对象(同样需要try catch),getInputStream()和getOutputStream()方法可以实现相关目的。
多线程服务器
以上的简单服务器是单线程的服务器,即同时只能处理一个客户端的信息,其他客户端的连接必须在之前的客户端断开连接之后才能进行,这在实际应用中是绝对不行的。所以采用线程的方法,可以实现服务器能够实现多线程。
try {
ServerSocket server = new ServerSocket(9090);
while (true) {
Socket client = server.accept();
ClientThread clientThread = new ClientThread(client);
clientThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
public class ClientThread extends Thread {
private Socket client;
public ClientThread(Socket client) {
this.client = client;
}
public void run() {
clientRun();
}
private void clientRun() {
try {
while (true) {
java.io.OutputStream outputStream = client.getOutputStream();
String msg = "hello welcome to server!";
outputStream.write(msg.getBytes());
java.io.InputStream inputStream = client.getInputStream();
String print = "";
while (print != "bye") {
print = readLine(inputStream);
System.out.println(print);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String readLine(java.io.InputStream inputStream) {
String print = null;
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
try {
print = bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return print;
}
}
以上就是多线程的简单服务器的实现。其中用到了一种新的输入流对象,bufferedReader,用来读取字符串。
字符串的读取
bufferedReader也是一种过滤流,这次主要用到的是bufferedReader中的readline()方法,readline是从输入流中连续读取字节,直到遇到回车符停止,并将之前读取到的字节转换为字符串,其编码依据平台默认的编码方式。
这实际上就是Java自身对之前使用的单个字节读取字符串的方法的一个封装实现。